fis-gtm-V6.0-003/0000755000032200000250000000000012201176223012336 5ustar librarygtcfis-gtm-V6.0-003/CMakeLists.txt0000644000032200000250000006221312201176223015102 0ustar librarygtc################################################################# # # # Copyright 2012, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # CMake 2.8.4 introduced LINK_DEPENDS target property # CMake 2.8.4 introduced generator expressions in custom commands # CMake 2.8.5 introduced use of C compiler as the assembler cmake_minimum_required(VERSION 2.8.5) project(GTM C ASM) # Max optimization level is -O2 get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) foreach(lang ${languages}) get_property(flags CACHE CMAKE_${lang}_FLAGS_RELEASE PROPERTY VALUE) if("${flags}" MATCHES "-O[3-9]") string(REGEX REPLACE "-O[3-9]" "-O2" flags "${flags}") set_property(CACHE CMAKE_${lang}_FLAGS_RELEASE PROPERTY VALUE "${flags}") endif() endforeach() # Defaults set(version V6.0-003) if("${version}" STREQUAL "") set(version V9.9-0) endif() # If CMAKE_BUILD_TYPE is not defined make it a Release build if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) endif() # If it's a debug build make sure GT.M uses all of its debug options set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG") set(install_permissions_script OWNER_READ OWNER_EXECUTE OWNER_WRITE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG DEBUG) # Only IA64 and x86_64 architectures use this option set(gen_xfer_desc 0) # Platform specific libs set(gtm_osarch_libs "") # Define these ahead of establishing platforms set(gt_src_list) set(sources_used "") set(extralibs "") set(is_encryption_supported 1) set(libmumpsrestoreregex "") message("--> OS = ${CMAKE_SYSTEM_NAME} / ARCH = ${CMAKE_SYSTEM_PROCESSOR}") # Establish platform # Except for Solaris, CMAKE_COMPILER_IS_GNUCC is true if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") include(sr_linux/platform.cmake) elseif("${CMAKE_SYSTEM_NAME}" MATCHES "HP-UX") include(sr_hpux/platform.cmake) elseif("${CMAKE_SYSTEM_NAME}" MATCHES "AIX") include(sr_aix/platform.cmake) elseif("${CMAKE_SYSTEM_NAME}" MATCHES "SunOS") include(sr_sun/platform.cmake) else() message(FATAL_ERROR "--> OS = ${CMAKE_SYSTEM_NAME} / ARCH = ${CMAKE_SYSTEM_PROCESSOR}") endif() # Choose where to get bootstrap sources. set(GTM_DIST "" CACHE PATH "Existing GT.M Distribution") if(GTM_DIST) # Bootstrap using already-installed mumps. message(STATUS "Using existing gtm_dist=${GTM_DIST} to generate sources.") set(gen_bootstrap 1) set(gen_bootstrap_dist "${GTM_DIST}") set(gen_bootstrap_mumps "${GTM_DIST}/mumps") set(gen_bootstrap_depend "${gen_bootstrap_mumps}") else() # Bootstrap using pre-generated bootstrap sources. # We generate them again only for comparison. set(gen_bootstrap 0) set(gen_bootstrap_dist "${GTM_BINARY_DIR}") set(gen_bootstrap_mumps "$") set(gen_bootstrap_depend mumps) endif() set(GTM_INSTALL_DIR lib/fis-gtm/${version}_${arch} CACHE STRING "Install directory (under CMAKE_PREFIX_PATH if relative)") if(NOT GTM_INSTALL_DIR) set(GTM_INSTALL_DIR .) endif() #----------------------------------------------------------------------------- # Source files are organized into subdirectories named by platform. # Store in 'gt_src_list' a list of directory names selected and # ordered based on the target platform. A given source file name may # appear in multiple directories but only the instance found earliest # in the search path will be used. Later instances of the same source # file name will be ignored. list(APPEND gt_src_list sr_unix_gnp sr_unix_cm sr_unix sr_port_cm sr_port ) # Collect the source file names belonging to each directory. Store # the full path to a directory in 'source_dir_${d}' and the list of # source file names in the directory in 'sources_${d}'. foreach(d ${gt_src_list}) set(source_dir_${d} ${GTM_SOURCE_DIR}/${d}) file(GLOB sources_${d} RELATIVE ${source_dir_${d}} ${d}/*.c ${d}/*.s ${d}/*.si) endforeach() if(gen_bootstrap) # Prefer generated sources over all other locations. set(gt_src_list gen ${gt_src_list}) set(source_dir_gen ${GTM_BINARY_DIR}/gen) # Hard-code list since we cannot glob files that do not exist. set(sources_gen cmerrors_ctl.c cmierrors_ctl.c gdeerrors_ctl.c merrors_ctl.c ttt.c) endif() # The C preprocessor include search path consists of every source # directory ordered by 'gt_src_list'. set(includes) foreach(d ${gt_src_list}) list(APPEND includes ${source_dir_${d}}) endforeach() include_directories(${includes}) # We generate some uniquely-named headers in the top of the build tree. include_directories(${GTM_BINARY_DIR}) # Function to select the first instance of a given source file name # found in the ordered 'gt_src_list' search path. function(select_file src_var name) set(found "") foreach(d ${gt_src_list}) set(src "${source_dir_${d}}/${name}") if(EXISTS "${src}") set(found "${src}") break() endif() endforeach() if(NOT found) message(FATAL_ERROR "Cannot find \"${name}\" as ${ARGN}") endif() set("${src_var}" "${found}" PARENT_SCOPE) endfunction() # Macro to search directories ordered by 'gt_src_list' for a given # list of source file names, assign them to a target, and exclude the # source file names from inclusion in libmumps. macro(set_source_list target) foreach(name ${ARGN}) set(src "") foreach(d ${gt_src_list}) if(";${sources_${d}};" MATCHES ";(${name}\\.(c|s|si));") set(fname ${CMAKE_MATCH_1}) set(src ${d}/${fname}) set("source_used_${fname}" 1) list(APPEND sources_used ${source_dir_${d}}/${fname}) if(NOT "${libmumpsrestoreregex}" STREQUAL "") if(";${name};" MATCHES ";(${libmumpsrestoreregex});") set("source_used_${fname}" 0) endif() endif() break() endif() endforeach() if(src) list(APPEND ${target}_SOURCES ${src}) else() message(FATAL_ERROR "No source \"${name}\" available!") endif() endforeach() endmacro() # Macro like set_source_list but that loads the list of source file # names from a file. macro(load_source_list target listfile) file(STRINGS "${listfile}" names) set_source_list(${target} ${names}) endmacro() #----------------------------------------------------------------------------- # Assign sources to libraries. load_source_list(libcmisockettcp sr_unix_gnp/libcmisockettcp.list) load_source_list(libdbcertify sr_unix/libdbcertify.list) load_source_list(libdse sr_unix/libdse.list) load_source_list(libgnpclient sr_unix_gnp/libgnpclient.list) load_source_list(libgnpserver sr_unix_gnp/libgnpserver.list) load_source_list(libgtcm sr_unix_cm/libgtcm.list) load_source_list(liblke sr_unix/liblke.list) load_source_list(libmupip sr_unix/libmupip.list) load_source_list(libstub sr_unix/libstub.list) if("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS") load_source_list(libgtmrpc sr_sun/libgtmrpc.list) endif() # Assign sources to executables. set_source_list(gtm_threadgbl_deftypes gtm_threadgbl_deftypes) set_source_list(dbcertify dbcertify dbcertify_cmd) set_source_list(dse dse dse_cmd) set_source_list(ftok ftok) set_source_list(geteuid geteuid) set_source_list(gtcm_gnp_server gtcm_gnp_server) set_source_list(gtcm_pkdisp gtcm_pkdisp) set_source_list(gtcm_play gtcm_play omi_srvc_xct) set_source_list(gtcm_server gtcm_main omi_srvc_xct) set_source_list(gtcm_shmclean gtcm_shmclean) set_source_list(gtmsecshr gtmsecshr_wrapper) set_source_list(gtmsecshr_real gtmsecshr) set_source_list(libgtmcrypt gtmcrypt_ref gtmcrypt_pk_ref gtmcrypt_dbk_ref) set_source_list(libgtmshr gtm_main) set_source_list(lke lke lke_cmd) set_source_list(maskpass maskpass) set_source_list(mumps gtm) set_source_list(mupip mupip mupip_cmd) set_source_list(semstat2 semstat2) if("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS") set_source_list(gtm_svc gtm_svc gtm_rpc_init gtm_dal_svc) endif() #----------------------------------------------------------------------------- # libmumps gets leftover sources, so compute the remaining list. set(source_used_dtgbldir.c 1) # exclude unused source set(libmumps_SOURCES "") foreach(d ${gt_src_list}) foreach(s ${sources_${d}}) if(NOT source_used_${s}) list(APPEND libmumps_SOURCES ${d}/${s}) set(source_used_${s} 1) list(APPEND sources_used ${source_dir_${d}}/${s}) endif() endforeach() endforeach() #----------------------------------------------------------------------------- # Generate files depending on gtm # Copy generation routines to a working directory. foreach(m chk2lev.m chkop.m gendash.m genout.m loadop.m loadvx.m msg.m tttgen.m tttscan.m) add_custom_command( OUTPUT gen/${m} DEPENDS ${GTM_SOURCE_DIR}/sr_port/${m} COMMAND ${CMAKE_COMMAND} -E copy ${GTM_SOURCE_DIR}/sr_port/${m} ${GTM_BINARY_DIR}/gen/${m} ) endforeach() foreach(f ttt.txt opcode_def.h vxi.h) select_file(src ${f}) list(APPEND tttfiles ${src}) endforeach() set(mumps_ttt_args -run tttgen ${tttfiles}) add_custom_command( OUTPUT gen/ttt.c DEPENDS ${tttfiles} gen/chk2lev.m gen/chkop.m gen/gendash.m gen/genout.m gen/loadop.m gen/loadvx.m gen/tttgen.m gen/tttscan.m ${GTM_SOURCE_DIR}/sr_unix/mumps.cmake ${gen_bootstrap_depend} WORKING_DIRECTORY ${GTM_BINARY_DIR}/gen COMMAND ${CMAKE_COMMAND} -D gtm_dist=${gen_bootstrap_dist} -D gtmroutines=. -D mumps=${gen_bootstrap_mumps} -D "args=${mumps_ttt_args}" -D output_file=ttt.log -P ${GTM_SOURCE_DIR}/sr_unix/mumps.cmake VERBATIM ) list(APPEND gen_bootstrap_files gen/ttt.c) set(gen_merrors_extra gen/merrors_ansi.h) foreach(msg sr_port/cmerrors.msg sr_port/gdeerrors.msg sr_port/merrors.msg sr_unix_gnp/cmierrors.msg ) get_filename_component(name ${msg} NAME_WE) set(mumps_msg_args -run msg ${GTM_SOURCE_DIR}/${msg} unix) set(outputs gen/${name}_ctl.c ${gen_${name}_extra}) add_custom_command( OUTPUT ${outputs} DEPENDS gen/msg.m ${GTM_SOURCE_DIR}/${msg} ${GTM_SOURCE_DIR}/sr_unix/mumps.cmake ${gen_bootstrap_depend} WORKING_DIRECTORY ${GTM_BINARY_DIR}/gen COMMAND ${CMAKE_COMMAND} -D gtm_dist=${gen_bootstrap_dist} -D gtmroutines=. -D mumps=${gen_bootstrap_mumps} -D "args=${mumps_msg_args}" -P ${GTM_SOURCE_DIR}/sr_unix/mumps.cmake VERBATIM ) list(APPEND gen_bootstrap_files ${outputs}) endforeach() add_custom_target(gen_bootstrap ALL DEPENDS ${gen_bootstrap_files}) #----------------------------------------------------------------------------- if(gen_xfer_desc) list(SORT sources_used) set(CMAKE_CONFIGURABLE_FILE_CONTENT "") foreach(src ${sources_used}) set(CMAKE_CONFIGURABLE_FILE_CONTENT "${CMAKE_CONFIGURABLE_FILE_CONTENT}${src}\n") endforeach() configure_file(${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in ${GTM_BINARY_DIR}/sources.list) add_custom_command( OUTPUT xfer_desc.i WORKING_DIRECTORY ${GTM_BINARY_DIR} DEPENDS ${GTM_SOURCE_DIR}/sr_unix/gen_xfer_desc.cmake ${GTM_BINARY_DIR}/sources.list COMMAND ${CMAKE_COMMAND} -D CMAKE_C_COMPILER=${CMAKE_C_COMPILER} -D "arch=${arch}" -D "includes=${includes}" -P ${GTM_SOURCE_DIR}/sr_unix/gen_xfer_desc.cmake VERBATIM ) add_custom_target(gen_xfer_desc DEPENDS xfer_desc.i) if(gen_bootstrap) add_dependencies(gen_xfer_desc gen_bootstrap) endif() endif() #----------------------------------------------------------------------------- add_executable(gtm_threadgbl_deftypes ${gtm_threadgbl_deftypes_SOURCES}) if(gen_xfer_desc) add_dependencies(gtm_threadgbl_deftypes gen_xfer_desc) elseif(gen_bootstrap) add_dependencies(gtm_threadgbl_deftypes gen_bootstrap) endif() add_custom_command( OUTPUT gtm_threadgbl_deftypes.h DEPENDS gtm_threadgbl_deftypes COMMAND gtm_threadgbl_deftypes > gtm_threadgbl_deftypes.h.tmp COMMAND ${CMAKE_COMMAND} -E rename gtm_threadgbl_deftypes.h.tmp gtm_threadgbl_deftypes.h ) add_custom_target(gen_gtm_threadgbl_deftypes DEPENDS gtm_threadgbl_deftypes.h) foreach(exp exe shr) set(out gtm${exp}_symbols.export) set(in ${GTM_SOURCE_DIR}/sr_unix/gtm${exp}_symbols.exp) add_custom_command( OUTPUT ${out} DEPENDS ${in} COMMAND tcsh -f ${GTM_SOURCE_DIR}/sr_linux/genexport.csh ${in} ${out} ) endforeach() add_custom_target(gen_export DEPENDS gtmexe_symbols.export gtmshr_symbols.export) foreach(lib gtcm cmisockettcp gnpclient gnpserver dbcertify dse lke mupip stub mumps ${extralibs} ) add_library(lib${lib} STATIC ${lib${lib}_SOURCES}) set_property(TARGET lib${lib} PROPERTY OUTPUT_NAME ${lib}) add_dependencies(lib${lib} gen_gtm_threadgbl_deftypes) endforeach() # TODO: find_package or find_library for system libs? include_directories ("/usr/local/include") target_link_libraries(libmumps ${libmumpslibs}) add_executable(mumps ${mumps_SOURCES}) target_link_libraries(mumps libmumps) add_executable(dse ${dse_SOURCES}) target_link_libraries(dse libdse libmumps libstub) list(APPEND with_export dse) add_executable(dbcertify ${dbcertify_SOURCES}) target_link_libraries(dbcertify libdbcertify libmupip libmumps libstub) add_executable(geteuid ${geteuid_SOURCES}) add_executable(gtmsecshr ${gtmsecshr_SOURCES}) add_dependencies(gtmsecshr gen_gtm_threadgbl_deftypes) add_executable(gtmsecshr_real ${gtmsecshr_real_SOURCES}) target_link_libraries(gtmsecshr_real libmumps) set_target_properties(gtmsecshr_real PROPERTIES OUTPUT_NAME gtmsecshr RUNTIME_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/gtmsecshrdir ) add_dependencies(gtmsecshr_real gen_gtm_threadgbl_deftypes) add_executable(mupip ${mupip_SOURCES}) target_link_libraries(mupip libmupip libmumps libstub) list(APPEND with_export mupip) add_executable(lke ${lke_SOURCES}) target_link_libraries(lke liblke libmumps libgnpclient libmumps libgnpclient libcmisockettcp) list(APPEND with_export lke) add_executable(gtcm_server ${gtcm_server_SOURCES}) target_link_libraries(gtcm_server libgtcm libmumps libstub) list(APPEND with_export gtcm_server) add_executable(gtcm_gnp_server ${gtcm_gnp_server_SOURCES}) target_link_libraries(gtcm_gnp_server libgnpserver liblke libmumps libcmisockettcp libstub) list(APPEND with_export gtcm_gnp_server) add_executable(gtcm_play ${gtcm_play_SOURCES}) target_link_libraries(gtcm_play libgtcm libmumps libstub) list(APPEND with_export gtcm_play) add_executable(gtcm_pkdisp ${gtcm_pkdisp_SOURCES}) target_link_libraries(gtcm_pkdisp libgtcm libmumps libstub) add_executable(gtcm_shmclean ${gtcm_shmclean_SOURCES}) target_link_libraries(gtcm_shmclean libgtcm libmumps libstub) add_executable(semstat2 ${semstat2_SOURCES}) add_executable(ftok ${ftok_SOURCES}) target_link_libraries(ftok libmumps libstub) if("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS") add_executable(gtm_svc ${gtm_svc_SOURCES}) target_link_libraries(gtm_svc libmumps libgnpclient libcmisockettcp libgtmrpc) endif() foreach(t ${with_export}) set_target_properties(${t} PROPERTIES LINK_FLAGS "${gtm_link}" LINK_DEPENDS "${gtm_dep}" ) add_dependencies(${t} gen_export) endforeach() add_library(libgtmshr MODULE ${libgtmshr_SOURCES}) set_property(TARGET libgtmshr PROPERTY OUTPUT_NAME gtmshr) target_link_libraries(libgtmshr libmumps libgnpclient libcmisockettcp) set_target_properties(libgtmshr PROPERTIES LINK_FLAGS "${libgtmshr_link}" LINK_DEPENDS "${libgtmshr_dep}" ) add_dependencies(libgtmshr gen_export) add_dependencies(mumps libgtmshr) if(is_encryption_supported) # Iterate over the list of GPG related libraries foreach(gpglib gpg-error gpgme gcrypt) # For each library, we need a new CMake variable, hence GPGLIB_${gpglib} find_library(GPGLIB_${gpglib} NAME ${gpglib} PATHS ${CMAKE_LIBRARY_PATH}) # Append the found library to the list set(GPG_LIBRARIES ${GPG_LIBRARIES} ${GPGLIB_${gpglib}}) endforeach() add_library(libgtmcrypt MODULE ${libgtmcrypt_SOURCES}) set_target_properties(libgtmcrypt PROPERTIES OUTPUT_NAME gtmcrypt COMPILE_DEFINITIONS "USE_GCRYPT -DUSE_AES256CFB" LIBRARY_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin ) target_link_libraries(libgtmcrypt ${GPG_LIBRARIES}) install(TARGETS libgtmcrypt DESTINATION ${GTM_INSTALL_DIR}/plugin) add_executable(maskpass ${maskpass_SOURCES}) target_link_libraries(maskpass ${GPG_LIBRARIES}) set_target_properties(maskpass PROPERTIES COMPILE_DEFINITIONS USE_GCRYPT RUNTIME_OUTPUT_DIRECTORY ${GTM_BINARY_DIR}/plugin/gtmcrypt ) install(TARGETS maskpass DESTINATION ${GTM_INSTALL_DIR}/plugin/gtmcrypt) foreach(f add_db_key.sh build.sh encrypt_sign_db_key.sh gen_keypair.sh gen_sym_hash.sh gen_sym_key.sh gtmcrypt.tab gtmcrypt_dbk_ref.c gtmcrypt_dbk_ref.h gtmcrypt_interface.h gtmcrypt_pk_ref.c gtmcrypt_pk_ref.h gtmcrypt_dbk_ref.c gtmcrypt_dbk_ref.h gtmcrypt_ref.c gtmcrypt_ref.h gtmcrypt_sym_ref.h gtmxc_types.h import_and_sign_key.sh install.sh maskpass.c pinentry-gtm.sh pinentry.m pinentry.m show_install_config.sh ) set(f_in "${GTM_SOURCE_DIR}/sr_unix/${f}") set(f_out "${GTM_BINARY_DIR}/plugin/gtmcrypt/${f}") add_custom_command( OUTPUT "${f_out}" DEPENDS "${f_in}" COMMAND ${CMAKE_COMMAND} -E copy "${f_in}" "${f_out}" ) if("${f}" MATCHES "\\.sh$") set(permissions PERMISSIONS ${install_permissions_script}) else() set(permissions "") endif() install(FILES "${f_out}" DESTINATION ${GTM_INSTALL_DIR}/plugin/gtmcrypt ${permissions}) list(APPEND files_to_place "${f_out}") endforeach() endif() install(TARGETS mumps dse lke geteuid gtcm_server gtcm_gnp_server gtcm_pkdisp gtcm_play gtcm_shmclean semstat2 ftok gtmsecshr mupip libgtmshr DESTINATION ${GTM_INSTALL_DIR} ) install(TARGETS gtmsecshr_real DESTINATION ${GTM_INSTALL_DIR}/gtmsecshrdir) # .m -> .m #file(GLOB m_files_sr_port RELATIVE ${GTM_SOURCE_DIR}/sr_port ${GTM_SOURCE_DIR}/sr_port/*.m) set(m_files_sr_port gde.m gdeadd.m gdechang.m gdedelet.m gdeexit.m gdehelp.m gdeinit.m gdelocks.m gdelog.m gdemap.m gdemsgin.m gdeparse.m gdequit.m gderenam.m gdescan.m gdesetgd.m gdeshow.m gdespawn.m gdetempl.m ) file(GLOB m_files_sr_unix RELATIVE ${GTM_SOURCE_DIR}/sr_unix ${GTM_SOURCE_DIR}/sr_unix/*.m) file(GLOB mpt_files_sr_port RELATIVE ${GTM_SOURCE_DIR}/sr_port ${GTM_SOURCE_DIR}/sr_port/*.mpt) file(GLOB mpt_files_sr_unix RELATIVE ${GTM_SOURCE_DIR}/sr_unix ${GTM_SOURCE_DIR}/sr_unix/*.mpt) set(gtm_chset_dir_ "") set(gtm_chset_dir_UTF-8 "/utf8") foreach(d sr_port sr_unix) foreach(m ${m_files_${d}}) get_filename_component(m_name "${m}" NAME_WE) string(TOUPPER "${m_name}" m_upper) if("${m}" MATCHES "^gde") foreach(gtm_chset "" "UTF-8") set(m_out "${GTM_BINARY_DIR}${gtm_chset_dir_${gtm_chset}}/${m_upper}.m") add_custom_command( OUTPUT "${m_out}" DEPENDS ${GTM_SOURCE_DIR}/${d}/${m} COMMAND ${CMAKE_COMMAND} -E copy ${GTM_SOURCE_DIR}/${d}/${m} "${m_out}" ) list(APPEND files_to_place "${m_out}") list(APPEND gtm_chset_routines_${gtm_chset} "${m_out}") endforeach() else() set(m_out "${GTM_BINARY_DIR}/${m_upper}.m") add_custom_command( OUTPUT "${m_out}" DEPENDS ${GTM_SOURCE_DIR}/${d}/${m} COMMAND ${CMAKE_COMMAND} -E copy ${GTM_SOURCE_DIR}/${d}/${m} "${m_out}" ) install(FILES "${m_out}" DESTINATION ${GTM_INSTALL_DIR}) list(APPEND files_to_place "${m_out}") endif() endforeach() foreach(m ${mpt_files_${d}}) string(TOUPPER "_${m}" m_upper) string(REGEX REPLACE "MPT$" "m" m_out "${GTM_BINARY_DIR}/${m_upper}") add_custom_command( OUTPUT "${m_out}" DEPENDS ${GTM_SOURCE_DIR}/${d}/${m} COMMAND ${CMAKE_COMMAND} -E copy ${GTM_SOURCE_DIR}/${d}/${m} "${m_out}" ) install(FILES "${m_out}" DESTINATION ${GTM_INSTALL_DIR}) list(APPEND files_to_place "${m_out}") endforeach() endforeach() set(files) foreach(f gtm_descript.h gtm_limits.h gtm_sizeof.h gtm_stdio.h gtm_stdlib.h gtm_string.h gtm_strings.h gtmxc_types.h main_pragma.h arch.gtc gtcm_run.gtc gtcm_slist.gtc gdedefaults.gtc gtmcshrc.gtc gtmprofile.gtc gtmprofile_preV54000.gtc gtmstart.gtc gtmstop.gtc dse.hlp gde.hlp lke.hlp mumps.hlp mupip.hlp custom_errors_sample.txt ) select_file(src ${f}) list(APPEND files ${src}) endforeach() install(FILES ${files} DESTINATION ${GTM_INSTALL_DIR}) set(scripts) foreach(f gtm.gtc gtmbase.gtc ) select_file(src ${f}) list(APPEND scripts ${src}) endforeach() install(FILES ${scripts} DESTINATION ${GTM_INSTALL_DIR} PERMISSIONS ${install_permissions_script} ) find_program(ICUCONFIG NAMES icu-config) if(ICUCONFIG) execute_process( COMMAND ${ICUCONFIG} --version OUTPUT_VARIABLE icu_version RESULT_VARIABLE icu_failed OUTPUT_STRIP_TRAILING_WHITESPACE ) if(icu_failed) message(FATAL_ERROR "Command\n ${ICUCONFIG} --version\nfailed (${icu_failed}).") elseif("x${icu_version}" MATCHES "^x([0-9]+\\.[0-9]+)") set(gtm_icu_version "${CMAKE_MATCH_1}") else() message(FATAL_ERROR "Command\n ${ICUCONFIG} --version\nproduced unrecognized output:\n ${icu_version}") endif() else() message(FATAL_ERROR "Unable to find 'icu-config'. Set ICUCONFIG in CMake cache.") endif() if (gtm_icu_version GREATER 10) message("libicu version ${gtm_icu_version} > 10") string(REGEX REPLACE "([0-9])([0-9]).*" "\\1.\\2" gtm_icu_version "${gtm_icu_version}") message("Fixing gtm_icu_version to ${gtm_icu_version}.\nThis had better be the default") endif() foreach(gtm_chset "" "UTF-8") foreach(in ${gtm_chset_routines_${gtm_chset}}) string(REPLACE ".m" ".o" out "${in}") get_filename_component(out_dir "${out}" PATH) add_custom_command( OUTPUT ${out} DEPENDS ${in} ${GTM_SOURCE_DIR}/sr_unix/mumps.cmake mumps COMMAND ${CMAKE_COMMAND} -D gtm_dist=${GTM_BINARY_DIR} -D gtmroutines=. -D gtm_chset=${gtm_chset} -D gtm_icu_version=${gtm_icu_version} -D mumps=$ -D "args=${in}" -P ${GTM_SOURCE_DIR}/sr_unix/mumps.cmake WORKING_DIRECTORY ${out_dir} VERBATIM ) list(APPEND files_to_place ${out}) install(FILES "${out}" DESTINATION ${GTM_INSTALL_DIR}${gtm_chset_dir_${gtm_chset}}) endforeach() endforeach() #----------------------------------------------------------------------------- set(gtm_hlp mumps.hlp) set(gde_hlp gde.hlp) set(mupip_hlp mupip.hlp) set(dse_hlp dse.hlp) set(lke_hlp lke.hlp) foreach(help gtm gde mupip dse lke) set(CMAKE_CONFIGURABLE_FILE_CONTENT "Change -segment DEFAULT -block=2048 -file=\$gtm_dist/${help}help.dat Change -region DEFAULT -record=1020 -key=255 exit") configure_file(${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in ${GTM_BINARY_DIR}/${help}help.in1) set(CMAKE_CONFIGURABLE_FILE_CONTENT "Do ^GTMHLPLD ${GTM_SOURCE_DIR}/sr_port/${${help}_hlp} Halt") configure_file(${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in ${GTM_BINARY_DIR}/${help}help.in2) set(env -D gtm_dist=${GTM_BINARY_DIR} -D gtmroutines=. -D gtmgbldir=${GTM_BINARY_DIR}/${help}help ) add_custom_command( OUTPUT ${help}help.dat ${help}help.gld DEPENDS ${GTM_SOURCE_DIR}/sr_unix/mumps.cmake mumps mupip ${GTM_BINARY_DIR}/${help}help.in1 ${GTM_BINARY_DIR}/${help}help.in2 COMMAND ${CMAKE_COMMAND} -E remove ${help}help.dat ${help}help.gld COMMAND ${CMAKE_COMMAND} ${env} -D mumps=$ -D "args=-run;GDE" -D input_file=${GTM_BINARY_DIR}/${help}help.in1 -P ${GTM_SOURCE_DIR}/sr_unix/mumps.cmake COMMAND ${CMAKE_COMMAND} ${env} -D mumps=$ -D "args=create" -P ${GTM_SOURCE_DIR}/sr_unix/mumps.cmake COMMAND ${CMAKE_COMMAND} ${env} -D mumps=$ -D "args=-direct" -D input_file=${GTM_BINARY_DIR}/${help}help.in2 -P ${GTM_SOURCE_DIR}/sr_unix/mumps.cmake VERBATIM ) list(APPEND files_to_place ${help}help.dat) install(FILES ${GTM_BINARY_DIR}/${help}help.dat DESTINATION ${GTM_INSTALL_DIR}) endforeach() #----------------------------------------------------------------------------- set(GTM_TOP "${GTM_BINARY_DIR}") configure_file(sr_unix/gpgagent.tab.in plugin/gpgagent.tab @ONLY) set(GTM_TOP "${CMAKE_INSTALL_PREFIX}/${GTM_INSTALL_DIR}") configure_file(sr_unix/gpgagent.tab.in CMakeFiles/plugin/gpgagent.tab @ONLY) install(FILES ${GTM_BINARY_DIR}/CMakeFiles/plugin/gpgagent.tab DESTINATION ${GTM_INSTALL_DIR}/plugin) install(FILES sr_unix/configure.gtc DESTINATION ${GTM_INSTALL_DIR} PERMISSIONS ${install_permissions_script} RENAME configure ) install(FILES sr_unix/gtminstall.sh DESTINATION ${GTM_INSTALL_DIR} PERMISSIONS ${install_permissions_script} RENAME gtminstall ) install(FILES sr_unix/lowerc_cp.sh DESTINATION ${GTM_INSTALL_DIR} RENAME lowerc_cp ) install(FILES COPYING DESTINATION ${GTM_INSTALL_DIR}) add_custom_target(place_files ALL DEPENDS ${files_to_place}) fis-gtm-V6.0-003/COPYING0000644000032200000250000010333012201176223013371 0ustar librarygtc GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU Affero General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Remote Network Interaction; Use with the GNU General Public License. Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . fis-gtm-V6.0-003/LICENSE0000644000032200000250000000110012201176223013333 0ustar librarygtcAll software in this package is part of FIS GT.M (http://fis-gtm.com) which is Copyright 2013 Fidelity Information Services, Inc., and provided to you under the terms of a license. If there is a COPYING file included in this package, it contains the terms of the license under which the package is provided to you. If there is not a COPYING file in the package, you must ensure that your use of FIS GT.M complies with the license under which it is provided. If you are unsure as to the terms of your license, please consult with the entity that provided you with the package. fis-gtm-V6.0-003/README0000644000032200000250000000727312201176223013227 0ustar librarygtcAll software in this package is part of FIS GT.M (http://fis-gtm.com) which is Copyright 2013 Fidelity Information Services, Inc., and provided to you under the terms of a license. If there is a COPYING file included in this package, it contains the terms of the license under which the package is provided to you. If there is not a COPYING file in the package, you must ensure that your use of FIS GT.M complies with the license under which it is provided. If you are unsure as to the terms of your license, please consult with the entity that provided you with the package. GT.M relies on CMake to generate the Makefiles to build GT.M from source. The prerequisites are CMake (at least 2.8.5), GNU make (at least 3.81), Linux (either x86 or x86_64), Unicode include files and GPG. Unicode include files are automatically installed if ICU is installed. GPG include files require installing the GNUPG and related library development packages. Debian 6, Ubuntu 12.04 LTS and RHEL 6.0 were used to do the test builds for this distribution. The default ICU and GPG packages were taken from the distribution repositories. To build GT.M for Linux, do the following steps: 1. Fulfill the pre-requisites Install developement libraries libelf, zlib, libicu, libgpgme, libgpg-error, libgcrypt. Ensure that your locale settings are correct, otherwise you will see GTM-E-NONUTF8LOCALE messages. Refer the Messages and Recovery Procedures Manual if you do encounter these messages. [optional] The GT.M source tarball includes pre-generated files. To generate these files requires a binary distribution of GT.M. You can download GT.M from http://sourceforge.net/projects/fis-gtm/ Unpack the tar file and run the configure script as root. Note: the tar file unpacks everything into your current working directory, not a new subdirectory. The Linux Standard Base (LSB) install path for GT.M V6.0-003 is /opt/fis-gtm/V6.0-003_i686 or /opt/fis-gtm/V6.0-003_x8664. These instrcutions are written using x8664, please use i686 as necessary. $ tar xfz gtm_V60003_linux_x8664_pro.tar.gz # Note down the installation path for use with cmake below $ sudo sh ./configure 2. Unpack the GT.M sources The GT.M source tarball extracts to a directory with the version number in the name, fis-gtm-V6.0-003 $ tar xfz fis-gtm-V6.0-003.tar.gz $ cd fis-gtm-V6.0-003 You should find this README, LICENSE, COPYING and CMakeLists.txt file and sr_* source directories. 3. Building GT.M - can be a sub directory of the source directory, fis-gtm-V6.0-003, or any other valid path. $ mkdir $ cd # [optional] If you installed GT.M, provide the directory path to cmake # -D GTM_DIST:PATH=$gtm_dist # # By default the build produces release versions of GT.M. To build a debug # version of GT.M supply the following parameter to cmake # -D CMAKE_BUILD_TYPE=DEBUG # # Note that the cmake install does not create the final installed GT.M. # Instead, it stages GT.M for distribution. Change the CMAKE_INSTALL_PREFIX # to place the staged files in a local directory. To install GT.M, you must # cd to that installed directory and execute the configure script. # # -D CMAKE_INSTALL_PREFIX:PATH=${PWD}/package # $ cmake /fis-gtm-V6.0-003 -D CMAKE_INSTALL_PREFIX:PATH=${PWD}/package $ make $ make install $ cd package/lib/fis-gtm/V6.0-003_x86_64 # Now you are ready to install GT.M. Answer a few questions and install it. # The recommended installation path is /opt/fis-gtm/V6.0-003_x86_64 $ sudo ./configure $ make clean 4. Packaging GT.M - Create a tar file from the installed directory fis-gtm-V6.0-003/sr_alpha/0000755000032200000250000000000012201176175014135 5ustar librarygtcfis-gtm-V6.0-003/sr_alpha/axp.h0000644000032200000250000001161712201176170015077 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* axp.h - AXP machine instruction information. * * Requires "axp_registers.h" and "axp_gtm_registers.h". * */ /* Machine instruction templates. */ #define ALPHA_INS_ADDL ((unsigned)0x10 << ALPHA_SHIFT_OP) #define ALPHA_INS_BEQ ((unsigned)0x39 << ALPHA_SHIFT_OP) #define ALPHA_INS_BGE ((unsigned)0x3e << ALPHA_SHIFT_OP) #define ALPHA_INS_BGT ((unsigned)0x3f << ALPHA_SHIFT_OP) #define ALPHA_INS_BIS ((unsigned)0x11 << ALPHA_SHIFT_OP | 0x20 << ALPHA_SHIFT_FUNC) #define ALPHA_INS_BLE ((unsigned)0x3b << ALPHA_SHIFT_OP) #define ALPHA_INS_BLT ((unsigned)0x3a << ALPHA_SHIFT_OP) #define ALPHA_INS_BLBC ((unsigned)0x38 << ALPHA_SHIFT_OP) #define ALPHA_INS_BLBS ((unsigned)0x3c << ALPHA_SHIFT_OP) #define ALPHA_INS_BNE ((unsigned)0x3d << ALPHA_SHIFT_OP) #define ALPHA_INS_BSR ((unsigned)0x34 << ALPHA_SHIFT_OP) #define ALPHA_INS_BR ((unsigned)0x30 << ALPHA_SHIFT_OP) #define ALPHA_INS_JMP ((unsigned)0x1a << ALPHA_SHIFT_OP) #define ALPHA_INS_JSR ((unsigned)0x1a << ALPHA_SHIFT_OP | 1 << ALPHA_SHIFT_BRANCH_FUNC) #define ALPHA_INS_LDA ((unsigned)0x08 << ALPHA_SHIFT_OP) #define ALPHA_INS_LDAH ((unsigned)0x09 << ALPHA_SHIFT_OP) #define ALPHA_INS_LDL ((unsigned)0x28 << ALPHA_SHIFT_OP) #define ALPHA_INS_LDQ ((unsigned)0x29 << ALPHA_SHIFT_OP) #define ALPHA_INS_RET ((unsigned)0x1a << ALPHA_SHIFT_OP | 2 << ALPHA_SHIFT_BRANCH_FUNC) #define ALPHA_INS_STL ((unsigned)0x2c << ALPHA_SHIFT_OP) #define ALPHA_INS_STQ ((unsigned)0x2d << ALPHA_SHIFT_OP) #define ALPHA_INS_SUBL ((unsigned)0x10 << ALPHA_SHIFT_OP | 0x9 << ALPHA_SHIFT_FUNC) #define ALPHA_INS_SUBQ ((unsigned)0x10 << ALPHA_SHIFT_OP | 0x29 << ALPHA_SHIFT_FUNC) /* Bit offsets to instruction fields. */ #define ALPHA_SHIFT_OP 26 #define ALPHA_SHIFT_BRANCH_FUNC 14 #define ALPHA_SHIFT_FUNC 5 #define ALPHA_SHIFT_LITERAL 13 #define ALPHA_SHIFT_RA 21 #define ALPHA_SHIFT_RB 16 #define ALPHA_SHIFT_RC 0 #define ALPHA_SHIFT_BRANCH_DISP 0 #define ALPHA_SHIFT_DISP 0 /* Bit masks for instruction fields. */ #define ALPHA_BIT_LITERAL (1 << 12) #define ALPHA_MASK_BRANCH_DISP 0x1fffff #define ALPHA_MASK_BRANCH_FUNC 0xc00000 #define ALPHA_MASK_DISP 0xffff #define ALPHA_MASK_FUNC 0x7f #define ALPHA_MASK_LITERAL 0xff #define ALPHA_MASK_OP 0x3f #define ALPHA_MASK_REG 0x1f /* Alternative assembler mnemonics for machine instruction. */ #define ALPHA_INS_CLRQ (ALPHA_INS_BIS \ | (ALPHA_REG_ZERO << ALPHA_SHIFT_RA) \ | (ALPHA_REG_ZERO << ALPHA_SHIFT_RB)) #define ALPHA_INS_LPC (ALPHA_INS_BR \ | (GTM_REG_CODEGEN_TEMP << ALPHA_SHIFT_RA)) #define ALPHA_INS_MOVE (ALPHA_INS_BIS \ | ALPHA_REG_ZERO << ALPHA_SHIFT_RB) #define ALPHA_INS_NOP (ALPHA_INS_BIS \ | (ALPHA_REG_ZERO << ALPHA_SHIFT_RA) \ | (ALPHA_REG_ZERO << ALPHA_SHIFT_RB) \ | (ALPHA_REG_ZERO << ALPHA_SHIFT_RC)) /* Construction forms. */ #define ALPHA_BRA(op,ra,disp) ((op) | ((ra) << ALPHA_SHIFT_RA) | (disp)&ALPHA_MASK_BRANCH_DISP) #define ALPHA_JMP(op,ra,rb) ((op) | ((ra) << ALPHA_SHIFT_RA) | ((rb) << ALPHA_SHIFT_RB)) #define ALPHA_LIT(op,ra,lit,rc) ((op) | ((ra) << ALPHA_SHIFT_RA) \ | (((lit)&ALPHA_MASK_LITERAL) << ALPHA_SHIFT_LITERAL) \ | ALPHA_BIT_LITERAL \ | ((rc) << ALPHA_SHIFT_RC)) #define ALPHA_MEM(op,ra,rb,disp)((op) | ((ra) << ALPHA_SHIFT_RA) | ((rb) << ALPHA_SHIFT_RB) | (disp)&ALPHA_MASK_DISP) #define ALPHA_OPR(op,ra,rb,rc) ((op) | ((ra) << ALPHA_SHIFT_RA) | ((rb) << ALPHA_SHIFT_RB) | ((rc) << ALPHA_SHIFT_RC)) #ifdef DEBUG #define GET_OPCODE(ains) ((ains >> ALPHA_SHIFT_OP) & ALPHA_MASK_OP) #define GET_RA(ains) ((ains >> ALPHA_SHIFT_RA) & ALPHA_MASK_REG) #define GET_RB(ains) ((ains >> ALPHA_SHIFT_RB) & ALPHA_MASK_REG) #define GET_RC(ains) ((ains >> ALPHA_SHIFT_RC) & ALPHA_MASK_REG) #define GET_MEMDISP(ains) ((ains >> ALPHA_SHIFT_DISP) & ALPHA_MASK_DISP) #define GET_BRDISP(ains) ((ains >> ALPHA_SHIFT_BRANCH_DISP) & ALPHA_MASK_BRANCH_DISP) #define GET_FUNC(ains) ((ains >> ALPHA_SHIFT_FUNC) & ALPHA_MASK_FUNC) #define ADDL_INST "addl" #define SUBL_INST "subl" #define SUBQ_INST "subq" #define BIS_INST "bis" #define JSR_INST "jsr" #define RET_INST "ret" #define JMP_INST "jmp" #define LDA_INST "lda" #define LDAH_INST "ldah" #define LDL_INST "ldl" #define LDQ_INST "ldq" #define STL_INST "stl" #define STQ_INST "stq" #define BR_INST "br" #define BSR_INST "bsr" #define BLBC_INST "blbc" #define BEQ_INST "beq" #define BLT_INST "blt" #define BLE_INST "ble" #define BLBS_INST "blbs" #define BNE_INST "bne" #define BGE_INST "bge" #define BGT_INST "bgt" #define CONSTANT "Constant 0x" /* Space for op_code to be in */ #define OPSPC 7 #endif fis-gtm-V6.0-003/sr_alpha/cacheflush.m640000644000032200000250000000177612201176170016600 0ustar librarygtc; ################################################################ ; # # ; # Copyright 2001, 2008 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ################################################################ .title cacheflush - flush data and instruction caches ; cacheflush ; ; entry: ; a0 (r16) address of start of region to flush ; a1 (r17) length (in bytes) of region to flush ; a2 (r18) flag indicating which region to flush (not used on AXP) $routine name=cacheflush, entry=cacheflush_ca, kind=null imb ret r26 $end_routine name=cacheflush fis-gtm-V6.0-003/sr_alpha/double2s.c0000644000032200000250000001062212201176170016014 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "stringpool.h" #define MAX_NUM_SIZE 64 GBLREF spdesc stringpool; static char pot_index [256] = { -78, 78, -77, 77, 77, 77, -76, 76, 76, -75, 75, 75, -74, 74, 74, 74, -73, 73, 73, -72, 72, 72, -71, 71, 71, 71, -70, 70, 70, -69, 69, 69, -68, 68, 68, -67, 67, 67, 67, -66, 66, 66, -65, 65, 65, -64, 64, 64, 64, -63, 63, 63, -62, 62, 62, -61, 61, 61, 61, -60, 60, 60, -59, 59, 59, -58, 58, 58, 58, -57, 57, 57, -56, 56, 56, -55, 55, 55, 55, -54, 54, 54, -53, 53, 53, -52, 52, 52, 52, -51, 51, 51, -50, 50, 50, -49, 49, 49, 49, -48, 48, 48, -47, 47, 47, -46, 46, 46, 46, -45, 45, 45, -44, 44, 44, -43, 43, 43, 43, -42, 42, 42, -41, 41, 41, -40, 40, 40, 40, -39, 39, 39, -38, 38, 38, -37, 37, 37, -36, 36, 36, 36, -35, 35, 35, -34, 34, 34, -33, 33, 33, 33, -32, 32, 32, -31, 31, 31, -30, 30, 30, 30, -29, 29, 29, -28, 28, 28, -27, 27, 27, 27, -26, 26, 26, -25, 25, 25, -24, 24, 24, 24, -23, 23, 23, -22, 22, 22, -21, 21, 21, 21, -20, 20, 20, -19, 19, 19, -18, 18, 18, 18, -17, 17, 17, -16, 16, 16, -15, 15, 15, 15, -14, 14, 14, -13, 13, 13, -12, 12, 12, 12, -11, 11, 11, -10, 10, 10, -9, 9, 9, -8, 8, 8, 8, -7, 7, 7, -6, 6, 6, -5, 5, 5, 5, -4, 4, 4, -3, 3, 3, -2, 2, 2, 2, -1 }; static double pot [79] = { 1.701411834604692e+38 + 2.83e+22, 1e+38, 1e+37, 1e+36, 1e+35, 1e+34, 1e+33, 1e+32, 1e+31, 1e+30, 1e+29, 1e+28, 1e+27, 1e+26, 1e+25, 1e+24, 1e+23, 1e+22, 1e+21, 1e+20, 1e+19, 1e+18, 1e+17, 1e+16, 1e+15, 1e+14, 1e+13, 1e+12, 1e+11, 1e+10, 1e+9, 1e+8, 1e+7, 1e+6, 1e+5, 1e+4, 1e+3, 1e+2, 1e+1, 1.0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, 1e-9, 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 1e-16, 1e-17, 1e-18, 1e-19, 1e-20, 1e-21, 1e-22, 1e-23, 1e-24, 1e-25, 1e-26, 1e-27, 1e-28, 1e-29, 1e-30, 1e-31, 1e-32, 1e-33, 1e-34, 1e-35, 1e-36, 1e-37, 1e-38, 0 }; #define POT_UNITY 39 /* Subscript of pot: pot[POT_UNITY] == 1.0 */ struct D_float /* Format of D-floating point datum */ { unsigned int : 7; /* fraction, bits 0:6 */ unsigned int exp : 8; /* exponent, bits 7:14 */ unsigned int sign : 1; /* sign, bit 15 */ unsigned int : 16; /* fraction, bits 16:31 */ unsigned int : 32; /* fraction, bits 32:63 */ }; void double2s (double *dp, mval *v) { double d = *dp; char *p, *q; int i, j, k; ENSURE_STP_FREE_SPACE(MAX_NUM_SIZE); assert (stringpool.free >= stringpool.base); v->mvtype = MV_STR; p = v->str.addr = (char *)stringpool.free; if (d == 0.0) *p++ = '0'; else { if (d < 0.0) { *p++ = '-'; /* plug in a minus sign */ d = -d; /* but make d positive */ } i = pot_index[((struct D_float *)dp)->exp]; if (i < 0) { i = -i; if (d < pot[i]) ++i; } i = POT_UNITY + 1 - i; /* "Normalize" the number; i.e. adjust it to be between 0.0 and 1.0 */ d *= pot[i + POT_UNITY]; if (d < 5e-16) /* Call it zero */ *p++ = '0'; else { /* Round the sixteenth digit */ d += 5e-16; if (d >= 1.0) { /* Readjust it to be between 0.0 and 1.0 */ d /= 10.0; ++i; } q = p; /* q will point to the last non-zero byte */ j = i; if (i <= 0) { *p++ = '.'; for (; i < 0; ++i) *p++ = '0'; } for (i = 15; i > 0; --i) { /* Multiply the value by ten, put the integer portion of the result into k (0 <= k <= 9), and replace the value with the fractional portion of the result */ k = d *= 10.0; d -= k; *p++ = '0' + k; if (k > 0) q = p; if (--j == 0) { q = p; *p++ = '.'; } } if (j > 0) do *p++ = '0'; while (--j > 0); else p = q; } } v->str.len = p - (char *)stringpool.free; stringpool.free = (unsigned char *)p; assert(stringpool.free <= stringpool.top); return; } fis-gtm-V6.0-003/sr_alpha/emit_code_sp.c0000644000032200000250000001433612201176175016742 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "cgp.h" #include "compiler.h" #include #include "list_file.h" #include GBLREF uint4 code_buf[]; /* Instruction buffer */ GBLREF int code_idx; /* Index into code_buf */ GBLREF char cg_phase; /* Current compiler phase */ GBLREF int4 curr_addr; #ifdef DEBUG GBLREF unsigned char *obpt; /* output buffer index */ GBLREF unsigned char outbuf[]; /* assembly language output buffer */ static unsigned int ains; /* assembler instruction (binary) */ #endif /* Used by emit_base_offset to extract offset parts */ int alpha_adjusted_upper(int offset) { int upper; upper = (offset >> 16) & 0xFFFF; if (offset & 0x8000) upper = (upper + 1) & 0xFFFF; return upper; } void emit_base_offset(int base, int offset) { /* NOTE: emit_base_offset does not advance past its last generated instruction because that instruction is incomplete; it contains only a base and offset -- the rt and opcode field are left empty for use by the caller. */ int upper, low, source; switch (cg_phase) { #ifdef DEBUG case CGP_ASSEMBLY: #endif case CGP_ADDR_OPT: case CGP_APPROX_ADDR: case CGP_MACHINE: assert(base >= 0 && base <= 31); source = base; upper = alpha_adjusted_upper(offset); if (0 != upper) { code_buf[code_idx++] = ALPHA_INS_LDAH | (GTM_REG_CODEGEN_TEMP << ALPHA_SHIFT_RA) | (source << ALPHA_SHIFT_RB) | (upper & ALPHA_MASK_DISP) << ALPHA_SHIFT_DISP; source = GTM_REG_CODEGEN_TEMP; } low = offset & 0xFFFF; code_buf[code_idx] = source << ALPHA_SHIFT_RB | (low & ALPHA_MASK_DISP) << ALPHA_SHIFT_DISP; break; default: GTMASSERT; } } #ifdef DEBUG void fmt_ra() { *obpt++ = 'r'; obpt = i2asc(obpt, GET_RA(ains)); } void fmt_ra_rb() { fmt_ra(); *obpt++ = ','; *obpt++; *obpt++ = 'r'; obpt = i2asc(obpt, GET_RB(ains)); } void fmt_ra_rb_rc() { fmt_ra_rb(); *obpt++ = ','; *obpt++; *obpt++ = 'r'; obpt = i2asc(obpt, GET_RC(ains)); } void fmt_ra_mem() { fmt_ra(); *obpt++ = ','; obpt++; *obpt++ = '0'; *obpt++ = 'x'; obpt += i2hex_nofill(GET_MEMDISP(ains), obpt, 6); *obpt++ = '('; *obpt++ = 'r'; obpt = i2asc(obpt, GET_RB(ains)); *obpt++ = ')'; } void fmt_ra_brdisp() { fmt_ra(); *obpt++ = ','; obpt++; *obpt++ = '0'; *obpt++ = 'x'; obpt += i2hex_nofill(GET_BRDISP(ains) * 4, obpt, 6); } void format_machine_inst(void) { int instindx; for (instindx = 0; instindx < code_idx; instindx++) { list_chkpage(); obpt = &outbuf[0]; memset(obpt, SP, ASM_OUT_BUFF); obpt += 10; i2hex((curr_addr - SIZEOF(rhdtyp)), (uchar_ptr_t)obpt, 8); curr_addr += 4; obpt += 10; i2hex(code_buf[instindx], (uchar_ptr_t)obpt, 8); obpt += 10; ains = code_buf[instindx]; switch(GET_OPCODE(ains)) { case 0x8: memcpy(obpt, LDA_INST, SIZEOF(LDA_INST) - 1); obpt += OPSPC; fmt_ra_mem(); break; case 0x9: memcpy(obpt, LDAH_INST, SIZEOF(LDAH_INST) - 1); obpt += OPSPC; fmt_ra_mem(); break; case 0x10: /* Note opcodes 0x10, 0x11, have overlapping functions but none that we generate so we can combine their disassembly. */ case 0x11: switch(GET_FUNC(ains)) { case 0x0: /* main opcode 0x10 */ memcpy(obpt, ADDL_INST, SIZEOF(ADDL_INST) - 1); break; case 0x9: /* main opcode 0x10 */ memcpy(obpt, SUBL_INST, SIZEOF(SUBL_INST) - 1); break; case 0x29: /* main opcode 0x10 */ memcpy(obpt, SUBQ_INST, SIZEOF(SUBQ_INST) - 1); break; case 0x20: /* main opcode 0x11 */ memcpy(obpt, BIS_INST, SIZEOF(BIS_INST) - 1); break; default: GTMASSERT; } obpt += OPSPC; fmt_ra_rb_rc(); break; case 0x1a: switch(GET_MEMDISP(ains) & 0x3) { case 0x0: memcpy(obpt, JMP_INST, SIZEOF(JMP_INST) - 1); break; case 0x1: memcpy(obpt, JSR_INST, SIZEOF(JSR_INST) - 1); break; case 0x2: memcpy(obpt, RET_INST, SIZEOF(RET_INST) - 1); break; default: GTMASSERT; } obpt += OPSPC; fmt_ra_rb(); break; case 0x28: memcpy(obpt, LDL_INST, SIZEOF(LDL_INST) - 1); obpt += OPSPC; fmt_ra_mem(); break; case 0x29: memcpy(obpt, LDQ_INST, SIZEOF(LDQ_INST) - 1); obpt += OPSPC; fmt_ra_mem(); break; case 0x2c: memcpy(obpt, STL_INST, SIZEOF(STL_INST) - 1); obpt += OPSPC; fmt_ra_mem(); break; case 0x2d: memcpy(obpt, STQ_INST, SIZEOF(STQ_INST) - 1); obpt += OPSPC; fmt_ra_mem(); break; case 0x30: memcpy(obpt, BR_INST, SIZEOF(BR_INST) - 1); obpt += OPSPC; fmt_ra_brdisp(); break; case 0x34: memcpy(obpt, BSR_INST, SIZEOF(BSR_INST) - 1); obpt += OPSPC; fmt_ra_brdisp(); break; case 0x38: memcpy(obpt, BLBC_INST, SIZEOF(BLBC_INST) - 1); obpt += OPSPC; fmt_ra_brdisp(); break; case 0x39: memcpy(obpt, BEQ_INST, SIZEOF(BEQ_INST) - 1); obpt += OPSPC; fmt_ra_brdisp(); break; case 0x3a: memcpy(obpt, BLT_INST, SIZEOF(BLT_INST) - 1); obpt += OPSPC; fmt_ra_brdisp(); break; case 0x3b: memcpy(obpt, BLE_INST, SIZEOF(BLE_INST) - 1); obpt += OPSPC; fmt_ra_brdisp(); break; case 0x3c: memcpy(obpt, BLBS_INST, SIZEOF(BLBS_INST) - 1); obpt += OPSPC; fmt_ra_brdisp(); break; case 0x3d: memcpy(obpt, BNE_INST, SIZEOF(BNE_INST) - 1); obpt += OPSPC; fmt_ra_brdisp(); break; case 0x3e: memcpy(obpt, BGE_INST, SIZEOF(BGE_INST) - 1); obpt += OPSPC; fmt_ra_brdisp(); break; case 0x3f: memcpy(obpt, BGT_INST, SIZEOF(BGT_INST) - 1); obpt += OPSPC; fmt_ra_brdisp(); break; default: /* Not an instruction but a constant */ memcpy(obpt, CONSTANT, SIZEOF(CONSTANT) - 1); obpt += SIZEOF(CONSTANT) - 1; i2hex(ains, obpt, 8); obpt += 8; } emit_eoi(); } } #endif fis-gtm-V6.0-003/sr_alpha/emit_code_sp.h0000644000032200000250000002427212201176170016742 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef EMIT_CODE_SP_INCLUDED #define EMIT_CODE_SP_INCLUDED #include "axp_registers.h" #include "axp_gtm_registers.h" #include "axp.h" void emit_base_offset(int base, int offset); int alpha_adjusted_upper(int offset); #ifdef DEBUG void format_machine_inst(void); void fmt_ra(void); void fmt_ra_rb(void); void fmt_ra_rb_rc(void); void fmt_ra_mem(void); void fmt_ra_brdisp(void); #endif #define INST_SIZE (int)SIZEOF(uint4) #define BRANCH_OFFSET_FROM_IDX(idx_start, idx_end) (idx_end - (idx_start + 1)) #define LONG_JUMP_OFFSET (0x4ffffffc) /* should be large enough to force the long jump instruction sequence */ #define MAX_BRANCH_CODEGEN_SIZE 32 /* The length in bytes, of the longest form of branch instruction sequence */ #define MAX_OFFSET 0x3fff #define STACK_ARG_OFFSET(indx) (8 * (indx)) /* All arguments on Alpha platforms are 8 bytes wide on stack */ #define MACHINE_FIRST_ARG_REG ALPHA_REG_A0 /* Register usage in some of the code generation expansions */ #define CALLS_TINT_TEMP_REG ALPHA_REG_R1 #define CLRL_REG ALPHA_REG_ZERO #define CMPL_TEMP_REG ALPHA_REG_T1 #define GET_ARG_REG(indx) (ALPHA_REG_A0 + (indx)) #define MOVC3_SRC_REG ALPHA_REG_R0 #define MOVC3_TRG_REG ALPHA_REG_R1 #define MOVL_RETVAL_REG ALPHA_REG_V0 #define MOVL_REG_R1 ALPHA_REG_R1 /* Macros to define the opcodes for use in emit_jmp() and emit_tip() args */ #define GENERIC_OPCODE_BEQ ((uint4)ALPHA_INS_BEQ) #define GENERIC_OPCODE_BGE ((uint4)ALPHA_INS_BGE) #define GENERIC_OPCODE_BGT ((uint4)ALPHA_INS_BGT) #define GENERIC_OPCODE_BLE ((uint4)ALPHA_INS_BLE) #define GENERIC_OPCODE_BLT ((uint4)ALPHA_INS_BLT) #define GENERIC_OPCODE_BNE ((uint4)ALPHA_INS_BNE) #define GENERIC_OPCODE_BLBC ((uint4)ALPHA_INS_BLBC) #define GENERIC_OPCODE_BLBS ((uint4)ALPHA_INS_BLBS) #define GENERIC_OPCODE_BR ((uint4)ALPHA_INS_BR) #define GENERIC_OPCODE_LDA ((uint4)ALPHA_INS_LDA) #define GENERIC_OPCODE_LOAD ((uint4)ALPHA_INS_LDL) #define GENERIC_OPCODE_STORE ((uint4)ALPHA_INS_STL) #define GENERIC_OPCODE_NOP ((uint4)ALPHA_INS_NOP) /* Macro to extract parts of generic opcodes */ #define GENXCT_LOAD_SRCREG(inst) ((inst >> ALPHA_SHIFT_RB) & ALPHA_MASK_REG) /* Macros to create specific generated code sequences */ /* Note that the GEN_CLEAR/SET_TRUTH macros are only used on VMS (TRUTH_IN_REG) */ #define GEN_CLEAR_TRUTH code_buf[code_idx++] = (ALPHA_INS_STL | ALPHA_REG_ZERO << ALPHA_SHIFT_RA \ | GTM_REG_DOLLAR_TRUTH << ALPHA_SHIFT_RB \ | 0 << ALPHA_SHIFT_DISP) #define GEN_SET_TRUTH { \ code_buf[code_idx++] = (ALPHA_INS_BIS | ALPHA_REG_ZERO << ALPHA_SHIFT_RA \ | 1 << ALPHA_SHIFT_LITERAL | ALPHA_BIT_LITERAL \ | GTM_REG_CODEGEN_TEMP << ALPHA_SHIFT_RC); \ code_buf[code_idx++] = (ALPHA_INS_STL | GTM_REG_CODEGEN_TEMP << ALPHA_SHIFT_RA \ | GTM_REG_DOLLAR_TRUTH << ALPHA_SHIFT_RB \ | 0 << ALPHA_SHIFT_DISP); \ } #define GEN_LOAD_ADDR(reg, breg, disp) code_buf[code_idx++] = (ALPHA_INS_LDA | reg << ALPHA_SHIFT_RA \ | breg << ALPHA_SHIFT_RB \ | (disp & ALPHA_MASK_DISP) << ALPHA_SHIFT_DISP) #define GEN_LOAD_WORD(reg, breg, disp) code_buf[code_idx++] = (ALPHA_INS_LDL | reg << ALPHA_SHIFT_RA \ | breg << ALPHA_SHIFT_RB \ | (disp & ALPHA_MASK_DISP) << ALPHA_SHIFT_DISP) #define GEN_STORE_WORD(reg, breg, disp) code_buf[code_idx++] = (ALPHA_INS_STL | reg << ALPHA_SHIFT_RA \ | breg << ALPHA_SHIFT_RB \ | (disp & ALPHA_MASK_DISP) << ALPHA_SHIFT_DISP) #define GEN_LOAD_IMMED(reg, disp) GEN_LOAD_ADDR(reg, ALPHA_REG_ZERO, disp) #define GEN_CLEAR_WORD_EMIT(reg) emit_trip(*(fst_opr + *inst++), TRUE, ALPHA_INS_STL, reg) #define GEN_LOAD_WORD_EMIT(reg) emit_trip(*(fst_opr + *inst++), TRUE, ALPHA_INS_LDL, reg) #define GEN_SUBTRACT_REGS(src1, src2, trgt) \ code_buf[code_idx++] = (ALPHA_INS_SUBL \ | src1 << ALPHA_SHIFT_RA \ | src2 << ALPHA_SHIFT_RB \ | trgt << ALPHA_SHIFT_RC) #define GEN_ADD_IMMED(reg, imval) code_buf[code_idx++] = (ALPHA_INS_ADDL \ | reg << ALPHA_SHIFT_RA \ | imval << ALPHA_SHIFT_LITERAL | ALPHA_BIT_LITERAL \ | reg << ALPHA_SHIFT_RC) #define GEN_JUMP_REG(reg) code_buf[code_idx++] = (ALPHA_INS_JMP | ALPHA_REG_ZERO << ALPHA_SHIFT_RA \ | reg << ALPHA_SHIFT_RB) #define GEN_STORE_ARG(reg, offset) code_buf[code_idx++] = (ALPHA_INS_STQ | reg << ALPHA_SHIFT_RA \ | ALPHA_REG_SP << ALPHA_SHIFT_RB \ | (offset & ALPHA_MASK_DISP) << ALPHA_SHIFT_DISP) #define GEN_PCREL code_buf[code_idx++] = (ALPHA_INS_LPC) #define GEN_MOVE_REG(trg, src) code_buf[code_idx++] = (ALPHA_INS_MOVE | src << ALPHA_SHIFT_RA | trg << ALPHA_SHIFT_RC) #if defined(__vms) /* CALL_INST_SIZE is the byte length of the minimum-length instruction sequence to implement a transfer * table call. In the case of OpenVMS AXP, this is the sequence: * * ldl r27, xfer(r11) ; get address of procedure descriptor from transfer table * ldq r26, 8(r27) ; get code address of procedure from procedure descriptor * jmp r26, (r26) ; call it * * This value is used to determine how to adjust the offset value for a relative call and may not * be appropriate for the Alpha because VAX relative calls are emulated on the Alpha differently. */ # define CALL_INST_SIZE (3 * INST_SIZE) # define GEN_XFER_TBL_CALL(xfer) \ { \ emit_base_offset(GTM_REG_XFER_TABLE, xfer); \ code_buf[code_idx++] |= ALPHA_INS_LDL | ALPHA_REG_PV << ALPHA_SHIFT_RA; \ emit_base_offset(ALPHA_REG_PV, 8); \ code_buf[code_idx++] |= ALPHA_INS_LDQ | ALPHA_REG_RA << ALPHA_SHIFT_RA; \ code_buf[code_idx++] = ALPHA_INS_JSR | ALPHA_REG_RA << ALPHA_SHIFT_RA | ALPHA_REG_RA << ALPHA_SHIFT_RB; \ } #elif defined(__osf__) /* CALL_INST_SIZE is the byte length of the minimum-length instruction sequence to implement a transfer * table call. In the case of OSF/1 (Digital Unix) AXP, this is the sequence: * * ldl r27, offset(r12) # get address of entry point from transfer table * jmp r26, (r27) # call it * * This value is used to determine how to adjust the offset value for a relative call and may not * be appropriate for the Alpha because VAX relative calls are emulated on the Alpha differently. */ # define CALL_INST_SIZE (2 * INST_SIZE) # define GEN_XFER_TBL_CALL(xfer) \ { \ emit_base_offset(GTM_REG_XFER_TABLE, xfer); \ code_buf[code_idx++] |= ALPHA_INS_LDL | ALPHA_REG_PV << ALPHA_SHIFT_RA; \ code_buf[code_idx++] = ALPHA_INS_JSR | ALPHA_REG_RA << ALPHA_SHIFT_RA | ALPHA_REG_PV << ALPHA_SHIFT_RB; \ } #else # error "Unsupported platform" #endif /* Macros to return an instruction value. This is typcically used to modify an instruction that is already in the instruction buffer such as the last instruction that was created by emit_pcrel(). */ #define IGEN_COND_BRANCH_REG_OFFSET(opcode, reg, disp) (opcode | ((reg & ALPHA_MASK_REG) << ALPHA_SHIFT_RA) \ | ((disp & ALPHA_MASK_DISP) << ALPHA_SHIFT_BRANCH_DISP)) #define IGEN_UCOND_BRANCH_REG_OFFSET(opcode, reg, disp) IGEN_COND_BRANCH_REG_OFFSET(opcode, reg, disp) #define IGEN_LOAD_ADDR_REG(reg) (ALPHA_INS_LDA | (reg & ALPHA_MASK_REG) << ALPHA_SHIFT_RA) #define IGEN_LOAD_WORD_REG(reg) (ALPHA_INS_LDL | (reg & ALPHA_MASK_REG) << ALPHA_SHIFT_RA) #define IGEN_LOAD_NATIVE_REG(reg) IGEN_LOAD_WORD_REG(reg) #define IGEN_COND_BRANCH_OFFSET(disp) ((disp & ALPHA_MASK_BRANCH_DISP) << ALPHA_SHIFT_BRANCH_DISP) #define IGEN_UCOND_BRANCH_OFFSET(disp) IGEN_COND_BRANCH_OFFSET(disp) #define IGEN_LOAD_LINKAGE(reg) (ALPHA_INS_LDQ | (reg & ALPHA_MASK_REG) << ALPHA_SHIFT_RA) #define IGEN_GENERIC_REG(opcode, reg) (opcode | ((reg & ALPHA_MASK_REG) << ALPHA_SHIFT_RA)) /* Some macros that are used in certain routines in emit_code.c. The names of these macros start with the routine name they are used in. */ /* Branch has origin of +1 instructions. However, if the branch was nullified in an earlier shrink_trips, * the origin is the current instruction itself */ #define EMIT_JMP_ADJUST_BRANCH_OFFSET branch_offset = ((branch_offset != 0) ? branch_offset - 1 : 0) /* Can jump be done within range of immediate operand */ #define EMIT_JMP_SHORT_CODE_CHECK (branch_offset >= (-(ALPHA_MASK_BRANCH_DISP/2) - 1) \ && branch_offset <= (ALPHA_MASK_BRANCH_DISP/2)) /* Emit the short jump */ #define EMIT_JMP_SHORT_CODE_GEN \ { \ code_buf[code_idx++] = (branchop | (reg << ALPHA_SHIFT_RA) \ | ((branch_offset & ALPHA_MASK_BRANCH_DISP) << ALPHA_SHIFT_BRANCH_DISP)); \ branch_offset--; \ } /* Is this a conditional branch? */ #define EMIT_JMP_OPPOSITE_BR_CHECK (branchop != ALPHA_INS_BR && (branchop != ALPHA_INS_BEQ || reg != ALPHA_REG_ZERO)) #define EMIT_JMP_GEN_COMPARE /* No compare necessary */ #define EMIT_JMP_LONG_CODE_CHECK FALSE /* Is the offset field in this instruction zero? */ #define EMIT_JMP_ZERO_DISP_COND (0 == ((code_buf[code_idx] >> ALPHA_SHIFT_DISP) & ALPHA_MASK_DISP)) /* Emit code to load a given numeric literal */ #define EMIT_TRIP_ILIT_GEN { /* Emit liternal number */ \ emit_base_offset(ALPHA_REG_ZERO, immediate); \ code_buf[code_idx++] |= (ALPHA_INS_LDA | \ (trg_reg & ALPHA_MASK_REG) << ALPHA_SHIFT_RA); \ } /* * GT.M on AIX and SPARC is 64bit * By default the loads/stores use ldd/std(load double), * but if the value being dealt with is a word,the * opcode in generic_inst is changed to ldw/stw */ #define REVERT_GENERICINST_TO_WORD(inst) #endif fis-gtm-V6.0-003/sr_alpha/follow.m640000644000032200000250000000223512201176170015764 0ustar librarygtc; ################################################################ ; # # ; # Copyright 2001, 2008 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ################################################################ .title FOLLOW "Allows run-time modules to call OP_FOLLOW" ; FOLLOW simply passes its two arguments, which are pointers to ; mval's, to OP_FOLLOW, which expects them in registers r0 and r1. ; OP_FOLLOW returns 1, 0, or -1; FOLLOW returns a boolean result: ; 1 (true) if OP_FOLLOW returned 1, otherwise 0 (false). $routine FOLLOW, entry=FOLLOW_CA, kind=stack .base r27, $ls sextl r16, r0 sextl r17, r1 $call OP_FOLLOW, set_arg_info=false sextl r0, r0 cmovlt r0, 0, r0 $return $end_routine .end fis-gtm-V6.0-003/sr_alpha/gtm_dump.c0000644000032200000250000000102112201176170016102 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /*** STUB FILE ***/ #include "mdef.h" #include "error.h" void gtm_dump(void) {}; fis-gtm-V6.0-003/sr_alpha/inst_flush.m640000644000032200000250000000162612201176170016643 0ustar librarygtc; ################################################################ ; # # ; # Copyright 2001, 2008 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ################################################################ .title inst_flush flush instruction cache ; inst_flush is a C-callable routine that makes the instruction cache coherent with memory. $routine name=inst_flush,entry=inst_flush_ca,kind=null imb ret r26 $end_routine name=inst_flush .end fis-gtm-V6.0-003/sr_alpha/mint2mval.m640000644000032200000250000000207412201176170016374 0ustar librarygtc .title mint2mval "Convert integer to mval" ; ############################################################### ; # # ; # Copyright 2001, 2004 Sanchez Computer Associates, Inc. # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ############################################################### ; On input, r1 = integer value, r0 -> mval mval$def $linkage_section int_hi_val: .quad INT_HI $routine MINT2MVAL, entry=MINT2MVAL_CA, kind=null lda sp, -24(sp) stq r26, (sp) stq r13, 8(sp) mov r27, r13 .base r13, $ls ldq r22, int_hi_val cmplt r1, r22, r28 beq r28, 11$ ; int >= INT_HI negq r22, r22 cmple r1, r22, r28 bne r28, 11$ ; int <= -INT_HI mv_i2mval r1, r0 12$: ldq r26, (sp) ldq r13, 8(sp) lda sp, 24(sp) ret r26 11$: mov r0, r16 mov r1, r17 $call I2MVAL, args=, set_arg_info=false, nonstandard=true br 12$ $end_routine .end fis-gtm-V6.0-003/sr_alpha/movq.m640000644000032200000250000000145312201176170015445 0ustar librarygtc; ################################################################ ; # # ; # Copyright 2001, 2008 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ################################################################ .title movq move quadword $routine name=movq,entry=movq_ca,kind=null ldq r28, (r16) stq r28, (r17) ret r26 $end_routine name=movq fis-gtm-V6.0-003/sr_alpha/mval2bool.m640000644000032200000250000000211612201176170016355 0ustar librarygtc; ################################################################ ; # # ; # Copyright 2000, 2008 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ################################################################ .title mval2bool "Sets condition code from mval" ; On entry, r1 -> mval. ; On exit, r24 = numeric value of mval mval$def $routine MVAL2BOOL, entry=MVAL2BOOL_CA, kind=null lda sp, -24(sp) stq r26, (sp) stq r13, 8(sp) mov r27, r13 .base r13, $ls mv_force_defined r1 stq r1, 16(sp) mv_force_num (r1) ldq r1, 16(sp) ldl r24, mval$l_m1(r1) ldq r26, (sp) ldq r13, 8(sp) lda sp, 24(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_alpha/mval2mint.m640000644000032200000250000000215312201176170016372 0ustar librarygtc; ################################################################ ; # # ; # Copyright 2000, 2008 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ################################################################ .title mval2mint "Converts an mval to integer" ; On entry, r1 -> mval ; On exit, r0 = integer value mval$def $routine MVAL2MINT, entry=MVAL2MINT_CA, kind=null lda sp, -24(sp) stq r26, (sp) stq r13, 8(sp) mov r27, r13 .base r13, $ls mv_force_defined r1 stq r1, 16(sp) mv_force_num (r1) ldq r16, 16(sp) $call MVAL2I, args=, set_arg_info=false, nonstandard=true ldq r26, (sp) ldq r13, 8(sp) lda sp, 24(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_alpha/objlangdefs.h0000644000032200000250000002575112201176170016571 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* Object record types: */ #define EOBJ$C_EMH 8 #define EOBJ$C_EEOM 9 #define EOBJ$C_EGSD 10 #define EOBJ$C_ETIR 11 #define EOBJ$C_EDBG 12 #define EOBJ$C_ETBT 13 #define EOBJ$C_MAXRECTYP 13 /* Byte offsets into object record and related constants: */ #define EOBJ$K_SUBTYP 4 #define EOBJ$C_SUBTYP 4 #define EOBJ$C_MAXRECSIZ 8192 #define EOBJ$C_STRLVL 2 #define EOBJ$C_SYMSIZ 31 #define EOBJ$C_STOREPLIM -1 #define EOBJ$C_PSCALILIM 16 #define EOBJ$S_EOBJRECDEF 10 #define EOBJ$W_RECTYP 0 #define EOBJ$W_SIZE 2 #define EOBJ$W_SUBTYP 4 #define EOBJ$B_MHD_STRLV 6 #define EOBJ$B_MHD_HOLD 7 #define EOBJ$W_MHD_RECSZ 8 #define EOBJ$T_MHD_NAME 10 /* Object header record (EOBJ$C_EMH) subtypes: */ #define EMH$C_MHD 0 #define EMH$C_LNM 1 #define EMH$C_SRC 2 #define EMH$C_TTL 3 #define EMH$C_CPR 4 #define EMH$C_MTC 5 #define EMH$C_GTX 6 #define EMH$C_MAXHDRTYP 6 /* Byte offsets of fields in object header record (EOBJ$C_EMH): */ #define EMH$S_EMHDEF 52 #define EMH$W_RECTYP 0 #define EMH$W_SIZE 2 #define EMH$W_HDRTYP 4 #define EMH$B_STRLVL 6 #define EMH$B_TEMP 7 #define EMH$L_ARCH1 8 #define EMH$L_ARCH2 12 #define EMH$L_RECSIZ 16 #define EMH$B_NAMLNG 20 #define EMH$S_NAME 31 #define EMH$T_NAME 21 #define EEOM$C_SUCCESS 0 #define EEOM$C_WARNING 1 #define EEOM$C_ERROR 2 #define EEOM$C_ABORT 3 #define EEOM$K_EOMMIN 10 #define EEOM$C_EOMMIN 10 #define EEOM$K_EOMMX1 10 #define EEOM$C_EOMMX1 10 #define EEOM$M_WKTFR 0X1 #define EEOM$K_EOMMAX 24 #define EEOM$C_EOMMAX 24 #define EEOM$S_EEOMDEF 24 #define EEOM$W_RECTYP 0 #define EEOM$W_SIZE 2 #define EEOM$L_TOTAL_LPS 4 #define EEOM$W_COMCOD 8 #define EEOM$B_TFRFLG 10 #define EEOM$V_WKTFR 0 #define EEOM$B_TEMP 11 #define EEOM$L_PSINDX 12 #define EEOM$S_TFRADR 8 #define EEOM$Q_TFRADR 16 #define EEOM$L_TFRADR 16 #define EGSD$K_ENTRIES 2 #define EGSD$C_ENTRIES 2 #define EGSD$C_PSC 0 #define EGSD$C_SYM 1 #define EGSD$C_IDC 2 #define EGSD$C_ENV 3 #define EGSD$C_LSY 4 #define EGSD$C_SPSC 5 #define EGSD$C_SYMV 6 #define EGSD$C_SYMM 7 #define EGSD$C_SYMG 8 #define EGSD$C_MAXRECTYP 8 #define EGSD$S_EGSDEF 12 #define EGSD$W_RECTYP 0 #define EGSD$W_RECSIZ 2 #define EGSD$L_ALIGNLW 4 #define EGSD$W_GSDTYP 8 #define EGSD$W_GSDSIZ 10 #define EGPS$M_PIC 0X1 #define EGPS$M_LIB 0X2 #define EGPS$M_OVR 0X4 #define EGPS$M_REL 0X8 #define EGPS$M_GBL 0X10 #define EGPS$M_SHR 0X20 #define EGPS$M_EXE 0X40 #define EGPS$M_RD 0X80 #define EGPS$M_WRT 0X100 #define EGPS$M_VEC 0X200 #define EGPS$M_NOMOD 0X400 #define EGPS$M_COM 0X800 #define EGPS$K_NAME 12 #define EGPS$C_NAME 12 #define EGPS$S_EGPSDEF 44 #define EGPS$W_GSDTYP 0 #define EGPS$T_START 0 #define EGPS$W_SIZE 2 #define EGPS$B_ALIGN 4 #define EGPS$B_TEMP 5 #define EGPS$W_FLAGS 6 #define EGPS$V_PIC 0 #define EGPS$V_LIB 1 #define EGPS$V_OVR 2 #define EGPS$V_REL 3 #define EGPS$V_GBL 4 #define EGPS$V_SHR 5 #define EGPS$V_EXE 6 #define EGPS$V_RD 7 #define EGPS$V_WRT 8 #define EGPS$V_VEC 9 #define EGPS$V_NOMOD 10 #define EGPS$V_COM 11 #define EGPS$L_ALLOC 8 #define EGPS$B_NAMLNG 12 #define EGPS$S_NAME 31 #define EGPS$T_NAME 13 #define ESGPS$M_PIC 0X1 #define ESGPS$M_LIB 0X2 #define ESGPS$M_OVR 0X4 #define ESGPS$M_REL 0X8 #define ESGPS$M_GBL 0X10 #define ESGPS$M_SHR 0X20 #define ESGPS$M_EXE 0X40 #define ESGPS$M_RD 0X80 #define ESGPS$M_WRT 0X100 #define ESGPS$M_VEC 0X200 #define ESGPS$M_NOMOD 0X400 #define ESGPS$M_COM 0X800 #define ESGPS$K_NAME 25 #define ESGPS$C_NAME 25 #define ESGPS$S_ESGPSDEF 56 #define ESGPS$W_GSDTYP 0 #define ESGPS$T_START 0 #define ESGPS$W_SIZE 2 #define ESGPS$B_ALIGN 4 #define ESGPS$B_TEMP 5 #define ESGPS$W_FLAGS 6 #define ESGPS$V_PIC 0 #define ESGPS$V_LIB 1 #define ESGPS$V_OVR 2 #define ESGPS$V_REL 3 #define ESGPS$V_GBL 4 #define ESGPS$V_SHR 5 #define ESGPS$V_EXE 6 #define ESGPS$V_RD 7 #define ESGPS$V_WRT 8 #define ESGPS$V_VEC 9 #define ESGPS$V_NOMOD 10 #define ESGPS$V_COM 11 #define ESGPS$L_ALLOC 8 #define ESGPS$L_BASE 12 #define ESGPS$S_VALUE 8 #define ESGPS$Q_VALUE 16 #define ESGPS$L_VALUE 16 #define ESGPS$B_NAMLNG 24 #define ESGPS$S_NAME 31 #define ESGPS$T_NAME 25 #define EGSY$M_WEAK 0X1 #define EGSY$M_DEF 0X2 #define EGSY$M_UNI 0X4 #define EGSY$M_REL 0X8 #define EGSY$M_COMM 0X10 #define EGSY$M_VECEP 0X20 #define EGSY$M_NORM 0X40 #define EGSY$S_EGSYDEF 8 #define EGSY$W_GSDTYP 0 #define EGSY$T_START 0 #define EGSY$W_SIZE 2 #define EGSY$B_DATYP 4 #define EGSY$B_TEMP 5 #define EGSY$W_FLAGS 6 #define EGSY$V_WEAK 0 #define EGSY$V_DEF 1 #define EGSY$V_UNI 2 #define EGSY$V_REL 3 #define EGSY$V_COMM 4 #define EGSY$V_VECEP 5 #define EGSY$V_NORM 6 #define EGST$K_NAME 37 #define EGST$C_NAME 37 #define EGST$S_EGSTDEF 68 #define EGST$W_GSDTYP 0 #define EGST$T_START 0 #define EGST$W_SIZE 2 #define EGST$B_DATYP 4 #define EGST$B_TEMP 5 #define EGST$W_FLAGS 6 #define EGST$S_VALUE 8 #define EGST$Q_VALUE 8 #define EGST$L_VALUE 8 #define EGST$S_LP_1 8 #define EGST$Q_LP_1 16 #define EGST$L_LP_1 16 #define EGST$S_LP_2 8 #define EGST$Q_LP_2 24 #define EGST$L_LP_2 24 #define EGST$L_PSINDX 32 #define EGST$B_NAMLNG 36 #define EGST$S_NAME 31 #define EGST$T_NAME 37 #define ESDF$K_NAME 33 #define ESDF$C_NAME 33 #define ESDF$S_ESDFDEF 64 #define ESDF$W_GSDTYP 0 #define ESDF$T_START 0 #define ESDF$W_SIZE 2 #define ESDF$B_DATYP 4 #define ESDF$B_TEMP 5 #define ESDF$W_FLAGS 6 #define ESDF$S_VALUE 8 #define ESDF$Q_VALUE 8 #define ESDF$L_VALUE 8 #define ESDF$S_CODE_ADDRESS 8 #define ESDF$Q_CODE_ADDRESS 16 #define ESDF$L_CODE_ADDRESS 16 #define ESDF$L_CA_PSINDX 24 #define ESDF$L_PSINDX 28 #define ESDF$B_NAMLNG 32 #define ESDF$S_NAME 31 #define ESDF$T_NAME 33 #define ESDFV$K_NAME 25 #define ESDFV$C_NAME 25 #define ESDFV$S_ESDFVDEF 56 #define ESDFV$W_GSDTYP 0 #define ESDFV$T_START 0 #define ESDFV$W_SIZE 2 #define ESDFV$B_DATYP 4 #define ESDFV$B_TEMP 5 #define ESDFV$W_FLAGS 6 #define ESDFV$S_VALUE 8 #define ESDFV$Q_VALUE 8 #define ESDFV$L_VALUE 8 #define ESDFV$L_PSINDX 16 #define ESDFV$L_VECTOR 20 #define ESDFV$B_NAMLNG 24 #define ESDFV$S_NAME 31 #define ESDFV$T_NAME 25 #define ESDFM$K_NAME 25 #define ESDFM$C_NAME 25 #define ESDFM$S_ESDFMDEF 56 #define ESDFM$W_GSDTYP 0 #define ESDFM$T_START 0 #define ESDFM$W_SIZE 2 #define ESDFM$B_DATYP 4 #define ESDFM$B_TEMP 5 #define ESDFM$W_FLAGS 6 #define ESDFM$S_VALUE 8 #define ESDFM$Q_VALUE 8 #define ESDFM$L_VALUE 8 #define ESDFM$L_PSINDX 16 #define ESDFM$L_VERSION_MASK 20 #define ESDFM$B_NAMLNG 24 #define ESDFM$S_NAME 31 #define ESDFM$T_NAME 25 #define ESRF$K_NAME 9 #define ESRF$C_NAME 9 #define ESRF$S_ESRFDEF 40 #define ESRF$W_GSDTYP 0 #define ESRF$T_START 0 #define ESRF$W_SIZE 2 #define ESRF$B_DATYP 4 #define ESRF$B_TEMP 5 #define ESRF$W_FLAGS 6 #define ESRF$B_NAMLNG 8 #define ESRF$S_NAME 31 #define ESRF$T_NAME 9 #define EIDC$C_LEQ 0 #define EIDC$C_EQUAL 1 #define EIDC$S_EIDCDEF 7 #define EIDC$W_GSDTYP 0 #define EIDC$W_SIZE 2 #define EIDC$B_NAMLNG 4 #define EIDC$T_NAME 5 #define EIDC$W_FLAGS 5 #define EIDC$V_BINIDENT 0 #define EIDC$S_IDMATCH 2 #define EIDC$V_IDMATCH 1 #define EIDC$S_ERRSEV 3 #define EIDC$V_ERRSEV 3 #define EENV$M_DEF 0X1 #define EENV$M_NESTED 0X2 #define EENV$S_EENVDEF 40 #define EENV$W_GSDTYP 0 #define EENV$W_SIZE 2 #define EENV$W_FLAGS 4 #define EENV$V_DEF 0 #define EENV$V_NESTED 1 #define EENV$W_ENVINDX 6 #define EENV$B_NAMLNG 8 #define EENV$S_NAME 31 #define EENV$T_NAME 9 #define ELSY$M_WEAK 0X1 #define ELSY$M_DEF 0X2 #define ELSY$M_UNI 0X4 #define ELSY$M_REL 0X8 #define ELSY$S_ELSYDEF 14 #define ELSY$W_GSDTYP 0 #define ELSY$T_START 0 #define ELSY$W_SIZE 2 #define ELSY$B_DATYP 4 #define ELSY$B_TEMP1 5 #define ELSY$W_FLAGS 6 #define ELSY$V_WEAK 0 #define ELSY$V_DEF 1 #define ELSY$V_UNI 2 #define ELSY$V_REL 3 #define ELSY$L_PSINDX 8 #define ELSY$W_ENVINDX 12 #define ELSRF$K_NAME 17 #define ELSRF$C_NAME 17 #define ELSRF$S_ELSRFDEF 48 #define ELSRF$W_GSDTYP 0 #define ELSRF$T_START 0 #define ELSRF$W_SIZE 2 #define ELSRF$B_DATYP 4 #define ELSRF$B_TEMP1 5 #define ELSRF$W_FLAGS 6 #define ELSRF$L_PSINDX 8 #define ELSRF$W_ENVINDX 12 #define ELSRF$W_TEMP2 14 #define ELSRF$B_NAMLNG 16 #define ELSRF$S_NAME 31 #define ELSRF$T_NAME 17 #define ELSDF$K_NAME 25 #define ELSDF$C_NAME 25 #define ELSDF$S_ELSDFDEF 56 #define ELSDF$W_GSDTYP 0 #define ELSDF$T_START 0 #define ELSDF$W_SIZE 2 #define ELSDF$B_DATYP 4 #define ELSDF$B_TEMP1 5 #define ELSDF$W_FLAGS 6 #define ELSDF$S_VALUE 8 #define ELSDF$Q_VALUE 8 #define ELSDF$L_VALUE 8 #define ELSDF$L_PSINDX 16 #define ELSDF$W_ENVINDX 20 #define ELSDF$W_TEMP2 22 #define ELSDF$B_NAMLNG 24 #define ELSDF$S_NAME 31 #define ELSDF$T_NAME 25 /* ETIR command types: */ /* ETIR stack commands: */ #define ETIR$C_MINSTACOD 0 #define ETIR$C_STA_GBL 0 #define ETIR$C_STA_LW 1 #define ETIR$C_STA_QW 2 #define ETIR$C_STA_PQ 3 #define ETIR$C_STA_LI 4 #define ETIR$C_STA_MOD 5 #define ETIR$C_STA_CKARG 6 #define ETIR$C_MAXSTACOD 6 #define ETIR$C_MINSTOCOD 50 #define ETIR$C_STO_B 50 #define ETIR$C_STO_W 51 #define ETIR$C_STO_LW 52 #define ETIR$C_STO_QW 53 #define ETIR$C_STO_IMMR 54 #define ETIR$C_STO_GBL 55 #define ETIR$C_STO_CA 56 #define ETIR$C_STO_RB 57 #define ETIR$C_STO_AB 58 #define ETIR$C_STO_OFF 59 #define ETIR$C_STO_IMM 61 #define ETIR$C_STO_GBL_LW 62 #define ETIR$C_STO_HINT_GBL 64 #define ETIR$C_STO_HINT_PS 65 #define ETIR$C_MAXSTOCOD 65 #define ETIR$C_MINOPRCOD 100 #define ETIR$C_OPR_NOP 100 #define ETIR$C_OPR_ADD 101 #define ETIR$C_OPR_SUB 102 #define ETIR$C_OPR_MUL 103 #define ETIR$C_OPR_DIV 104 #define ETIR$C_OPR_AND 105 #define ETIR$C_OPR_IOR 106 #define ETIR$C_OPR_EOR 107 #define ETIR$C_OPR_NEG 108 #define ETIR$C_OPR_COM 109 #define ETIR$C_OPR_INSV 110 #define ETIR$C_OPR_ASH 111 #define ETIR$C_OPR_USH 112 #define ETIR$C_OPR_ROT 113 #define ETIR$C_OPR_SEL 114 #define ETIR$C_OPR_REDEF 115 #define ETIR$C_OPR_DFLIT 116 #define ETIR$C_MAXOPRCOD 116 #define ETIR$C_MINCTLCOD 150 #define ETIR$C_CTL_SETRB 150 #define ETIR$C_CTL_AUGRB 151 #define ETIR$C_CTL_DFLOC 152 #define ETIR$C_CTL_STLOC 153 #define ETIR$C_CTL_STKDL 154 #define ETIR$C_MAXCTLCOD 154 #define ETIR$C_MINSTCCOD 200 #define ETIR$C_STC_LP 200 #define ETIR$C_STC_LP_PSB 201 #define ETIR$C_STC_GBL 202 #define ETIR$C_STC_GCA 203 #define ETIR$C_STC_PS 204 #define ETIR$C_STC_NOP_GBL 205 #define ETIR$C_STC_NOP_PS 206 #define ETIR$C_STC_BSR_GBL 207 #define ETIR$C_STC_BSR_PS 208 #define ETIR$C_STC_LDA_GBL 209 #define ETIR$C_STC_LDA_PS 210 #define ETIR$C_STC_BOH_GBL 211 #define ETIR$C_STC_BOH_PS 212 #define ETIR$C_STC_NBH_GBL 213 #define ETIR$C_STC_NBH_PS 214 #define ETIR$C_MAXSTCCOD 214 #define ETIR$S_ETIRDEF 4 #define ETIR$W_RECTYP 0 #define ETIR$W_SIZE 2 fis-gtm-V6.0-003/sr_alpha/op_call.m640000644000032200000250000000216712201176170016077 0ustar librarygtc .title OP_CALL ; ############################################################### ; # # ; # Copyright 2001, 2003 Sanchez Computer Associates, Inc. # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ############################################################### G_MSF $linkage_section a_frame_pointer: .address frame_pointer $code_section $routine OP_CALLB, entry=OP_CALL_CA, aliases=, kind=null lda sp, -16(sp) stq r13, 8(sp) stq r26, (sp) mov r27, r13 .base r13, $ls ldq r1, a_frame_pointer ldl r1, (r1) ; Bump the return PC past the branch sequence following the jsr that got us here: addl r26, r16, r26 ; length of branch sequence stl r26, msf$mpc_off(r1) ; and store it in the Mumps stack frame $call COPY_STACK_FRAME, set_arg_info=false, nonstandard=true ldq r12, a_frame_pointer ldl r12, (r12) ldq r26, (sp) ldq r13, 8(sp) lda sp, 16(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_alpha/op_equnul.m640000644000032200000250000000303212201176170016465 0ustar librarygtc; ################################################################ ; # # ; # Copyright 2001, 2008 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ################################################################ .title OP_EQUNUL "Compare mval to null string" mval$def $linkage_section a_undef_inhibit: .address undef_inhibit $code_section $routine OP_EQUNUL, entry=OP_EQUNUL_CA, kind=null .base r27, $ls mv_if_notdefined (r0), 30$ mv_if_notstring (r0), 20$ ldl r28, mval$l_strlen(r0) bne r28, 20$ ; Mval is a null string 10$: mov 1, r24 ret r26 ; Mval is not a null string 20$: clr r24 ret r26 ; If undef_inhibit is set, then all undefined values are equal to the null string: 30$: ldq r28, a_undef_inhibit ldq_u r24, (r28) extbl r24, r28, r24 bne r24, 10$ ; it's set; treat mval as a null string ; It's not set, so issue a message: lda sp, -8(sp) ; but first, stq r26, (sp) ; save the return address mov r0, r16 $call UNDERR, args=, set_arg_info=false, nonstandard=true ldq r26, (sp) ; restore our return address lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_alpha/op_forlcldo.m640000644000032200000250000000224712201176170016767 0ustar librarygtc .title OP_FORLCLDO ; ############################################################### ; # # ; # Copyright 2001, 2003 Sanchez Computer Associates, Inc. # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ############################################################### G_MSF $linkage_section a_frame_pointer: .address frame_pointer $code_section $routine OP_FORLCLDOB, entry=OP_FORLCLDO_CA, aliases=, kind=null lda sp, -16(sp) stq r13, 8(sp) stq r26, (sp) mov r27, r13 .base r13, $ls ldq r1, a_frame_pointer ldl r1, (r1) ; Bump the return PC past the branch instruction following the jsr that got us here: addl r26, r16, r26 ; length of branch sequence stl r26, msf$mpc_off(r1) ; and store it in the Mumps stack frame $call EXFUN_FRAME, set_arg_info=false, nonstandard=true ldq r12, a_frame_pointer ldl r12, (r12) ldl r9, msf$temps_ptr_off(r12) ldq r26, (sp) ldq r13, 8(sp) lda sp, 16(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_alpha/op_linestart.m640000644000032200000250000000163712201176170017172 0ustar librarygtc; ################################################################ ; # # ; # Copyright 2001, 2008 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ################################################################ .title op_linestart G_MSF ; op_linestart - establish start of line in GT.M MUMPS stack frame $routine name=op_linestart,entry=op_linestart_ca,kind=null stl r26, msf$mpc_off(r12) stl r13, msf$ctxt_off(r12) ret r26 $end_routine name=op_linestart fis-gtm-V6.0-003/sr_alpha/op_pattern.m640000644000032200000250000000312112201176170016630 0ustar librarygtc; ################################################################ ; # # ; # Copyright 2001, 2008 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ################################################################ .title OP_PATTERN mval$def $routine OP_PATTERN, entry=OP_PATTERN_CA, kind=null lda sp, -16(sp) stq r13, 8(sp) stq r26, (sp) mov r27, r13 .base r13, $ls mov r0, r16 mov r1, r17 ; ; This is an array of unaligned ints. If the first word is zero, then call do_pattern ; instead of do_patfixed. Only the low order byte is significant and so it is the only ; one we need to test. We would do this in assembly because (1) we need the assmembly ; routine anyway to save the return value into $TEST and (2) it saves an extra level of ; call linkage at the C level to do the decision here. ; ldl r28, mval$a_straddr(r1) ldq_u r24, (r28) extbl r24, r28, r24 beq r24, 20$ 10$: $call DO_PATFIXED, args=, set_arg_info=false, nonstandard=true 15$: mov r0, r24 ldq r26, (sp) ldq r13, 8(sp) lda sp, 16(sp) ret r26 20$: $call DO_PATTERN, args=, set_arg_info=false, nonstandard=true br 15$ $end_routine .end fis-gtm-V6.0-003/sr_alpha/op_sorts_after.m640000644000032200000250000000227712201176170017521 0ustar librarygtc; ################################################################ ; # # ; # Copyright 2001, 2008 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ################################################################ .title OP_SORTS_AFTER ; On entry: ; r0 -> mval for left hand side ; r1 -> mval for right hand side ; ; On exit: ; r24 < 0 : lhs ']] rhs (lhs ]] rhs is false) ; r24 = 0 : lhs = rhs (lhs ]] rhs is false) ; r24 > 0 : lhs ]] rhs (lhs ]] rhs is true) $routine OP_SORTS_AFTER, entry=OP_SORTS_AFTER_CA, kind=null lda sp, -8(sp) stq r26, (sp) .base r27, $ls mov r0, r16 mov r1, r17 $call SORTS_AFTER, args=, set_arg_info=false, nonstandard=true mov r0, r24 ldq r26, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_alpha/pseudo_ret.m640000644000032200000250000000256012201176170016634 0ustar librarygtc; ################################################################ ; # # ; # Copyright 2001, 2008 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ################################################################ .title PSEUDO_RET ; PSEUDO_RET calls opp_ret (which doesn't return). It executes in a ; GT.M MUMPS stack frame and is, in fact, normally entered via a ; getframe/ret instruction sequence. ; ; entry: ; r13 - address of PSEUDO_RET's procedure descriptor (not r27) ; ; WARNING: because PSEUDO_RET is designed to be invoked from a GT.M ; MUMPS stack frame, it does not conform to the Alpha calling ; standard and cannot be invoked from any high-level language. The ; invoker should load the address of PSEUDO_RET's procedure descriptor ; into r13, not r27. $code_section $routine PSEUDO_RET, entry=PSEUDO_RET_CA, kind=null .base r13, $ls $call opp_ret, set_arg_info=false, nonstandard=true $end_routine .end fis-gtm-V6.0-003/sr_alpha/zbreaksp.h0000644000032200000250000000243112201176170016122 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ typedef unsigned short zb_code; #define ZB_CODE_MASK 0xffff #define INST_TYPE zb_code /* The ZBreak command operates by finding the generated code for the op_linestart or op_linefetch for the source * line in question and changing the offset in the transfer table load address instruction from the op_linestart or * op_linefetch offset to the appropriate zbreak functionality opcode offset. * In some platforms(IA64 and ZOS) since the INSTRUCTION LAYOUT is complex we need following * macros for instruction manipulation. * EXTRACT_OFFSET_TO_M_OPCODE * FIX_OFFSET_WITH_ZBREAK_OFFSET * EXTRACT_AND_UPDATE_INST * These macros are called only when COMPLEX_INSTRUCTION_UPDATE is defined * If COMPLEX_INSTRUCTION_UPDATE is not defined portable code in the caller of these macros * is invoked. */ #undef COMPLEX_INSTRUCTION_UPDATE fis-gtm-V6.0-003/sr_avms/0000755000032200000250000000000012201176175014016 5ustar librarygtcfis-gtm-V6.0-003/sr_avms/adawi.c0000644000032200000250000000147112201176167015253 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include /* __ADAWI on Alpha returns a simulated VAX PSL, NOT a value representing a condition code (-1, 0, or +1). adawi is defined here as a static routine to convert the PSL to an appropriate value. */ int adawi(short x, short *y) { int vax_psl = __ADAWI(x, y); if (vax_psl & 4 /* Z bit */) return 0; if (vax_psl & 8 /* N bit */) return -1; return 1; } fis-gtm-V6.0-003/sr_avms/aswp.m640000644000032200000250000000074612201176167015330 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2005 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GTMSHR_ASWP = 1 .INCLUDE "gtm$src:aswp_src.h" fis-gtm-V6.0-003/sr_avms/aswp_secshr.m640000644000032200000250000000075112201176167016673 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2005 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GTMSECSHR_ASWP = 1 .INCLUDE "gtm$src:aswp_src.h" fis-gtm-V6.0-003/sr_avms/aswp_src.h0000644000032200000250000000363612201176167016021 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2005 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Atomic swap operation ; int aswp(int *loc, int value) ; ; set *loc to value and return the old value of *loc, ; in the equivalent of one atomic operation. ; .IF DEFINED GTMSHR_ASWP .title ASWP $routine ASWP, entry=ASWP_CA, kind=null .ELSE .IF DEFINED GTMSECSHR_ASWP .title ASWP_SECSHR $routine ASWP_SECSHR, entry=ASWP_SECSHR_CA, kind=null .ELSE .ERROR "Unsupported Image" .ENDC .ENDC RETRY_COUNT = 1024 ; of times to attempt swap before sleeping SLEEP_TIME = 500 ; 1/2 ms stack_size = 32 lda sp, -stack_size(sp) stq r26,0(sp) stq r16,8(sp) ; loc stq r17,16(sp) ; value .base r27, $ls mov RETRY_COUNT,r23 ; Make sure we know what we're about to pick up. mb ; the ldl_l/stl_c combination detects whether the location has been modified ; in between load and store. retry: ldl_l r22,(r16) mov r22, r0 mov r17, r22 stl_c r22,(r16) ; r22 == 0: unsuccessful, retry operation ; r22 == 1: successful swap beq r22,store_failed ; Make sure what we put down is really there.. mb ; Return... ldq r26,0(sp) lda sp, stack_size(sp) ret (r26) ; retry operation immediately unless we've retried too many times. In that ; case hibernate for a short while defined above. store_failed: subq r23,1,r23 bne r23,retry .IF DEFINED GTMSHR_ASWP ; for GTMSECSHR, we do not sleep - not a good idea in privileged mode mov SLEEP_TIME,r16 $call HIBER_START, args=, set_arg_info=false, nonstandard=true .ENDC mov RETRY_COUNT,r23 ldq r16,8(sp) ldq r17,16(sp) br retry $end_routine .end fis-gtm-V6.0-003/sr_avms/auto_zlink.c0000644000032200000250000001026212201176175016342 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "axp_registers.h" #include "axp_gtm_registers.h" #include "axp.h" #include "urx.h" #include #include "stack_frame.h" #include "op.h" #include #define INST_SZ 1 #define LDQ_R17_OFF ((-5)*INST_SZ) #define LDQ_R16_OFF ((-4)*INST_SZ) #define LDL_R27_OFF ((-3)*INST_SZ) #define LDQ_R26_OFF ((-2)*INST_SZ) #define JMP_R26_OFF ((-1)*INST_SZ) #define LDQ_R17_X2_R13 (ALPHA_INS_LDQ | (ALPHA_REG_A1 << ALPHA_SHIFT_RA) | (GTM_REG_PV << ALPHA_SHIFT_RB)) #define LDQ_R16_X1_R13 (ALPHA_INS_LDQ | (ALPHA_REG_A0 << ALPHA_SHIFT_RA) | (GTM_REG_PV << ALPHA_SHIFT_RB)) #define LDL_R27_XF_R11 (ALPHA_INS_LDL | (ALPHA_REG_PV << ALPHA_SHIFT_RA) | (GTM_REG_XFER_TABLE << ALPHA_SHIFT_RB)) #define LDQ_R26_8_R27 (ALPHA_INS_LDQ | (ALPHA_REG_RA << ALPHA_SHIFT_RA) | (ALPHA_REG_PV << ALPHA_SHIFT_RB) \ | (8 << ALPHA_SHIFT_DISP)) #define JMP_R26_R26 (ALPHA_INS_JSR | (ALPHA_REG_RA << ALPHA_SHIFT_RA) | (ALPHA_REG_RA << ALPHA_SHIFT_RB)) GBLREF stack_frame *frame_pointer; error_def(ERR_LABELUNKNOWN); error_def(ERR_ROUTINEUNKNOWN); rhdtyp *auto_zlink(uint4 *pc, uint4 *line) { uint4 *A_proc_desc, *A_labaddr; mstr rname; mval rtn; rhdtyp *rhead; urx_rtnref *rtnurx; mident_fixed rname_local; /* ASSUMPTION The instructions immediately preceding the current mpc form a transfer table call. * There will be two arguments to this call: * the address of a procedure descriptor and * the address of a pointer to a value which is the offset from the beginning of the routine header to * the address of the first instruction to be executed in the routine to be called, as specified * by the [label][+offset] field (or the beginning of the routine if label and offset are not * specified * * The entire instruction sequence will look like this: * ldq r17, x2(r13) * ldq r16, x1(r13) * ldl r27, 4*xf_off(r11) * ldq r26, 8(r27) * jmp r26, (r26) * * N.B., the instruction sequence above occurs in compiled object modules; in direct mode, the argument * registers are loaded via "ldl" instructions. However, this routine should never be invoked from direct * mode because the applicable routine should have been ZLINK'ed by prior calls to op_labaddr and op_rhdaddr. */ /* Verify calling sequence. */ if ( (*(pc + LDQ_R17_OFF) & ~(ALPHA_MASK_DISP << ALPHA_SHIFT_DISP)) != LDQ_R17_X2_R13 || (*(pc + LDQ_R16_OFF) & ~(ALPHA_MASK_DISP << ALPHA_SHIFT_DISP)) != LDQ_R16_X1_R13 || (*(pc + LDL_R27_OFF) & ~(ALPHA_MASK_DISP << ALPHA_SHIFT_DISP)) != LDL_R27_XF_R11 || (*(pc + LDQ_R26_OFF) != LDQ_R26_8_R27) || (*(pc + JMP_R26_OFF) != JMP_R26_R26) ) GTMASSERT; /* Calling sequence O.K.; get address(address(procedure descriptor)) and address(address(label offset)). */ A_proc_desc = (*(pc + LDQ_R16_OFF) & (ALPHA_MASK_DISP << ALPHA_SHIFT_DISP)) + frame_pointer->ctxt; A_labaddr = (*(pc + LDQ_R17_OFF) & (ALPHA_MASK_DISP << ALPHA_SHIFT_DISP)) + frame_pointer->ctxt; if (azl_geturxrtn(A_proc_desc, &rname, &rtnurx)) { assert(rname.len <= MAX_MIDENT_LEN); assert(0 != rname.addr); /* Copy rname into local storage because azl_geturxrtn sets rname.addr to an address that is * free'd during op_zlink and before the call to find_rtn_hdr. */ memcpy(rname_local.c, rname.addr, rname.len); rname.addr = rname_local.c; assert(0 != rtnurx); assert(azl_geturxlab(A_labaddr, rtnurx)); assert(0 == find_rtn_hdr(&rname)); rtn.mvtype = MV_STR; rtn.str.len = rname.len; rtn.str.addr = rname.addr; op_zlink(&rtn, 0); if (0 != (rhead = find_rtn_hdr(&rname))) { *line = *A_labaddr; if (0 == *line) rts_error(VARLSTCNT(1) ERR_LABELUNKNOWN); return rhead; } } rts_error(VARLSTCNT(1) ERR_ROUTINEUNKNOWN); } fis-gtm-V6.0-003/sr_avms/auto_zlink.h0000644000032200000250000000104512201176167016347 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __AUTO_ZLINK_H__ #define __AUTO_ZLINK_H__ rhdtyp *auto_zlink(uint4 *pc, uint4 *line); #endif fis-gtm-V6.0-003/sr_avms/axp_gtm_registers.h0000644000032200000250000000322312201176167017716 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* axp_gtm_registers.h - GT.M OpenVMS AXP register usage. * * Requires "axp_registers.h". * */ #define GTM_REG_FRAME_POINTER ALPHA_REG_S10 /* r12 */ #define GTM_REG_FRAME_VAR_PTR ALPHA_REG_S6 /* r8 */ #define GTM_REG_FRAME_TMP_PTR ALPHA_REG_S7 /* r9 */ #define GTM_REG_LITERAL_BASE ALPHA_REG_S12 /* r14 */ #define GTM_REG_XFER_TABLE ALPHA_REG_S9 /* r11 */ #define GTM_REG_DOLLAR_TRUTH ALPHA_REG_S8 /* r10 */ #define GTM_REG_R0 ALPHA_REG_R0 #define GTM_REG_R1 ALPHA_REG_R1 #define GTM_REG_ACCUM ALPHA_REG_T1 /* r23 */ #define GTM_REG_COND_CODE ALPHA_REG_T2 /* r24 */ #define GTM_REG_CODEGEN_TEMP ALPHA_REG_VS /* r28 */ /* The generated code uses GTM_REG_PV for its PV. Also, the VAX Macro * translator uses S11 (R13) to save the current PV. So, for consistency, * we make the GTM PV the same (S11). In addition, when returning from * C, we usually reload the PV of the procedure to which we are returning * into S11 where it is expected (from the Mumps stack frame). In some * routines (OPP_RET, for example), we intend to "return" to a new procedure * and enter it via its prolog: in that case, we need to set the PV into * R27, the Alpha PV register. */ #define GTM_REG_PV ALPHA_REG_S11 /* r13 */ fis-gtm-V6.0-003/sr_avms/axp_registers.h0000644000032200000250000000326112201176167017051 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* axp_registers.h - OpenVMS AXP register usage. */ /* Register names according to OpenVMS usage. */ #define ALPHA_REG_R0 0 /* corresponds to VAX register r0 */ #define ALPHA_REG_R1 1 /* corresponds to VAX register r1 */ #define ALPHA_REG_S0 2 /* saved */ #define ALPHA_REG_S1 3 #define ALPHA_REG_S2 4 #define ALPHA_REG_S3 5 #define ALPHA_REG_S4 6 #define ALPHA_REG_S5 7 #define ALPHA_REG_S6 8 #define ALPHA_REG_S7 9 #define ALPHA_REG_S8 10 #define ALPHA_REG_S9 11 #define ALPHA_REG_S10 12 #define ALPHA_REG_S11 13 #define ALPHA_REG_S12 14 #define ALPHA_REG_S13 15 #define ALPHA_REG_A0 16 /* argument */ #define ALPHA_REG_A1 17 #define ALPHA_REG_A2 18 #define ALPHA_REG_A3 19 #define ALPHA_REG_A4 20 #define ALPHA_REG_A5 21 #define ALPHA_REG_T0 22 /* temp */ #define ALPHA_REG_T1 23 #define ALPHA_REG_T2 24 #define ALPHA_REG_AI 25 /* arg info */ #define ALPHA_REG_RA 26 /* return address */ #define ALPHA_REG_PV 27 /* procedure value */ #define ALPHA_REG_VS 28 /* volatile scratch */ #define ALPHA_REG_FP 29 /* frame pointer */ #define ALPHA_REG_SP 30 /* stack pointer */ #define ALPHA_REG_ZERO 31 /* hard-wired zero */ #define ALPHA_REG_V0 ALPHA_REG_R0 /* function return value */ /* Number of arguments passed in registers. */ #define MACHINE_REG_ARGS 6 fis-gtm-V6.0-003/sr_avms/base_frame.max0000644000032200000250000001646712201176167016630 0ustar librarygtc .macro base_frame ; base_frame describes the machine stack frame in which all GT.M MUMPS object code ; executes. It has a fixed stack size large enough for the saved registers and ; the condition handler address as expected by GTM$DYN_CH. In addition, there is ; a stack temporary area large enough for the largest allowable number of parameters ; (limited by the VAX 'calls' instruction whose count parameter must be <= 255). ; Stack size information. These fields MUST match values in create_object_file() in ; obj_file.c. Changes to any of these values will require customers both to recompile ; their GT.M source files and to re-link the new object files. ; Note: the intricacy of the offset calculations is required in order to duplicate ; the structure expected by the $routine and $return macros which require certain ; blocks of data in a stack frame to be aligned on 16-byte boundaries. NQUADS_REQUIRED = 2 ; one at (sp) for r27 and one at 8(sp) for A(condition handler) NLOCALS = 16 ; allows room for expansion base_frame_regs = "r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, fp" NREGS_SAVED = 16 ; and r26 (default) NARGS_SAVED = <1+6> ; r25 (count) and r16-r21 RSA_END = <<<<*8>+15>/16>*16> ; end of register save area RSA_OFFSET = > STACK_SIZE = <<+15>/16>*16> ; add room for argument save area (round up again) ARG_OFFSET = > ; offset of r25, r16-r21 save area in stack frame ; Offsets from fp into stack frame for locals: GTM_LOCAL_1 = 16 GTM_LOCAL_2 = 24 GTM_LOCAL_3 = 32 GTM_LOCAL_4 = 40 GTM_LOCAL_5 = 48 GTM_LOCAL_6 = 56 GTM_LOCAL_7 = 64 GTM_LOCAL_8 = 72 GTM_LOCAL_9 = 80 GTM_LOCAL_10 = 88 GTM_LOCAL_11 = 96 GTM_LOCAL_12 = 104 GTM_LOCAL_13 = 112 GTM_LOCAL_14 = 120 GTM_LOCAL_15 = 128 GTM_LOCAL_16 = 136 GTM_LOCAL_SIZE = GTM_LOCAL_16+8 ; Stack extension area for building argument lists for calling other routines and for internal use. ARG_AREA_SZ = 256*8 ; room for 256 arguments + 6 extra quadwords. The VAX 'calls' instruction allows a maximum ; of 255 arguments and we pass the count as an argument sometimes, but because the AXP ; passes the first six arguments and the argument count in registers, we only need 250 ; locations for argument-passing and the other 6 quadwords are available for internal ; GT.M use. ; Offsets from fp into stack extension area for internal use-quadwords (hidden locals): GTM_INTERNAL_1 = -1*8 GTM_INTERNAL_2 = -2*8 GTM_INTERNAL_3 = -3*8 GTM_INTERNAL_4 = -4*8 GTM_INTERNAL_5 = -5*8 GTM_INTERNAL_6 = -6*8 ; Here's the stack frame defined by base_frame and created by create_base_frame: ; +---------------------------------------+ <- caller's sp ----- ; | r21 (argument 6) |\ (Q-aligned) ^ ; +---------------------------------------+ \ | ; | r20 (argument 5) | | | ; +---------------------------------------+ | | ; | r19 (argument 4) | | | ; +---------------------------------------+ | home area for arguments | ; | r18 (argument 3) | |--- passed in registers; must | ; +---------------------------------------+ | be contiguous with | ; | r17 (argument 2) | | caller's sp for varargs | ; +---------------------------------------+ | to work | ; | r16 (argument 1) | | | ; +---------------------------------------+ / | ; | r25 (argument info/count) |/ | ; +---------------------------------------+ | ; = = | ; fp+RSA_END-> +---------------------------------------+ (Q-aligned) | ; | fp |\ | ; +---------------------------------------+ \ | ; | r15 | | | ; +---------------------------------------+ | | ; | r14 | | | ; +---------------------------------------+ | | ; | r13 | | | ; +---------------------------------------+ | | ; | r12 | | | ; +---------------------------------------+ | | ; | r11 | | | ; +---------------------------------------+ | | ; | r10 | | | ; +---------------------------------------+ |--- saved registers | ; | r9 | | | ; +---------------------------------------+ | | ; | r8 | | | ; +---------------------------------------+ | | ; | r7 | | | ; +---------------------------------------+ | | ; | r6 | | | ; +---------------------------------------+ | | ; | r5 | | | ; +---------------------------------------+ | | ; | r4 | | | ; +---------------------------------------+ | |--- STACK_SIZE ; | r3 | | | ; +---------------------------------------+ / | ; | r2 |/ | ; fp+RSA_OFFSET-> +---------------------------------------+ | ; = = | ; +---------------------------------------+ | ; fp+136 | GTM_LOCAL_16 | | ; +---------------------------------------+ | ; fp+128 | GTM_LOCAL_15 | | ; +---------------------------------------+ | ; fp+120 | GTM_LOCAL_14 | | ; +---------------------------------------+ | ; fp+112 | GTM_LOCAL_13 | | ; +---------------------------------------+ | ; fp+104 | GTM_LOCAL_12 | | ; +---------------------------------------+ | ; fp+96 | GTM_LOCAL_11 | | ; +---------------------------------------+ | ; fp+88 | GTM_LOCAL_10 | | ; +---------------------------------------+ | ; fp+80 | GTM_LOCAL_9 | | ; +---------------------------------------+ | ; fp+72 | GTM_LOCAL_8 | | ; +---------------------------------------+ | ; fp+64 | GTM_LOCAL_7 | | ; +---------------------------------------+ | ; fp+56 | GTM_LOCAL_6 | | ; +---------------------------------------+ | ; fp+48 | GTM_LOCAL_5 | | ; +---------------------------------------+ | ; fp+40 | GTM_LOCAL_4 | | ; +---------------------------------------+ | ; fp+32 | GTM_LOCAL_3 | | ; +---------------------------------------+ | ; fp+24 | GTM_LOCAL_2 | | ; +---------------------------------------+ | ; fp+16 | GTM_LOCAL_1 | | ; +---------------------------------------+ | ; fp+8 | A(condition handler) | GTM$DYN_CH looks here | ; +---------------------------------------+ (0 => no handler) | ; | r27 (PV) | v ; +---------------------------------------+ <- fp (Q-aligned) ----- ; fp-8 | GTM_INTERNAL_1 |\ ^ ; +---------------------------------------+ \ | ; fp-16 | GTM_INTERNAL_2 | | | ; +---------------------------------------+ | | ; fp-24 | GTM_INTERNAL_3 | | | ; +---------------------------------------+ |--- internal-use quadwords | ; fp-32 | GTM_INTERNAL_4 | | (hidden locals) |--- ARG_AREA_SZ ; +---------------------------------------+ | | ; fp-40 | GTM_INTERNAL_5 | | | ; +---------------------------------------+ / | ; fp-48 | GTM_INTERNAL_6 |/ | ; +---------------------------------------+ | ; = = | ; | (room for 250 arguments) | | ; = = V ; fp-ARG_AREA_SZ +---------------------------------------+ <- sp (Q-aligned) ----- .endm base_frame fis-gtm-V6.0-003/sr_avms/bci.mar0000644000032200000250000000017512201176167015260 0ustar librarygtc .title bci bit clear interlocked VAX = 1 code_psect .entry bci,^m<> clrl r0 bbcci #0,@4(ap),10$ incl r0 10$: ret .end fis-gtm-V6.0-003/sr_avms/bind_symbol.m640000644000032200000250000000141312201176167016647 0ustar librarygtc .title BIND_SYMBOL "Utility routine for bndsym macro" $routine BIND_SYMBOL, entry=BIND_SYMBOL_CA, kind=null lda sp, -32(sp) stq r13, 24(sp) stq r26, 16(sp) mov r27, r13 .base r13, $ls stq r18, 8(sp) ; save pointer to linkage pair $call LIB$FIND_IMAGE_SYMBOL, args=, nonstandard=true blbc r0, 10$ ldq r18, 8(sp) ; r18 -> linkage pair ldl r28, (sp) ; r28 = procedure value returned by LIB$FIND_IMAGE_SYMBOL stq r28, 8(r18) ; store PV in 2nd quadword of linkage pair ldq r28, 8(r28) ; r28 = entry address from procedure descriptor stq r28, (r18) ; store entry in 1st quadword of linkage pair 5$: ldq r28, 16(sp) ldq r13, 24(sp) lda sp, 32(sp) ret r28 10$: mov r0, r16 $call LIB$SIGNAL, args=, nonstandard=true br 5$ $end_routine .end fis-gtm-V6.0-003/sr_avms/bndsym.max0000644000032200000250000000252112201176167016022 0ustar librarygtc .macro bndsym symbol, image, ?entry_point, ?proc_value, ?symdesc, ?imdesc ; Bind a universal symbol at run time $routine symbol, entry=symbol'_CA, kind=null, - data_section=<$bndsym_data,pic,noexe>, data_section_pointer=true $data_section .align quad entry_point: .quad 0 ; entry_point and proc_value together proc_value: .quad 0 ; define a linkage pair .align long symdesc: .ascid /symbol/ .align long imdesc: .ascid /image/ $code_section .base r27, $ls ldq r22, $dp .base r22, $ds ldq r28, entry_point beq r28, 10$ ldq r27, proc_value jmp r28 ; Call BIND_SYMBOL to resolve the symbol's address, then jmp to it. ; This must be transparent, so save (and restore) all of the ; argument-related registers, as well as the original return address. 10$: lda sp, -80(sp) stq r16, 0(sp) stq r17, 8(sp) stq r18, 16(sp) stq r19, 24(sp) stq r20, 32(sp) stq r21, 40(sp) stq r22, 48(sp) ; data section base register stq r25, 56(sp) ; original argument count stq r26, 64(sp) ; original return address $call BIND_SYMBOL, args=, nonstandard=true ldq r16, 0(sp) ldq r17, 8(sp) ldq r18, 16(sp) ldq r19, 24(sp) ldq r20, 32(sp) ldq r21, 40(sp) ldq r22, 48(sp) ldq r25, 56(sp) ldq r26, 64(sp) lda sp, 80(sp) ldq r28, entry_point ldq r27, proc_value jmp r28 $end_routine .endm fis-gtm-V6.0-003/sr_avms/bsi.mar0000644000032200000250000000020112201176167015266 0ustar librarygtc .title bsi bit set interlocked VAX = 1 code_psect .entry bsi,^m<> clrl r0 bbssi #0,@4(ap),10$ ret 10$: incl r0 ret .end fis-gtm-V6.0-003/sr_avms/call_dm.m640000644000032200000250000000150312201176167015741 0ustar librarygtc .title CALL_DM ; CALL_DM - call direct mode ; ; CALL_DM controls execution of GT.M direct mode. It executes in a ; GT.M MUMPS stack frame and is, in fact, normally entered via a ; getframe/ret instruction sequence. CALL_DM invokes OPP_DMODE ; for each input line. ; ; entry: ; r13 - address of CALL_DM's procedure descriptor (not r27) ; ; WARNING: because CALL_DM is designed to be invoked from a GT.M ; MUMPS stack frame, it does not conform to the Alpha calling ; standard and cannot be invoked from any high-level language. ; The invoker should load the address of PSEUDO_RET's procedure ; descriptor into r13, not r27. $linkage_section $code_section $routine CALL_DM, entry=CALL_DM_CA, kind=null .base r13, $ls loop: $call OPP_DMODE, nonstandard=true $call OP_OLDVAR, nonstandard=true br loop $end_routine .end fis-gtm-V6.0-003/sr_avms/caller_id.m640000644000032200000250000000110412201176167016261 0ustar librarygtc .title CALLER_ID "Get PC of caller's caller" $LIBICBDEF $routine CALLER_ID, entry=CALLER_ID_CA, kind=stack, saved_regs= mov r27, r13 .base r13, $ls lda sp, -LIBICB$K_INVO_CONTEXT_BLK_SIZE(sp) ; Allocate an Invocation Context Block $call LIB$GET_CURR_INVO_CONTEXT, args= ; Get our invocation context $call LIB$GET_PREV_INVO_CONTEXT, args= ; Get our caller's invocation context $call LIB$GET_PREV_INVO_CONTEXT, args= ; Get our caller's caller's invocation context ldq r0, LIBICB$Q_PROGRAM_COUNTER(sp) ; Extract its PC $return $end_routine .end fis-gtm-V6.0-003/sr_avms/callg.mar0000644000032200000250000000017112201176167015601 0ustar librarygtc .title callg ;callg(rout, args) VAX = 1 code_psect .entry callg,^m<> movl 8(ap),r0 callg (r0),@4(ap) ret .end fis-gtm-V6.0-003/sr_avms/cmi_symbols.m640000644000032200000250000000044612201176167016673 0ustar librarygtc .title CMI_SYMBOLS "Bind CMISHR at run time" bndsym CMI_CLOSE, CMISHR bndsym CMI_INIT, CMISHR bndsym CMI_OPEN, CMISHR bndsym CMI_READ, CMISHR bndsym CMI_WRITE, CMISHR bndsym CMI_WRITE_INT, CMISHR bndsym CMU_GETCLB, CMISHR bndsym CMU_MAKCLB, CMISHR bndsym CMU_NTDROOT, CMISHR .end fis-gtm-V6.0-003/sr_avms/cmilink.axp0000644000032200000250000000154212201176167016161 0ustar librarygtc!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! ! Copyright 2001, 2003 Sanchez Computer Associates, Inc. ! ! ! ! This source code contains the intellectual property ! ! of its copyright holder(s), and is made available ! ! under a license. If you do not know the terms of ! ! the license, please stop and do not read further. ! ! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! cluster = code_clust collect = code_clust,$code psect_attr = $char_string_constants,shr,nowrt cluster = gtmvector collect = gtmvector,gtmvector gsmatch = lequal,4,0 symbol_vector=( - cmi_close = PROCEDURE, - cmi_init = PROCEDURE, - cmi_open = PROCEDURE, - cmi_read = PROCEDURE, - cmi_write = PROCEDURE, - cmi_write_int = PROCEDURE, - cmu_makclb = PROCEDURE, - cmu_getclb = PROCEDURE, - cmu_ntdroot = PROCEDURE - ) fis-gtm-V6.0-003/sr_avms/code_psect.max0000644000032200000250000000012312201176167016632 0ustar librarygtc .macro code_psect .psect $code,pic,usr,con,rel,lcl,shr,exe,rd,nowrt,novec .endm fis-gtm-V6.0-003/sr_avms/compswap.m640000644000032200000250000000075612201176167016210 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2005 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GTMSHR_COMPSWAP = 1 .INCLUDE "gtm$src:compswap_src.h" fis-gtm-V6.0-003/sr_avms/compswap_secshr.m640000644000032200000250000000076112201176167017553 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2005 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GTMSECSHR_COMPSWAP = 1 .INCLUDE "gtm$src:compswap_src.h" fis-gtm-V6.0-003/sr_avms/compswap_src.h0000644000032200000250000000562712201176167016702 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2005 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Compare and Swap ; int compswap(gtm_global_latch_t *loc, int cmpvalue1, int cmpvalue2, int newvalue1, int newvalue2) ; ; For VMS, the latch is the form of an aligned 8 byte field. The comparison value is ; constructed from (cmpvalue2 << 32 | cmpvalue1) and likewise the swap value ; is constructed from (newvalue2 << 32 | cmpvalue1). If the supplied latch contains ; the constructed comparison value, the constructed swap value is stored in the latch atomically. ; Return TRUE if store succeeds and lock reset. Otherwise return FALSE. .IF DEFINED GTMSHR_COMPSWAP .title COMPSWAP $routine COMPSWAP, entry=COMPSWAP_CA, kind=null .ELSE .IF DEFINED GTMSECSHR_COMPSWAP .title COMPSWAP_SECSHR $routine COMPSWAP_SECSHR, entry=COMPSWAP_SECSHR_CA, kind=null .ELSE .ERROR "Unsupported image" .ENDC .ENDC RETRY_COUNT = 1000 ; of times to attempts before sleeping SLEEP_TIME = 500 ; 1/2 ms TRUE = 1 FALSE = 0 stack_size = 56 lda sp, -stack_size(sp) stq r26, 0(sp) stq r16, 8(sp) ; ->loc stq r17, 16(sp) ; cmpvalue1 stq r18, 24(sp) ; cmpvalue2 stq r19, 32(sp) ; newvalue1 stq r20, 40(sp) ; newvalue2 .base r27, $ls mov RETRY_COUNT, r24 ; Make sure we know what we are about to pick up. mb ; the ldl_l/stl_c combination detects whether the location has been modified ; in between load and store. mov FALSE,r0 ; assume failure retry: sll r18, 32, r21 ; r21 = r18 << 32 bis r21, r17, r21 ; add in low order part of comparison value ldq_l r22, (r16) ; load and lock the value cmpeq r22, r21, r23 ; expected value supplied? beq r23, return_now ; return fact that compare failed sll r20, 32, r21 ; create 8 byte swap value bis r21, r19, r21 stq_c r21, (r16) ; store and return ; r22 == 0: unsuccessful, retry operation ; r22 == 1: successful swap beq r21, store_failed ; Make sure what we put down is really there.. mb mov TRUE,r0 ; Store was a success return_now: ; both error and normal return ldq r26,0(sp) lda sp, stack_size(sp) ret (r26) ; retry operation immediately unless we have retried too many times. In that ; case hibernate for a short period.. store_failed: subq r24, 1, r24 bne r24, retry .IF DEFINED GTMSHR_COMPSWAP ; for GTMSECSHR, we do not sleep - not a good idea in privileged mode mov SLEEP_TIME, r16 $call HIBER_START, args=, set_arg_info=false, nonstandard=true .ENDC mov RETRY_COUNT,r24 ldq r16, 8(sp) ldq r17, 16(sp) ldq r18, 24(sp) ldq r19, 32(sp) ldq r20, 40(sp) mov FALSE, r0 br retry $end_routine .end fis-gtm-V6.0-003/sr_avms/create_base_frame.max0000644000032200000250000000274012201176167020140 0ustar librarygtc .macro create_base_frame ; create_base_frame is the routine prologue code that sets up the machine ; stack frame in which all GT.M MUMPS object code executes. .if ne,$SIZE,STACK_SIZE .error "The stack frame size computed by $routine (%integer(%SIZE)) differs from that defined in the - base_frame macro (%integer(STACK_SIZE))." .endc .if ne,$SIZE-56,ARG_OFFSET .error "The homed argument list offset computed by $routine (%integer($SIZE-56)) differs from - that expected (%integer(ARG_OFFSET))." .endc lda sp, -$SIZE(sp) stq r27, (sp) ; linkage Psect pointer stq r26, $RSA_OFFSET(sp) stq r2, $RSA_OFFSET+8(sp) stq r3, $RSA_OFFSET+16(sp) stq r4, $RSA_OFFSET+24(sp) stq r5, $RSA_OFFSET+32(sp) stq r6, $RSA_OFFSET+40(sp) stq r7, $RSA_OFFSET+48(sp) stq r8, $RSA_OFFSET+56(sp) stq r9, $RSA_OFFSET+64(sp) stq r10, $RSA_OFFSET+72(sp) stq r11, $RSA_OFFSET+80(sp) stq r12, $RSA_OFFSET+88(sp) stq r13, $RSA_OFFSET+96(sp) stq r14, $RSA_OFFSET+104(sp) stq r15, $RSA_OFFSET+112(sp) stq fp, $RSA_OFFSET+120(sp) stq r31, 8(sp) ; establish no condition handler ; Copy the register arguments onto the stack (a la varargs). stq r21, $SIZE-8(sp) stq r20, $SIZE-16(sp) stq r19, $SIZE-24(sp) stq r18, $SIZE-32(sp) stq r17, $SIZE-40(sp) stq r16, $SIZE-48(sp) stq r25, $SIZE-56(sp) trapb ; synchronize exceptions mov sp, fp ; establish existence of stack frame $end_prologue lda sp, -ARG_AREA_SZ(sp) ; extend for argument push area .endm create_base_frame fis-gtm-V6.0-003/sr_avms/data_psect_bound.m640000644000032200000250000000122212201176167017642 0ustar librarygtc .title data_psect_bound define boundaries of $DATA PSECT's G_MSF .psect $DAT9ZZZZZZZZZZ pic,ovr,rel,gbl,noshr,noexe,rd,wrt,novec,long datastrt: .psect $DATAAAAAAAAAAA pic,ovr,rel,gbl,noshr,noexe,rd,wrt,novec,long dataend: $linkage_section A_datastrt: .address datastrt A_dataend: .address dataend ; data_psect_bound ; ; arg1 address of pointer to receive address of datastrt ; arg2 address of pointer to receive address of dataend $routine name=data_psect_bound,entry=data_psect_bound_ca,kind=null .base r27, $ls ldq r28, A_datastrt ldq r22, A_dataend stl r28, (r16) stl r22, (r17) ret r26 $end_routine name=data_psect_bound .end fis-gtm-V6.0-003/sr_avms/ddp_dal_dispatch.m640000644000032200000250000000530112201176167017614 0ustar librarygtc .title ddp_dal_dispatch MAX_SUBSCRIPTS = 12 MAX_ARG_SIZE = <<<*8>+15>/16>*16 ; space for gtmi$_extgbl, destination, aux owner, all subscripts $linkage_section A_subscript_array: .address subscript_array A_subscript_count: .address subscript_count Q_gtmi$_extgbl: .quad gtmi$_extgbl $routine name=ddp_dal_dispatch, entry=ddp_dal_dispatch_ca, - kind=stack, base_reg_is_fp=true, standard_prologue=true .base r27, $ls subq sp, MAX_ARG_SIZE, sp ldq r0, A_subscript_count ldq r1, A_subscript_array ldl r0, (r0) addq r0, 1, r25 ; argument count (array starts @ 0, argument count @ 1) ; If destination argument (argument 2) is non-zero, pass it as 2nd argument, else skip it. ; Rest of argument list to dispatched routine is addresses of elements in subscript array. beq r17, 3$ ; if no destination argument addq r25, 1, r25 ; need another argument position for destination (leave in r17) br 5$ 3$: lda r17, (r1) ; if no destination argument, start with first array element in r17 addq r1, 8, r1 ; skip over first array element (already in argument list) subq r0, 1, r0 ; remember not to count it twice 5$: lda r18, (r1) lda r19, 8(r1) lda r20, 16(r1) lda r21, 24(r1) subq r0, 4, r0 ble r0, 20$ ; if no more arguments ; Copy rest of array element addresses to stack area. addq r1, 32, r1 mov sp, r22 10$: lda r28, (r1) stq r28, (r22) subq r0, 1, r0 addq r1, 8, r1 addq r22, 8, r22 bgt r0, 10$ 20$: ldq r0, Q_gtmi$_extgbl mov r16, r27 ldq r26, 8(r16) mov r0, r16 jsr r26, (r26) $return $end_routine name=ddp_dal_dispatch $routine name=ddp_lock_dispatch, entry=ddp_lock_dispatch_ca, - kind=stack, base_reg_is_fp=true, standard_prologue=true .base r27, $ls subq sp, MAX_ARG_SIZE, sp ldq r0, A_subscript_count ldq r1, A_subscript_array ldl r0, (r0) addq r0, 2, r25 ; array elements + 1 for auxown mov r16, r22 ; save A(routine to call) for later ; Skip timeout on unlock. and r17, ^Xff, r16 bne r16, 3$ ; skip timeout on unlock (otherwise timeout in r16 == 0) mov r18, r17 ; aux owner ldq r18, Q_gtmi$_extgbl addq r25, 1, r25 ; need another argument position br 5$ 3$: mov r18, r16 ; aux owner ldq r17, Q_gtmi$_extgbl lda r18, (r1) addq r1, 8, r1 ; skip over first array element (already in argument list) subq r0, 1, r0 ; remember not to count it twice 5$: lda r19, (r1) lda r20, 8(r1) lda r21, 16(r1) subq r0, 3, r0 ble r0, 20$ ; if no more arguments ; Copy rest of array element addresses to stack area. addq r1, 24, r1 mov sp, r23 10$: lda r28, (r1) stq r28, (r23) subq r0, 1, r0 addq r1, 8, r1 addq r23, 8, r23 bgt r0, 10$ 20$: ldq r26, 8(r22) mov r22, r27 jsr r26, (r26) $return $end_routine name=ddp_lock_dispatch .end fis-gtm-V6.0-003/sr_avms/ddpgvusr_symbols.m640000644000032200000250000000060612201176167017757 0ustar librarygtc .title DDPGVUSR_SYMBOLS "Bind DDPGVUSR at run time" bndsym GVUSR_INIT, DDPGVUSR bndsym GVUSR_RUNDOWN, DDPGVUSR bndsym GVUSR_DATA, DDPGVUSR bndsym GVUSR_ORDER, DDPGVUSR bndsym GVUSR_QUERY, DDPGVUSR bndsym GVUSR_ZPREVIOUS,DDPGVUSR bndsym GVUSR_GET, DDPGVUSR bndsym GVUSR_KILL, DDPGVUSR bndsym GVUSR_PUT, DDPGVUSR bndsym GVUSR_LOCK, DDPGVUSR bndsym GVUSR_UNLOCK, DDPGVUSR .end fis-gtm-V6.0-003/sr_avms/ddplink.axp0000644000032200000250000000247412201176167016165 0ustar librarygtc!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! ! Copyright 2001, 2003 Sanchez Computer Associates, Inc. ! ! ! ! This source code contains the intellectual property ! ! of its copyright holder(s), and is made available ! ! under a license. If you do not know the terms of ! ! the license, please stop and do not read further. ! ! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ddpobj/lib gtmshr/share gtmsecshr/share symbol_vector=( - gvusr_init = PROCEDURE, - gvusr_rundown = PROCEDURE, - gvusr_data = PROCEDURE, - gvusr_order = PROCEDURE, - gvusr_query = PROCEDURE, - gvusr_zprevious = PROCEDURE, - gvusr_get = PROCEDURE, - gvusr_kill = PROCEDURE, - gvusr_put = PROCEDURE, - gvusr_lock = PROCEDURE, - gvusr_unlock = PROCEDURE - ) gsmatch=lequal,4,0 ! Because the linker creates image sections on a per-cluster ! basis, create a cluster for all of the code Psect's (whose ! pages can be shared among processes) and collect all of the ! code Psect's into it so the pages corresponding to that image ! section can be shared. Note the MACRO/MIGRATION compiler ! names its code Psect "$CODE" (as do most of the VAX compilers), ! while the AXP C compiler and MACRO assembler name their code ! Psect's "$CODE$". cluster = code_clust collect = code_clust,$CODE,$CODE$ fis-gtm-V6.0-003/sr_avms/error_return_vms.m640000644000032200000250000000136512201176167017771 0ustar librarygtc .title ERROR_RETURN_VMS ; ERROR_RETURN_VMS calls error_return (which doesn't return). ; ; entry: ; r13 - address of ERROR_RETURN_VMS's procedure descriptor (not r27) ; ; WARNING: because ERROR_RETURN_VMS is designed to be invoked from a GT.M ; MUMPS stack frame, it does not conform to the Alpha calling ; standard and cannot be invoked from any high-level language. ; The invoker should load the address of ERROR_RETURN_VMS's procedure ; descriptor into r13, not r27. g_msf $linkage_section A_frame_pointer: .address frame_pointer $code_section $routine ERROR_RETURN_VMS, entry=ERROR_RETURN_VMS_CA, kind=null .base r13, $ls mov r13, r27 $call error_return, set_arg_info=false, nonstandard=true getframe ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/fetch_args.max0000644000032200000250000000352312201176167016636 0ustar librarygtc .macro fetch_args sp_save_reg, stack_offset, ?loop, ?skip ; This macro is used to call routine GTM_FETCH, passing a variable-length argument list ; in which the first argument (i.e. R16) is the argument count. It moves the argument ; count from R16 to the Argument Information register, R25, and then moves the remaining ; arguments down one slot in the argument list. Since any arguments after the first six ; would have been passed on the stack, it also must move these arguments from their ; position above the current routine's save area to new slots below it. ; ; Arguments to this macro are: ; ; sp_save_reg : a register in which to save the current value of SP, and from ; which SP will be restored when done. This register must be ; one which is normally saved across routine calls, i.e. in the ; range of R2 to R15. ; ; stack_offset : the size, in bytes, of the current routine's save area. This ; value plus the current value of SP will be the address of the ; first stacked argument. ; ; Registers R16 through R21 and R25 through R28 are modified by this macro. mov r16, r25 ; argument count mov r17, r16 ; arg1 (to GTM_FETCH) mov r18, r17 ; arg2 mov r19, r18 ; arg3 mov r20, r19 ; arg4 mov r21, r20 ; arg5 ldq r21, stack_offset(sp) ; arg6 was on the stack subq r25, 6, r28 ; r28 = the number of arguments left on the stack mov sp, sp_save_reg ; save the current stack pointer ble r28, skip ; skip if no arguments left sll r28, 3, r27 ; r27 = the number of arguments to move, times 8 bytes addq r27, stack_offset, r27 ; account for the saved registers addq r27, sp, r27 ; r27 -> ArgN loop: ldq r26, (r27) lda sp, -8(sp) lda r27, -8(r27) subq r28, 1, r28 stq r26, (sp) bgt r28, loop skip: $call gtm_fetch, set_arg_info=false, nonstandard=true mov sp_save_reg, sp ; restore the stack .endm fetch_args fis-gtm-V6.0-003/sr_avms/fgncal_dispatch.m640000644000032200000250000006243312201176167017470 0ustar librarygtc .title fgncal_dispatch G_MSF base_frame ; Syntax codes. syn0 = 0 ; no mode argument (gtm$xecute) syn1 = 1 ; mode is in position 1, counting from 0 (gtm$lock) syn2 = 3 ; mode is in position 0, counting from 0 (gtm$get) syn3 = 4 ; mode is in position 2, counting from 0 (gtm$lock2) ; Stack offsets and related information. ; Locals. SAVE_R13 = GTM_LOCAL_1 $linkage_section A_active_lv: .address active_lv A_FGNCAL_CH: .address FGNCAL_CH A_fgncal_stack: .address fgncal_stack A_fgncal_rtn: .address fgncal_rtn A_frame_pointer: .address frame_pointer A_literal_null: .address literal_null A_mdb_condition_handler:.address mdb_condition_handler A_msp: .address msp A_mumps_status: .address mumps_status A_stringpool: .address stringpool A_xfer_table: .address xfer_table A_dollar_zstatus: .address dollar_zstatus L_ERR_IFBADPARM: .long ERR_IFBADPARM L_ERR_IFNOTINIT: .long ERR_IFNOTINIT L_ERR_LCKSTIMOUT: .long ERR_LCKSTIMOUT L_ERR_ORDER2: .long ERR_ORDER2 L_ERR_VAREXPECTED: .long ERR_VAREXPECTED Q_gtmi$_extgbl: .quad gtmi$_extgbl Q_gtmi$_extlcl: .quad gtmi$_extlcl Q_gtmi$_global: .quad gtmi$_global Q_gtmi$_local: .quad gtmi$_local Q_gtmi$_naked: .quad gtmi$_naked ; Strictly speaking, no_timeout should be in the data section, ; but it'll work here and save a base register. no_timeout: .long ^X0007fffe ; .macro fgncal_entry name, syn, fk, dst, ?A $routine name, entry=%string(name)_CA, kind=stack, - saved_regs=<%string(base_frame_regs)>, - rsa_offset=RSA_OFFSET, size=STACK_SIZE, - standard_prologue=false, handler=GTM$DYN_CH, synch_exceptions=true .if ne,$SIZE,STACK_SIZE .error "The stack frame size computed by $routine (%integer($SIZE)) differs from that expected - (%integer(STACK_SIZE))." .endc .if ne,$SIZE-56,ARG_OFFSET .error "The homed argument list offset computed by $routine (%integer($SIZE-56)) differs from - that expected (%integer(ARG_OFFSET))." .endc create_base_frame mov r27, r13 ; establish local base register .base r13, $ls ldq r28, A_stringpool ldl r28, (r28) bne r28, A ; if stringpool.base == 0, not initialized yet $call lib$signal, args= $return A: ldq r28, A_FGNCAL_CH stq r28, 8(fp) ; establish fgncal_ch as condition handler lda r2, syn(r31) lda r5, dst(r31) ; [Vinaya 10/30/2002] see note about dst in fgncal_procarg lda r7, fk(r31) ldq r28, A_mumps_status lda r22, 1(r31) stl r22, (r28) ldq r23, A_msp ldq r24, A_fgncal_stack ldl r23, (r23) stl r23, (r24) .endm ; fgncal_old provides an interface between old DAL entry points ; and new ones. The old version used separate names for the global ; and local versions of each function, while the new version uses ; the same name for both. fgncal_old creates dummy procedures that ; reset the link register and transfer execution to the new entry ; point. ; ; arguments: ; newname - name of new entry point ; gname - name of old global entry point ; lname - name of old local entry point .macro fgncal_old newname, gname, lname $linkage_section L_'newname: .linkage_pair newname $routine gname, entry=%string(gname)_CA, kind=null .base r27, $ls ldq r28, L_'newname ; N.B. don't modify r26 ldq r27, L_'newname+8 jmp r28 ; jump to name as if it were the entry point invoked $end_routine name=gname $routine lname, entry=%string(lname)_CA, kind=null .base r27, $ls ldq r28, L_'newname ; N.B. don't modify r26 ldq r27, L_'newname+8 jmp r28 ; jump to name as if it were the entry point invoked $end_routine name=lname .endm ; calls mimics the VAX calls instruction. It assumes all of ; the arguments to the routine to be called are on the stack. ; First, it copies the top 6 stack values to argument registers ; and pops the top 6 (or fewer, if fewer arguments) off the ; stack. After the call, it further adjusts the stack by ; removing any arguments after the first six. ; ; Arguments: ; args - number of arguments, must be either a saved ; register or an integer expression ; routine - routine to be called .macro calls args, routine ; Move arguments from stack to registers. mov args, r25 ldq r16, (sp) ldq r17, 8(sp) ldq r18, 16(sp) ldq r19, 24(sp) ldq r20, 32(sp) ldq r21, 40(sp) ; Adjust stack for arguments moved to registers. lda r22, 6(r31) subq r22, args, r28 cmovgt r28, args, r22 ; lesser of 6, actual number of arguments s8addq r22, sp, sp ; pop stack accordingly $call routine, set_arg_info=false, nonstandard=true ; If more than 6 arguments; remove rest from stack. mov args, r28 subq r28, 6, r28 cmovlt r28, r31, r28 ; number of arguments not in registers s8addq r28, sp, sp ; adjust stack .endm .macro bind sbc, mode, ?A, ?B, ?C, ?D, ?E, ?F, ?G ldq r28, Q_gtmi$_global subq mode, r28, r28 beq r28, B ldq r28, Q_gtmi$_extgbl subq mode, r28, r28 beq r28, D ldq r28, Q_gtmi$_local subq mode, r28, r28 beq r28, A ldq r28, Q_gtmi$_extlcl subq mode, r28, r28 beq r28, C F: br bparm ; unknown mode C: ; extlcl subq sbc, 2, r28 blt r28, F ; too few args ldq mode, (sp) br G D: ; extgbl subq sbc, 2, r28 blt r28, F ; too few args ldq mode, (sp) ; NOTE: The VAX instruction is "calls #0,fgn_glopref" which will not affect ; the caller's stack and requires the callee to handle its arguments properly. ; Consequently, we make no stack adjustment after the call here. $call fgn_glopref, args=<8(sp)/Q>, nonstandard=true G: stq r31, (sp) ; add 2nd env arg subq sp, 8, sp stq mode, (sp) br E B: ; global ; NOTE: The VAX instruction is "calls #0,fgn_glopref" which will not affect ; the caller's stack and requires the callee to handle its arguments properly. ; Consequently, we make no stack adjustment after the call here. $call fgn_glopref, args=<0(sp)/Q>, nonstandard=true A: subq sp, 8, sp stq r31, (sp) E: addq sbc, 1, sbc ; Move arguments to registers and set up stack properly. mov sbc, r25 ldq r16, (sp) ldq r17, 8(sp) ldq r18, 16(sp) ldq r19, 24(sp) ldq r20, 32(sp) ldq r21, 40(sp) lda r22, 6(r31) ; number of arguments in registers subq sbc, r22, r28 cmovlt r28, sbc, r22 ; lesser of 6, actual number of arguments s8addq r22, sp, sp ; pop register arguments off stack $call op_lkname, set_arg_info=false, nonstandard=true subq sbc, 6, r28 cmovlt r28, r31, r28 ; number of arguments not in registers s8addq r28, sp, sp ; pop rest off stack mov r31, sbc .endm ; fgncal_procarg is called at the beginning of each gtm$ fgncal_entry ; routine to verify and process input arguments. ; ; Entry: ; r2 - syntax code (syn) ; r5 - # of output arguments [Vinaya 10/30/2002] see note about dst below ; r7 - position of first key (fk), minimum # of arguments ; ; [Vinaya 10/30/2002] Note about dst. The role of this argument is not clear (to me). ; Note that this argument is 2 for gtm$data (and other functions ; that return a value) whereas $data returns only 1 result, ; i.e., there is only 1 destination argument. Also, $put doesn't ; provide any result, it takes input from arg in position 1 ; (counting from 0). In the below code, dst argument doesn't seem ; to be used, and doesn't appear to be stored by fgncal_procarg ; (in register or stack) for future use. I believe we could use ; this argument during argument processing. ; ; Exit: ; r0 - if local, pointer to lv_val -ret ; r2 - syntax code (syn) ; r3 - # of input arguments, # of subscripts ; r4 - return address of caller ; r5 - address of local name ; r6 - current key descriptor (b.j), mode -ret ; r7 - position of first key (fk), minimum # of arguments ; r8 - current arg in r25 (n) ; stack - sequence of &mval $routine name=fgncal_procarg, entry=fgncal_procarg_ca, kind=null, local=true stq r13, SAVE_R13(fp) mov r27, r13 .base r13, $ls mov r26, r4 ; save return address ldq r8, ARG_OFFSET(fp) ; n = ac subq r8, r7, r28 ; compare minimum # of arguments bge r28, 0$ br bparm ; too few 0$: bne r8, 15$ ; any args? subq r2, syn1, r28 ; might be a lock with no timeout bne r28, 12$ ldl r28, no_timeout subq sp, 8, sp stq r28, (sp) 12$: br fgncal_procarg_ret 15$: mov r31, r3 ; argument count 20$: ; loop top lda r6, ARG_OFFSET(fp) s8addq r8, r6, r6 ldq r6, (r6) ; r6 = b.n ldq r28, Q_gtmi$_extlcl ; highest-valued mode subq r6, r28, r28 ble r28, 22$ ; is it a mode? br 23$ 22$: ldq r28, Q_gtmi$_global ; lowest-valued mode subq r6, r28, r28 bge r28, 24$ ; it is a mode 23$: ; It's not a mode. $call push_mval, args=, nonstandard=true subq sp, 8, sp stq r0, (sp) ; pointer to mval used by op_xxname (accumulate on the stack) mov r0, r17 ; destination for conversion mov r6, r16 ; source descriptor $call desc2mval, args=, nonstandard=true ; convert descriptor to mval addq r3, 1, r3 subq r8, 1, r8 subq r8, r7, r28 ; n - fk cnt, bnd bge r28, 20$ ; more arguments left br pfin ; n == fk 24$: ; It's a mode. subq r2, syn1, r28 beq r28, 25$ subq r2, syn3, r28 beq r28, 25$ br bparm ; mode before done, but not a lock 25$: bne r3, 27$ ; any args? subq r8, r7, r28 ; n - fk bne r28, bparm ; should be done subq r8, 1, r8 br pfin ; n == fk 27$: bind r3, r6 ; bind.(k, nf, mode) subq r8, 1, r8 subq r8, r7, r28 ; n - fk cnt, bnd ble r28, pfin ; n == fk lda r6, ARG_OFFSET(fp) s8addq r8, r6, r6 ldq r6, (r6) ; r6 = b.n bne r6, bparm ; should be 0 delimiter between arguments subq r8, 1, r8 subq r8, r7, r28 ; n - fk cnt, bnd beq r28, bparm ; should be more to do br 20$ bparm: $call lib$signal, args=, nonstandard=true br fgncal_procarg_ret pfin: ; procarg wrap up subq r2, syn2, r28 beq r28, 50$ subq r2, syn1, r28 beq r28, 30$ subq r2, syn0, r28 beq r28, 40$ lda r28, ARG_OFFSET(fp) s8addq r8, r28, r28 ldq r28, (r28) subq sp, 8, sp stq r28, (sp) ; auxowner subq r8, 1, r8 30$: beq r8, 35$ subq r8, 1, r28 beq r28, 33$ br bparm ; should be down to timeout in position 0, counting from 0 33$: lda r6, ARG_OFFSET(fp) s8addq r8, r6, r6 ldq r6, (r6) ; timeout blt r6, 35$ subq sp, 8, sp stq r6, (sp) br 40$ 35$: ldl r0, no_timeout subq sp, 8, sp stq r0, (sp) 40$: br fgncal_procarg_ret 50$: subq r3, 1, r28 blt r28, bparm ; should have at least one arg ldq r6, ARG_OFFSET+8(fp) ldq r28, Q_gtmi$_global subq r6, r28, r28 bne r28, 60$ calls r3, op_gvname br fgncal_procarg_ret 60$: ldq r28, Q_gtmi$_naked subq r6, r28, r28 bne r28, 70$ calls r3, op_gvnaked br fgncal_procarg_ret 70$: ldq r28, Q_gtmi$_extgbl subq r6, r28, r28 bne r28, 90$ subq r3, 2, r28 blt r28, bparm ; extended globals need at least 2 args ldq r1, (sp) ; put new second parameter in for extnam ldq r28, A_literal_null ; second param for extnam is "" string stq r28, (sp) subq sp, 8, sp stq r1, (sp) addq r3, 1, r3 calls r3, op_gvextnam br fgncal_procarg_ret 90$: ldq r28, Q_gtmi$_local subq r6, r28, r28 bne r28, 95$ ldq r5, (sp) $call fgncal_lookup, args=, nonstandard=true addq sp, 8, sp beq r0, 100$ subq sp, 8, sp stq r0, (sp) br fgncal_procarg_ret 95$: br bparm ; unknown mode 100$: $call lib$signal, args=, nonstandard=true br fgncal_procarg_ret fgncal_procarg_ret: ldq r13, SAVE_R13(fp) ret r4 $end_routine name=fgncal_procarg ; fgncal_dispget sets up a destination mval and calls the op_ routine whose ; address is in r2. ; ; entry: ; r2 - address of routine to call ; ; exit: ; to fgncal_lclfini $routine fgncal_dispget, entry=fgncal_dispget_ca, kind=null, local=true mov r27, r13 .base r13, $ls $call push_mval, args=, nonstandard=true ; prepare a destination mov r0, r4 ; save for fgncal_lclfini ; $call (r2), args= ; do the real thing mov r0, r16 lda r25, 1(r31) mov r2, r27 ldq r26, 8(r27) jsr r26, (r26) $call fgncal_lclfini, set_arg_info=false, local=true, nonstandard=true ; doesn't return $end_routine name=fgncal_dispget ; fgncal_lclfini converts that to which r4 points from mval format to descriptor format. ; ; entry: ; r4 - pointer to mval ; ; exit: ; caller's second argument - descriptor created from mval $routine fgncal_lclfini, entry=fgncal_lclfini_ca, kind=null, local=true mov r27, r13 .base R13, $ls $call mval2desc, args=, nonstandard=true ; convert it for caller $call fgncal_dispret, set_arg_info=false, local=true, nonstandard=true ; doesn't return $end_routine name=fgncal_lclfini ; fgncal_dispret cleans up the fgncal stack and returns to the foreign caller. ; This is the routine that returns from the stack frame created by fgncal_entry. $routine fgncal_dispret, entry=fgncal_dispret_ca, kind=stack, local=true, - saved_regs=<%string(base_frame_regs)>, - rsa_offset=RSA_OFFSET, size=STACK_SIZE, - standard_prologue=false, handler=GTM$DYN_CH, synch_exceptions=true ; Since fgncal_dispret executes in and returns from the stack frame set up by ; fgncal_entry, it need not set up its own stack frame although it needs to declare ; one for the $return macro to work properly. $end_prologue mov r27, r13 .base r13, $ls $call fgncal_unwind, set_arg_info=false, nonstandard=true ldq r28, A_mumps_status ldl r0, (r28) $return ; to foreign caller $end_routine name=fgncal_dispret fgncal_entry gtm$get, syn2, 3, 2 $linkage_section A_op_gvget: .address op_gvget $code_section $call fgncal_procarg, set_arg_info=false, local=true ldq r28, Q_gtmi$_local subq r6, r28, r28 beq r28, 1$ ldq r2, A_op_gvget $call fgncal_dispget, set_arg_info=false, local=true ; doesn't return 1$: subq r3, 1, r28 beq r28, 10$ calls r3, op_getindx 10$: mov r0, r4 $call fgncal_lclfini, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$get fgncal_old gtm$get, gtm$gblget, gtm$lclget fgncal_entry gtm$put, syn2, 3, 2 $call fgncal_procarg, set_arg_info=false, local=true $call push_mval, args= ; convert value assigned mov r0, r4 $call desc2mval, args= ldq r28, Q_gtmi$_local subq r6, r28, r28 beq r28, 1$ $call op_gvput, args= $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return 1$: ldq r0, (sp) ; local subq r3, 1, r28 beq r28, 10$ calls r3, op_putindx 10$: ldl r16, (r4) ldl r17, 4(r4) ldl r18, 8(r4) ldl r19, 12(r4) ldl r20, 16(r4) stl r16, (r0) stl r17, 4(r0) stl r18, 8(r0) stl r19, 12(r0) stl r20, 16(r0) ldq r28, A_active_lv stl r31, (r28) $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$put fgncal_old gtm$put, gtm$gblput, gtm$lclput fgncal_entry gtm$kill, syn2, 2, 0 $call fgncal_procarg, set_arg_info=false, local=true ldq r28, Q_gtmi$_local subq r6, r28, r28 beq r28, 1$ $call op_gvkill, args=<> $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return 1$: subq r3, 1, r28 beq r28, 10$ calls r3, op_srchindx subq sp, 8, sp stq r0, (sp) 10$: calls 1, op_kill $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$kill fgncal_old gtm$kill, gtm$gblkill, gtm$lclkill fgncal_entry gtm$withdraw, syn2, 2, 0 $call fgncal_procarg, set_arg_info=false, local=true ldq r28, Q_gtmi$_local subq r6, r28, r28 beq r28, 1$ $call op_gvzwithdraw, args=<> $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return 1$: subq r3, 1, r28 beq r28, 10$ calls r3, op_srchindx subq sp, 8, sp stq r0, (sp) 10$: calls 1, op_lvzwithdraw $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$withdraw fgncal_old gtm$withdraw, gtm$gblwithdraw, gtm$lclwithdraw $routine gtm$zkill, entry=gtm$zkill_CA, kind=null .base r27, $ls ldq r28, L_gtm$withdraw ; defined by previous fgncal_old macro invocation ldq r27, L_gtm$withdraw+8 jmp r28 $end_routine name=gtm$zkill fgncal_entry gtm$data, syn2, 3, 2 $linkage_section A_op_gvdata: .address op_gvdata $code_section $call fgncal_procarg, set_arg_info=false, local=true ldq r28, Q_gtmi$_local subq r6, r28, r28 beq r28, 1$ ldq r2, A_op_gvdata $call fgncal_dispget, set_arg_info=false, local=true ; doesn't return 1$: subq r3, 1, r28 beq r28, 10$ calls r3, op_srchindx subq sp, 8, sp stq r0, (sp) 10$: $call push_mval, args= mov r0, r4 ldq r0, (sp) addq sp, 8, sp mov r4, r17 ; put return mval underneath lv_val mov r0, r16 $call op_fndata, args= $call fgncal_lclfini, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$data fgncal_old gtm$data, gtm$gbldata, gtm$lcldata fgncal_entry gtm$order, syn2, 4, 2 $linkage_section A_op_gvorder: .address op_gvorder $code_section $call fgncal_procarg, set_arg_info=false, local=true ldq r1, ARG_OFFSET+24(fp) ; direction argument addq r1, 1, r28 beq r28, 0$ ; -1 subq r1, 1, r28 beq r28, 1$ ; 1 $call lib$signal, args= ; second order arg must be -1 or 1 ; shouldn't return 0$: $call prev, set_arg_info=false, local=true ; based on direction, jump to zprevious ; shouldn't return 1$: $call order, set_arg_info=false, local=true ; shouldn't return $end_routine name=gtm$order $routine order, entry=order_ca, kind=null, local=true mov r27, r13 .base r13, $ls ldq r28, Q_gtmi$_local subq r6, r28, r28 beq r28, 1$ ldq r2, A_op_gvorder $call fgncal_dispget, set_arg_info=false, local=true, nonstandard=true ; doesn't return 1$: $call push_mval, args=, nonstandard=true mov r0, r4 subq r3, 1, r3 beq r3, 10$ subq r3, 1, r28 beq r28, 20$ calls r3, op_srchindx subq sp, 8, sp stq r0, (sp) br 20$ 10$: addq sp, 8, sp $call op_fnlvname, args=, nonstandard=true $call fgncal_lclfini, set_arg_info=false, local=true, nonstandard=true ; doesn't return 20$: ldq r0, (sp) ; put dst under src and key arguments ldq r1, 8(sp) addq sp, 16, sp mov r0, r16 mov r1, r17 mov r4, r18 $call op_fnorder, args=, nonstandard=true $call fgncal_lclfini, set_arg_info=false, local=true, nonstandard=true ; doesn't return $end_routine name=order fgncal_entry gtm$gblorder, syn2, 3, 2 $call fgncal_procarg, set_arg_info=false, local=true $call order, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$gblorder $routine gtm$lclorder, entry=gtm$lclorder_ca, kind=null $linkage_section L_gtm$gblorder: .linkage_pair gtm$gblorder $code_section .base r27, $ls ldq r28, L_gtm$gblorder ; N.B. don't modify r26 ldq r27, L_gtm$gblorder+8 jmp r28 ; jump to gtm$gblorder as if it were the entry point invoked $end_routine name=gtm$lclorder fgncal_entry gtm$previous, syn2, 3, 2 $linkage_section A_op_zprevious: .address op_zprevious $code_section $call fgncal_procarg, set_arg_info=false, local=true $call prev, set_arg_info=false, local=true ; shouldn't return $end_routine name=gtm$previous $routine prev, entry=prev_ca, kind=null, local=true mov r27, r13 .base r13, $ls ldq r28, Q_gtmi$_local subq r6, r28, r28 beq r28, 1$ ldq r2, A_op_zprevious $call fgncal_dispget, set_arg_info=false, nonstandard=true ; doesn't return 1$: $call push_mval, args=, nonstandard=true mov r0, r4 subq r3, 1, r3 beq r3, 10$ subq r3, 1, r28 beq r28, 20$ calls r3, op_srchindx subq sp, 8, sp stq r0, (sp) br 20$ 10$: addq sp, 8, sp $call op_fnlvprvname, args=, nonstandard=true ; put return mval underneath lv name $call fgncal_lclfini, set_arg_info=false, local=true, nonstandard=true ; doesn't return 20$: ldq r0, (sp) ; put dst under src and key arguments ldq r1, 8(sp) addq sp, 16, sp mov r0, r16 mov r1, r17 $call op_fnzprevious, args=, nonstandard=true $call fgncal_lclfini, set_arg_info=false, local=true, nonstandard=true ; doesn't return $end_routine name=prev fgncal_old gtm$previous, gtm$gblprevious, gtm$lclprevious fgncal_entry gtm$query, syn2, 3, 2 $linkage_section A_op_gvquery: .address op_gvquery $code_section $call fgncal_procarg, set_arg_info=false, local=true ldq r28, Q_gtmi$_local subq r6, r28, r28 beq r28, 1$ ldq r2, A_op_gvquery $call fgncal_dispget, set_arg_info=false, local=true ; doesn't return 1$: subq sp, 8, sp stq r5, (sp) $call push_mval, args= mov r0, r4 subq sp, 8, sp stq r0, (sp) addq r3, 2, r3 calls r3, op_fnquery $call fgncal_lclfini, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$query fgncal_old gtm$query, gtm$gblquery, gtm$lclquery fgncal_entry gtm$gblnext, syn2, 3, 2 $linkage_section A_op_gvnext: .address op_gvnext $code_section $call fgncal_procarg, set_arg_info=false, local=true ldq r2, A_op_gvnext $call fgncal_dispget, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$gblnext ; NOTE: For lock transactions, the mode is considered part of the key, ; since there can be multiple keys in a lock transaction. ; fgncal_entry gtm$lock, syn1, 2, 0 $call op_unlock, args=<> ldq r0, ARG_OFFSET(fp) and r0, ^Xff, r0 ; number of original arguments bne r0, 100$ $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return 100$: $call op_lkinit, args=<> $call fgncal_procarg, set_arg_info=false, local=true ldq r16, (sp) addq sp, 8, sp $call op_lock, args= subq r0, 1, r28 beq r28, 110$ ldl r22, L_ERR_LCKSTIMOUT ldq r23, A_mumps_status stl r22, (r23) 110$: $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$lock fgncal_entry gtm$inclock, syn1, 2, 0 $call op_lkinit, args=<> $call fgncal_procarg, set_arg_info=false, local=true ldq r16, (sp) addq sp, 8, sp $call op_incrlock, args= subq r0, 1, r28 beq r28, 111$ ldl r22, L_ERR_LCKSTIMOUT ldq r23, A_mumps_status stl r22, (r23) 111$: $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$inclock fgncal_entry gtm$declock, syn1, 1, 0 $call op_lkinit, args=<> $call fgncal_procarg, set_arg_info=false, local=true ldq r16, (sp) addq sp, 8, sp $call op_decrlock, args= $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$declock fgncal_entry gtm$zalloc, syn1, 2, 0 $call op_lkinit, args=<> $call fgncal_procarg, set_arg_info=false, local=true ldq r16, (sp) addq sp, 8, sp $call op_zallocate, args= subq r0, 1, r28 beq r28, 112$ ldl r22, L_ERR_LCKSTIMOUT ldq r23, A_mumps_status stl r22, (r23) 112$: $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$zalloc fgncal_entry gtm$zdealloc, syn1, 1, 0 $call op_lkinit, args=<> $call fgncal_procarg, set_arg_info=false, local=true ldq r16, (sp) addq sp, 8, sp $call op_zdeallocate, args= $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$zdealloc fgncal_entry gtm$lock2, syn3, 3, 0 $call op_lkinit, args=<> $call fgncal_procarg, set_arg_info=false, local=true ldq r16, (sp) ldq r17, 8(sp) addq sp, 16, sp $call op_lock2, args= subq r0, 1, r28 beq r28, 113$ ldl r22, L_ERR_LCKSTIMOUT ldq r23, A_mumps_status stl r22, (r23) 113$: $call fgncal_dispret, set_arg_info=false, local=true $end_routine name=gtm$lock2 fgncal_entry gtm$zdealloc2, syn3, 2, 0 $call op_lkinit, args=<> $call fgncal_procarg, set_arg_info=false, local=true ldq r16, (sp) ldq r17, 8(sp) addq sp, 16, sp $call op_zdealloc2, args= $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$zdealloc2 fgncal_entry gtm$setgbldir, syn0, 1, 0 $call fgncal_procarg, set_arg_info=false, local=true ldq r17, (sp) addq sp, 8, sp lda r16, 22(r31) $call op_svput, args= $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$setgbldir fgncal_entry gtm$ztstart, syn0, 0, 0 $call op_ztstart, args=<> $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$ztstart fgncal_entry gtm$ztcommit, syn0, 1, 0 ldq r28, ARG_OFFSET(fp) subq r28, r7, r28 bge r28, 10$ br bparm 10$: $call op_ztcommit, args= $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$ztcommit fgncal_entry gtm$mval2subsc, syn0, 2, 0 ldq r28, ARG_OFFSET(fp) subq r28, r7, r28 bge r28, 10$ br bparm 10$: $call mval2subsc, args= $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$mval2subsc fgncal_entry gtm$rundown, syn0, 0, 0 $call fgncal_rundown, args=<> $call fgncal_dispret, set_arg_info=false, local=true ; doesn't return $end_routine name=gtm$rundown fgncal_entry gtm$xecute, syn0, 1, 0 ldq r28, ARG_OFFSET(fp) subq r28, r7, r28 bge r28, 10$ br bparm 10$: ldq r11, A_xfer_table ldq r10, A_fgncal_rtn ; procedure descriptor ldq r10, 8(r10) ; entry point from procedure descriptor (=> routine header) $call base_frame, args= $call new_stack_frame, args= $call gtm_savetraps, args=<> $call fgncal_procarg, set_arg_info=false, local=true ldq r16, (sp) ; string to execute addq sp, 8, sp lda r17, 19(r31) ; indir_linetail $call op_commarg, args= ldq r28, A_mdb_condition_handler stq r28, 8(fp) ; establish mdb_condition_handler as condition handler getframe imb ret r26 ; it will go through gtm_ret_code on the way out $end_routine name=gtm$xecute fgncal_entry gtm$zstatus, syn0, 1, 0 ldq r28, ARG_OFFSET(fp) subq r28, r7, r28 bge r28, 10$ br bparm 10$: ldq r28, A_dollar_zstatus $call mval2desc, args=, nonstandard=true ; convert it for caller $call fgncal_dispret, set_arg_info=false, local=true, nonstandard=true ; doesn't return $end_routine name=gtm$zstatus .end fis-gtm-V6.0-003/sr_avms/fgncal_rtn.m640000644000032200000250000000663212201176167016473 0ustar librarygtc .title fgncal_rtn dummy routine header for gtm$xecute G_MSF ; The code PSECT must have the MIX attribute in order to contain data. $CODE$ = "FGNCAL_RTN,QUAD,PIC,CON,REL,LCL,SHR,EXE,RD,MIX,NOWRT" $routine name=fgncal_rtn, entry=fgncal_rtn_ca, kind=stack, - saved_regs=, - standard_prologue=false, data_section_pointer=true $linkage_section L_ERR_GTMCHECK: .long ERR_GTMCHECK $data_section literal_table: .asciz "$FGNXEC" $code_section ; This is a dummy GT.M routine header so this routine can be treated as if ; it had been produced by the GT.M compiler (see rtnhdr.h). jsb: ; There should be no way to enter this code via the procedure descriptor ; but use the jsb field to handle that if it happens. lda sp, -$SIZE(sp) stq r27, (sp) br check ; jsb field full; finish this later .if ne,<.-jsb>,mrt$src_len .error "The dummy routine header jsb size is incorrect; please check it against g_msf.max." .endc src_full_name: .long 0 ; source file name length address_32 0 ; source file name routine_name: .long 7 ; routine name length (sizeof("$FGNXEC") - 1) address_32 $ds ; routine name (dummy) vartab_ptr: .long label_table - $cs ; variable table vartab_len: .word 0 ; variable table length .word 0 ; padding labtab_ptr: .long label_table - $cs ; label table labtab_len: .word 2 ; label table length .word 0 ; padding lnrtab_ptr: .long line_table - $cs ; line table lnrtab_len: .word 1 ; line table length .word 0 ; padding ptext_ptr: .long fgncal_rtn_code - $cs ; pointer to start of actual code checksum: .long 0 compiler_qlf: .long 0 old_rhead_ptr: address_32 0 current_rhead_ptr: address_32 0 temp_mvals: .word 0 temp_size: .word 0 linkage_ptr: address_32 $ls literal_ptr: address_32 $ds ; End of GT.M routine header. .if ne,<.-jsb>,mrt$hdr_size .error "The dummy routine header size is incorrect; please check it against g_msf.max." .endc fgncal_rtn_code: .base r13, $ls ; should be set up by getframe $call opp_ret ; opp_ret shouldn't return; if it does, we have an error br check2 ; skip pseudo prologue check: ; It should never EVER be possible to execute this from the top (jsb). ; First, finish the prologue begun in the jsb field (for debugging purposes) stq r26, $RSA_OFFSET(sp) stq r2, $RSA_OFFSET+8(sp) stq r3, $RSA_OFFSET+16(sp) stq r4, $RSA_OFFSET+24(sp) stq r5, $RSA_OFFSET+32(sp) stq r6, $RSA_OFFSET+48(sp) stq r7, $RSA_OFFSET+56(sp) stq r8, $RSA_OFFSET+64(sp) stq r9, $RSA_OFFSET+72(sp) stq r10, $RSA_OFFSET+80(sp) stq r11, $RSA_OFFSET+88(sp) stq r12, $RSA_OFFSET+96(sp) stq r13, $RSA_OFFSET+104(sp) stq r14, $RSA_OFFSET+112(sp) stq r15, $RSA_OFFSET+120(sp) stq fp, $RSA_OFFSET+128(sp) mov sp, fp $end_prologue ; Set up base register r13 for either path to lib$signal call. mov r27, r13 .base r13, $ls ; Next, complain bitterly about the invalid invocation. check2: $call lib$signal, args= ; lib$signal should never return, but if it does, don't execute data: $return ; Standard variable (null), label, and line tables for end of GT.M object module. ; Variable table would go here if there were one. label_table: ; initialize the lab_tabent entry .long 0 address_32 0 .long lte - fgncal_rtn_ca line_table: .long fgncal_rtn_code - fgncal_rtn_ca ; line 0 lte: .long fgncal_rtn_code - fgncal_rtn_ca ; line 1 $end_routine name=fgncal_rtn .end fis-gtm-V6.0-003/sr_avms/find_line_call.c0000644000032200000250000001043412201176175017106 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "axp_registers.h" #include "axp_gtm_registers.h" #include "axp.h" #include "xfer_enum.h" #include /* Needed by zbreak.h */ #include "zbreak.h" /* Numeric literals are pushed on the stack or loaded into argument registers with a combination of the following instructions: */ #define PUSH_NUM_LIT1 (ALPHA_INS_LDAH) #define PUSH_NUM_LIT2 (ALPHA_INS_LDA) #define PUSH_NUM_LIT3 (ALPHA_INS_STQ | (GTM_REG_ACCUM << ALPHA_SHIFT_RA) | (ALPHA_REG_SP << ALPHA_SHIFT_RB)) /* The first two instructions set up a procedure descriptor and transfer address; the third makes the call. */ #define LOAD_XFER_ADDR1 (ALPHA_INS_LDL | (ALPHA_REG_PV << ALPHA_SHIFT_RA) | (GTM_REG_XFER_TABLE << ALPHA_SHIFT_RB)) #define LOAD_XFER_ADDR2 (ALPHA_INS_LDQ | (ALPHA_REG_RA << ALPHA_SHIFT_RA) | (ALPHA_REG_PV << ALPHA_SHIFT_RB) \ | ((8 & ALPHA_MASK_DISP) << ALPHA_SHIFT_DISP)) #define XFER_CALL (ALPHA_INS_JSR | (ALPHA_REG_RA << ALPHA_SHIFT_RA) | (ALPHA_REG_RA << ALPHA_SHIFT_RB)) /* find_line_call searches through machine instructions starting at the address corresponding to the * beginning of a MUMPS statement looking for a call to any of op_linestart, op_zbstart, op_linefetch, * or op_zbfetch. It will return the address of the displacement field of the instruction that indexes * to the desired runtime routine in order that its caller may examine or change that field. * * find_line_call will skip over any number of numeric literal arguments to op_linefetch or op_zbfetch * in its search for one of the desired calls. If it doesn't find any, it will return the address of * the offset field of the instruction to which addr points. * * entry * addr address of beginning of MUMPS statement * * exit * returns address of displacement field containing offset into the transfer table in the * instruction that refers to the transfer table */ zb_code *find_line_call(void *addr) { uint4 *call_addr; uint4 *xfer_addr; short xfer_offset; call_addr = addr; if ((LOAD_XFER_ADDR1 == (*call_addr & ~(ALPHA_MASK_DISP << ALPHA_SHIFT_DISP))) && (LOAD_XFER_ADDR2 == *(call_addr + 1))) { /* It's a transfer table load. */ xfer_addr = call_addr; xfer_offset = (*xfer_addr >> ALPHA_SHIFT_DISP) & ALPHA_MASK_DISP; call_addr += 2; assert(XFER_CALL == *call_addr); return ((zb_code *)addr); } /* Locate and skip over series of operand pushes. This is not rigorous, but should catch a series of * numeric constant arguments: */ xfer_addr = call_addr; if ( (PUSH_NUM_LIT1 == (*call_addr & (ALPHA_MASK_OP << ALPHA_SHIFT_OP))) || (PUSH_NUM_LIT2 == (*call_addr & (ALPHA_MASK_OP << ALPHA_SHIFT_OP))) || (PUSH_NUM_LIT3 == (*call_addr & ~(ALPHA_MASK_DISP << ALPHA_SHIFT_DISP)))) { while ( (PUSH_NUM_LIT1 == (*call_addr & (ALPHA_MASK_OP << ALPHA_SHIFT_OP))) || (PUSH_NUM_LIT2 == (*call_addr & (ALPHA_MASK_OP << ALPHA_SHIFT_OP))) || (PUSH_NUM_LIT3 == (*call_addr & ~(ALPHA_MASK_DISP << ALPHA_SHIFT_DISP)))) call_addr++; /* If it's not a transfer table call, give up. */ if ( (LOAD_XFER_ADDR1 != (*call_addr & ~(ALPHA_MASK_DISP << ALPHA_SHIFT_DISP))) || (LOAD_XFER_ADDR2 != *(call_addr + 1)) || (XFER_CALL != *(call_addr + 2))) return ((zb_code *)addr); xfer_addr = call_addr; xfer_offset = (*call_addr >> ALPHA_SHIFT_DISP) & ALPHA_MASK_DISP; call_addr += 3; if ((xf_linefetch * SIZEOF(int4) != xfer_offset) && (xf_zbfetch * SIZEOF(int4) != xfer_offset)) return ((zb_code *)addr); } else if ((LOAD_XFER_ADDR1 == (*call_addr & ~(ALPHA_MASK_DISP << ALPHA_SHIFT_DISP))) && (LOAD_XFER_ADDR2 == *(call_addr + 1)) && (XFER_CALL == *(call_addr + 2))) { xfer_addr = call_addr; xfer_offset = (*call_addr >> ALPHA_SHIFT_DISP) & ALPHA_MASK_DISP; if ((xf_linestart * SIZEOF(int4) != xfer_offset) && (xf_zbstart * SIZEOF(int4) != xfer_offset)) return ((zb_code *)addr); } return ((zb_code *)xfer_addr); } fis-gtm-V6.0-003/sr_avms/g_msf.max0000644000032200000250000000417712201176167015632 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .macro G_MSF ; msf - offsets into the GT.M MUMPS stack frame ; ; note: these offsets correspond to fields in the stack frame defined in stack_frame.h msf$rvector_off = 0 msf$l_symtab_off = 4 msf$mpc_off = 8 msf$ctxt_off = 12 msf$literal_ptr_off = 16 msf$temps_ptr_off = 20 msf$vartab_ptr_off = 24 msf$vartab_len_off = 28 msf$temp_mvals = 30 msf$old_frame_off = 32 msf$typ_off = 36 msf$flags_off = 38 msf$for_ctrl_stack = 40 msf$frame_size = 48 ; Stack frame type (msf$typ_off) field bits (see also stack_frame.h): sft_count = ^X01 ; frame counts (real code) or doesn't (transcendental code) sft_dm = ^X02 ; direct mode sft_rep_op = ^X04 ; frame to replace opcode (zbreak has already occurred) sft_zbrk_act = ^X08 ; action frame for zbreak sft_dev_act = ^X10 ; action frame for device error handler sft_ztrap = ^X20 ; ztrap frame sft_zstep_act = ^X80 ; action frame for a zstep sft_zintr = ^X100 ; $zinterrupt frame ; Stack frame flag (msf$flags_off) bits (see in stack_frame.h) sff_indce = ^X01 ; frame requires indr cache entry cleanup in op_unwind sff_etrap_err = ^X10 ; A $ETRAP style error occurred while in this frame. ; mrt - offsets into the GT.M object file routine header ; ; note: these offsets correspond to fields in the routine header defined in rtnhdr.h mrt$jsb = 0 mrt$src_len = 12 mrt$src_addr = 16 mrt$rtn_len = 20 mrt$rtn_addr = 24 mrt$var_ptr = 28 mrt$var_len = 32 mrt$lab_ptr = 36 mrt$lab_len = 40 mrt$lnr_ptr = 44 mrt$lnr_len = 48 mrt$ptxt_ptr = 52 mrt$checksum = 56 mrt$compiler_qlf = 60 mrt$oldr_ptr = 64 mrt$curr_ptr = 68 mrt$tmp_mv = 72 mrt$tmp_sz = 74 mrt$lnk_ptr = 76 mrt$lit_ptr = 80 mrt$hdr_size = 84 .endm fis-gtm-V6.0-003/sr_avms/get_registers.m640000644000032200000250000000032312201176167017213 0ustar librarygtc .title get_registers ; get_registers - copy machine registers into argument array ; ; This is a stub. $routine name=get_registers,entry=get_registers_ca,kind=null ret r26 $end_routine name=get_registers fis-gtm-V6.0-003/sr_avms/getframe.max0000644000032200000250000000265012201176167016323 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001, 2011 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Restore registers from the current GT.M MUMPS stack frame. ; Note: This macro puts the code address into some register; you may specify one or it will default to r26. .macro getframe reg=r26, ?label ; A_frame_pointer must be address of quadword containing the address of frame_pointer ldq r12, A_frame_pointer ldl r12, (r12) lda r8, msf$flags_off(r12) ldq_u r9, (r8) extbl r9, r8, r9 and r9, sff_etrap_err, r9 beq r9, label $call ERROR_RETURN, set_arg_info=false, nonstandard=true ldq r12, A_frame_pointer ldl r12, (r12) label: ldl r8, msf$l_symtab_off(r12) ldl r9, msf$temps_ptr_off(r12) ldl r13, msf$ctxt_off(r12) ldl r14, msf$literal_ptr_off(r12) ldl reg, msf$mpc_off(r12) .endm fis-gtm-V6.0-003/sr_avms/gtm$defaults.m640000644000032200000250000000151512201176167016734 0ustar librarygtc;**************************************************************** ;* * ;* Copyright 2002, 2011 Fidelity Information Services, Inc * ;* * ;* This source code contains the intellectual property * ;* of its copyright holder(s), and is made available * ;* under a license. If you do not know the terms of * ;* the license, please stop and do not read further. * ;* * ;****************************************************************/ .TITLE GTM$DEFAULTS GTM$USER_STACK_SIZE == 256 * 1024 GTM$USER_SPAWN_FLAG == 0 GTM$USER_INDRCACHE_SIZE == 32 GTM$USER_STRPL_SIZE == 20480 GTM$USER_IO_TIMER == 3300000 GTM$USER_WRITE_FILTER == 0 GTM$SPECIAL_INPUT == ^X000000 GTM$UNDEF_INHIBIT == 0 GTM$CTRLC_ENABLE == 1 GTM$BREAK_MESSAGE_MASK == 15 GTM$LOWER_CASE_LABELS == 1 GTM$LVNULLSUBS == 1 GTM$ZDIR_FORM == 0 GTM$ZDATE_FORM == 0 .END fis-gtm-V6.0-003/sr_avms/gtm$fgncall.m640000644000032200000250000001447512201176167016544 0ustar librarygtc .title gtm$fgncall perform calls from foreign languages to MUMPS G_MSF base_frame MAXARGS = 32 ; maximum number of arguments allowed ; Offsets from frame pointer into stack extension area. output = -8 label = output - 8 routine = label - 8 argcnt = routine - 8 arglist = argcnt - 8 save_sp = arglist - 8 end = save_sp - 8 ARG_COPY = end - <*4> ; argument copy area (one extra space for argument count) ; Offsets from stack pointer into stack extension area. args = 0 ; address of local array [0:MAXARGS] into which fgn_parms builds its argument list retval = MAXARGS*4 ; address of last element in the array into which fgn_parms puts return value address ; Invoked via entry created by MUMPS_BINDING macro. ; ; Arguments: ; r16 address of MUMPS routine ; r17 address of MUMPS label ; r18 does MUMPS routine return a value (is it a function)? 1 => yes, 0 => no ; r19 address of argument list (starting with argument count) ; r20 = 0, if the MUMPS label has been resolved by VMS linker ; = length of the MUMPS label, if it hasn't been resolved by VMS linker ; The code PSECT must have the MIX attribute in order to contain data. $CODE$ = "GTM$FGNCALL,QUAD,PIC,CON,REL,LCL,SHR,EXE,RD,MIX,NOWRT" $routine name=gtm$fgncall, entry=gtm$fgncall_ca, kind=stack, - saved_regs=<%string(base_frame_regs)>, - base_reg_is_fp=true, data_section_pointer=true - rsa_offset=RSA_OFFSET, size=STACK_SIZE, - standard_prologue=false, handler=GTM$DYN_CH, synch_exceptions=true .if ne,$SIZE,STACK_SIZE .error "The stack size computed by $routine (%integer($SIZE)) differs from that defined in the - base_frame macro (%integer(STACK_SIZE))." .endc $linkage_section A_line1: .address line1 A_var_on_cstack_ptr: .address var_on_cstack_ptr L_ERR_GTMCHECK: .long ERR_GTMCHECK $data_section literal_table: .asciz "$FGNFNC" $code_section jsb: .base r27, $ls ; the no-ops were introduced so that this code remains the same size ; at that of a generated mumps object file. nop nop jsr r0, (r0) ; gtm$main sets up the actual frame $end_prologue .if ne,<.-$cs>,mrt$src_len .error "The dummy routine header jsb size is incorrect; please check it against g_msf.max." .endc src_full_name: .long 0 ; source file name length address_32 0 ; source file name routine_name: .long 7 ; routine name length (sizeof("$FGNFNC") - 1) address_32 $ds ; routine name (dummy) vartab_ptr: .long label_table - $cs ; variable table vartab_len: .word 0 ; variable table length .word 0 ; padding labtab_ptr: .long label_table - $cs ; label table labtab_len: .word 1 ; label table length .word 0 ; padding lnrtab_ptr: .long line_table - $cs ; line table lnrtab_len: .word 2 ; line table length .word 0 ; padding ptext_ptr: .long gtm$fgncode - $cs ; pointer to start of actual code checksum: .long 0 compiler_qlf: .long 0 old_rhead_ptr: address_32 0 current_rhead_ptr: address_32 0 temp_mvals: .word 0 temp_size: .word 0 linkage_ptr: address_32 $ls literal_ptr: address_32 $ds ; End of GT.M routine header. .if ne,<.-jsb>,mrt$hdr_size .error "The dummy routine header size is incorrect; please check it against g_msf.max." .endc gtm$fgncode: ; gtm$main, among other things, creates a GT.M MUMPS stack frame for this routine; ; for which this is the entry point to which control is transferred by a ; "getframe/ret r26" sequence. .base r13, $ls ; also set up by getframe/ret sequence ; Reset var_on_cstack_ptr for the new M environment ldq r28, A_var_on_cstack_ptr stl r31, (r28) ; var_on_cstack_ptr = NULL; ; Save the current error trap and NEW it before any error could possibly occur. $call gtm_savetraps, args=<>, set_arg_info=false ; Restore argument info and argument registers (saved here by gtm$main). ldq r20, $SIZE-16(fp) ; MUMPS label length (0 if resolved by LINK) beq r20, resolved $call fgn_resolve_lab, args=<$SIZE-48(fp)/Q, r20, $SIZE-40(fp)/Q> stq r0, $SIZE-40(fp) resolved: ldq r16, $SIZE-48(fp) ; A(MUMPS routine) ldq r17, $SIZE-40(fp) ; A(MUMPS label) ldq r18, $SIZE-32(fp) ; output? ldq r19, $SIZE-24(fp) ; A(arg list to interface) stq r16, routine(fp) stq r17, label(fp) stq r18, output(fp) stq r19, arglist(fp) stq sp, save_sp(fp) ldq r28, A_line1 stl r28, msf$mpc_off(r12) line1: ldq r0, arglist(fp) ; original argument list lda r1, ARG_COPY(fp) ldl r22, (r0) ; number of arguments in arglist ; Copy arguments from original arglist to array of longs (or address_32's). 1$: ldq r28, (r0) stl r28, (r1) lda r0, 8(r0) lda r1, 4(r1) subq r22, 1, r22 bge r22, 1$ ; one extra iteration to include the argument count $call fgn_parms, args= stq r0, argcnt(fp) bgt r0, 5$ ; if any arguments ldq r28, output(fp) bgt r28, 20$ ; if it's a function $call op_extcall, args= br after_call ; Extend stack and copy arguments returned from fgn_parms to extension. 5$: ; Put first argument into appropriate register, then deal with rest. ldl r21, (sp) mov #MAXARGS+1, r22 ; copy entire array, including extra space at end for retval lda r0, 4(sp) ; start of arguments that don't fit into argument registers addq r22, 1, r23 ; round up to even double-quadword boundary bic r23, 1, r23 subq r31, r23, r28 ; negate because s8subq works backwards s8addq r28, sp, sp mov sp, r1 10$: ldl r28, (r0) stq r28, (r1) lda r0, 4(r0) lda r1, 8(r1) subq r22, 1, r22 bgt r22, 10$ 20$: ldq r22, save_sp(fp) $call op_extexfun, args=, set_arg_info=false after_call: ldq sp, save_sp(fp) ldl r16, retval(sp) beq r16, gohome $call op_exfunret, args= ldq r17, arglist(fp) ldq r17, 8(r17) ldl r16, retval(sp) $call mval2desc, args= gohome: ; Leaving new M environment; reset var_on_cstack_ptr for the old M environment ldq r28, A_var_on_cstack_ptr stl r31, (r28) ; var_on_cstack_ptr = NULL; $begin_epilogue $call opp_ret, set_arg_info=false ; shouldn't return $call lib$signal, args= ; also shouldn't return ; Standard variable (null), label, and line tables for end of GT.M object module. ; Variable table would go here if there were one. label_table: ; initialize the lab_tabent entry .long 0 address_32 0 .long lte - $cs line_table: .long gtm$fgncode - $cs ; line 0 lte: .long line1 - $cs ; line 1 $end_routine name=gtm$fgncall .end fis-gtm-V6.0-003/sr_avms/gtm_code_address.m640000644000032200000250000000057412201176167017643 0ustar librarygtc .title gtm_code_address return code address for a routine given its procedure descriptor address ; gtm$code_address ; ; entry: ; a0 (r16) address of procedure descriptor ; ; exit: ; r0 address of entry point indicated by procedure descriptor $routine name=gtm$code_address,entry=gtm$code_address_ca,kind=null ldq r0, 8(r16) ret r26 $end_routine name=gtm$code_address fis-gtm-V6.0-003/sr_avms/gtm_dyn_ch.m640000644000032200000250000000550012201176167016462 0ustar librarygtc .title GTM_DYN_CH dynamic condition handler interface ; WARNING: This condition handler uses an undocumented convention ; and library routine in Alpha VMS in order to emulate dynamic ; condition handlers for Alpha assembly language (MACRO) routines ; and GT.M-generated object modules. ; ; This mechanism should be semantically identical to that of VAX VMS, ; whereby the address of the condition handler for a frame could be ; found in the longword at 0(FP) for that frame (0 => no condition ; handler in effect) at the time the condition occurred. This ; allowed the condition handler for a frame to be changed by changing ; the value of that longword. ; ; In order for a procedure P to support dynamic condition handler ; specifications for its activation stack frames: ; ; 1. P must be a stack frame procedure ; ; 2. P must establish GTM$DYN_CH as its static condition ; handler (see OpenVMS Calling Standard and OpenVMS ; Programming Concepts Manual) ; ; 3. P must reserve the quadword at 8(FP) for the address ; of the procedure value of the currently-active condition ; handler; this quadword should be initialized to zero ; (indicating no condition handler active) or to the ; address of a real procedure value during the entry ; prologue before setting FP to ensure a valid value is ; always present. ; ; 4. It is possible P should also reserve the quadword at ; 16(FP), although it need not be initialized. ; ; It may be necessary to modify this at some future Alpha VMS ; operating system release to conform to any changes in the condition ; handler conventions. In this instance, compile the following VAX ; MACRO program with: ; ; macro/migration/machine/lis ; ; and examine the resulting .LIS file to determine how the static ; condition handler works (use it as a basis for the changes to ; GTM$DYN_CH) and where to store the address of the dynamically- ; specified condition handler (mdb_condition_handler in the example): ; ; .title zero_fp ; ; .psect zero_fp pic,usr,rel,gbl,shr,exe,rd,nowrt,novec,quad ; ; .call_entry preserve=all,label=zero_fp ; movl mdb_condition_handler, 0(fp) ; ret ; .end $linkage_section l_ots$call_proc: .linkage_pair OTS$CALL_PROC $routine name=gtm$dyn_ch,entry=gtm$dym_ch_ca,kind=null .base r27, $ls ldq r28, 8(r17) ; 8(a1) = MCH_FRAME in the condition handler mechanism array (second argument) ldl r28, 8(r28) ; 8(establisher's FP) = A(currently established condition handler for that frame) beq r28, no_handler mov r28, r23 ; t2 <- A(condition handler to invoke) ldq r28, l_ots$call_proc ; N.B., don't modify caller's r26 bis r31, 1, r24 ; t3 <- 1 lda r27, l_ots$call_proc+8 jmp r28 ; goto OTS$CALL_PROC no_handler: ; no established condition handler for that frame lda r0, 2328(r31) ; r0 <- SS$_RESIGNAL ret r26 $end_routine name=gtm$dyn_ch fis-gtm-V6.0-003/sr_avms/gtm_main.m640000644000032200000250000001713412201176167016150 0ustar librarygtc;**************************************************************** ;* * ;* Copyright 2002, 2012 Fidelity Information Services, Inc * ;* * ;* This source code contains the intellectual property * ;* of its copyright holder(s), and is made available * ;* under a license. If you do not know the terms of * ;* the license, please stop and do not read further. * ;* * ;****************************************************************/ .title gtm_main dispatch code for run-time system G_MSF base_frame $CODE$ = "GTM$INIT,QUAD,PIC,CON,REL,LCL,SHR,EXE,NOWRT" $DATA$ = "GTM$VECTOR,OCTA,PIC,OVR,REL,LCL,NOSHR,NOEXE,WRT" $LINK$ = "GTM$LINK,OCTA,NOPIC,CON,REL,LCL,NOSHR,NOEXE,WRT" $data_section gtm_vector: argcnt: .long rtn_start: address_32 start rtn_end: address_32 end zctable_start: address_32 gtm$startzc zctable_end: address_32 gtm$endzc zcpack_start: address_32 gtm$startzcpack zcpack_end: address_32 gtm$endzcpack vax_fp: .long 0 xf_table: .long 0 frm_ptr: .long 0 base_addr: .long 0 gtm_main_inaddr: address_32 gtm$main user_stack_size: .long GTM$USER_STACK_SIZE user_spawn_flag: .long GTM$USER_SPAWN_FLAG user_indrcache_size: .long GTM$USER_INDRCACHE_SIZE user_strpl_size: .long GTM$USER_STRPL_SIZE user_io_timer: .long GTM$USER_IO_TIMER user_write_filter: .long GTM$USER_WRITE_FILTER special_input: .long GTM$SPECIAL_INPUT undef_inhib: .long GTM$UNDEF_INHIBIT ctrlc_enable: .long GTM$CTRLC_ENABLE break_message_mask: .long GTM$BREAK_MESSAGE_MASK labels: .long GTM$LOWER_CASE_LABELS lvnullsubs: .long GTM$LVNULLSUBS zdir_form: .long GTM$ZDIR_FORM zdate_form: .long GTM$ZDATE_FORM sysid: address_32 gtm_sysid_mstr dlr_truth: .long 0 gtm_vector_end = . gtm_sysid_mstr: .long 9 ;These lines address_32 gtm_sysid ; construct gtm_sysid: .ascii "gtm_sysid" ; an mstr ; These dummy PSECT's will be sorted (alphabetically) by the linker ; to delimit the beginning and end of the initial routines name ; (rtn_tables) table. In order for this to work, they must have the ; same significant attributes as those of the PSECT generated by ; create_object_file (in obj_file.c) and must have alignment requirements ; no more restrictive than those of rtn_tables. ; GTM$R - beginning of initial routine tables .psect gtm$r pic,rel,gbl,noshr,noexe,rd,wrt,novec,long NUL = ^X00 DEL = ^X7F start: .long 8 ; length of start_rtn_name address_32 start_rtn_name .long 0 ; dummy address ; GTM$RZZZZZZZZZZZZZZZZZZZZZZZZZZ - end of initial routine tables plus some room for expansion .psect gtm$rzzzzzzzzzzzzzzzzzzzzzzzzzz pic,rel,gbl,noshr,noexe,rd,wrt,novec,long end: .long 8 ; length of end_rtn_name address_32 end_rtn_name .long 0 ; dummy address .blkl 17 * 3 ; extra room for expansion (FREE_RTNTBL_SPACE * (sizeof(rtn_tables)/sizeof(long))) (BYPASSOK) .psect gtm$rtn_literals pic,rel,gbl,shr,noexe,rd,nowrt,novec,quad start_rtn_name: ; name guaranteed to sort before all others .ascii .align quad ; so the next name starts at 8-byte boundary end_rtn_name: ; name guaranteed to sort after all others .ascii ; gtm$main - GT.M initialization interface ; ; The routine header for all GT.M object files contains code to transfer control ; to gtm$main. This code executes first whenever the GT.M object file is invoked ; by VMS (e.g., as the first module in an executable image) in order to set up ; the Alpha stack frame for GT.M and to ensure gtm$startup gets called to initialize ; the GT.M environment properly. ; ; Dynamically-linked GT.M object modules or those not the first to execute are ; invoked at the address following the routine header and, so, do not invoke gtm$main. ; ; gtm$main is invoked by the instruction sequence (see create_object_file in obj_file.c): ; ldq r0, gtm$main_linkage_pair(r27) ; ldq r1, gtm$main_linkage_pair+8(r27) ; jmp r0, (r0) ; so that gtm$main can execute in its caller's stack frame (and initialize it). ; ; Entry: ; r0 return address in gtm$main's GT.M caller (just after jsb field in routine header) ; r1 address of gtm$main's procedure descriptor $routine gtm$main, entry=gtm$main_ca, kind=stack, - saved_regs=<%string(base_frame_regs)>, - base_reg_is_fp=true, data_section_pointer=true, - rsa_offset=RSA_OFFSET, size=STACK_SIZE, - standard_prologue=false, handler=GTM$DYN_CH, synch_exceptions=true create_base_frame ; special prologue code + extend stack for argument push area mov r1, r13 .base r13, $ls ; init_gtm (, ) mov ^x0, r18 ; indicate that this is not a DAL case $call init_gtm, local=true, nonstandard=true, set_arg_info=false, scratch_regs=, args= ldq r22, $dp .base r22, $ds ldl r10, dlr_truth ldl r11, xf_table ldl r12, frm_ptr ldl r8, msf$l_symtab_off(r12) ldl r9, msf$temps_ptr_off(r12) ldl r28, msf$rvector_off(r12) ; get routine header of GT.M MUMPS routine to invoke ldl r13, mrt$lnk_ptr(r28) ; linkage Psect address not initialized by init_gtm -- obtain from routine header stl r13, msf$ctxt_off(r12) ldl r14, mrt$lit_ptr(r28) ; literal Psect address not initialized by init_gtm -- obtain from routine header stl r14, msf$literal_ptr_off(r12) ldl r26, msf$mpc_off(r12) ; Don't do a normal $return; leave stack unchanged. ; begin pseudo-epilogue $begin_epilogue trapb ; synchronize exceptions ret r26 $end_epilogue ; end pseudo-epilogue $end_routine name=gtm$main ; init_gtm - invoke gtm$startup to initialize GT.M ; ; init_gtm initializes some fields in the startup vector, gtm_vector, ; and then invokes gtm$startup to complete GT.M environment ; initialization. ; ; args a0 (r16) - return address of GT.M caller ; For a GT.M object module, this will be the ; address immediately following the call to ; gtm$main and will be in the routine header. ; For a foreign-language routine, this should ; have been set to zero by gtm$init. ; ; a1 (r17) - fp of condition handler ; This is the frame pointer of the stack frame ; that will contain the condition handler address. ; For GT.M objects that call gtm$main, this will be ; the first-invoked object module. ; For foreign-language calls, this will be the ; stack from for gtm$init. ; ; a2 (r18) - flag that indicates whether this function was ; invoked from gtm$main (0) or gtm$init (1) $routine name=init_gtm, entry=init_gtm_ca, local=true, - standard_prologue=true, kind=stack, - base_reg_is_fp=true, saved_regs=, - data_section_pointer=true .base r27, $ls ldq r22, $dp .base r22, $ds stl r16, base_addr addq r17, 8, r28 ; add 8 to point to address of handler stl r28, vax_fp $call gtm$startup, args= ; second parameter indicates whether this is DAL or not $return $end_routine name=init_gtm ; gtm$init - interface to GT.M for foreign-language routines ; ; Foreign-language (non-GT.M) programs that wish to invoke GT.M ; routines should call gtm$init first to invoke the GT.M initialization ; code. $linkage_section A_LIB$SIG_TO_RET: .address LIB$SIG_TO_RET $routine name=gtm$init, entry=gtm$init_ca, standard_prologue=true, kind=stack, - base_reg_is_fp=true, rsa_offset=24, saved_regs=, - handler=GTM$DYN_CH, synch_exceptions=true mov r27, r13 .base r13, $ls ldq r28, A_LIB$SIG_TO_RET stl r28, 8(fp) ; establish LIB$SIG_TO_RET as handler mov ^x1, r18 ; indicate that this is a DAL case $call init_gtm, local=true, args= lda r0, 1(r31) ; return success $return $end_routine name=gtm$init .end fis-gtm-V6.0-003/sr_avms/gtm_memmove.c0000644000032200000250000000257412201176167016507 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* * --------------------------------------------------- * memmove() - Move memory. * This routine may replace any existing memcpy() * calls. It correctly handles overlapping memory * regions. * * Arguments: * same as memcpy() * pdest - pointer to destination * psrc - pointer to source * cnt - # of bytes to copy * Return: * pointer to destination * --------------------------------------------------- */ #include "mdef.h" char_ptr_t gtm_memmove(char_ptr_t pdest, char_ptr_t psrc, int cnt) { register char_ptr_t src, dst; assert((0 <= cnt) && (cnt <= MAXPOSINT4)); /* nothing beyond max positive int4 allowed */ src = psrc; dst = pdest; if (cnt && dst != src) { if (src < dst && src + cnt > dst) { /* Overlapping region, downward copy, copy backwards */ dst += cnt; src += cnt; while (cnt-- > 0) *--dst = *--src; } else { while (cnt-- > 0) *dst++ = *src++; } } return (pdest); } fis-gtm-V6.0-003/sr_avms/gtm_ret_code.m640000644000032200000250000000252312201176167017004 0ustar librarygtc .title gtm_ret_code base_frame $routine gtm_ret_code, entry=gtm_ret_code_ca, kind=stack, - saved_regs=<%string(base_frame_regs)>, - rsa_offset=RSA_OFFSET, size=STACK_SIZE, - standard_prologue=false, base_reg_is_fp=true, rsa_offset=RSA_OFFSET .if ne,$SIZE,STACK_SIZE .error "The stack frame size computed by $routine (%integer($SIZE)) differs from that defined in the base_frame - macro (%integer(STACK_SIZE))." .endc $linkage_section A_frame_pointer: .address frame_pointer A_msp: .address msp A_mumps_status: .address mumps_status ; Since gtm_ret_code executes in the machine stack frame set up by gtm$main, it need not set ; up the stack frame and because gtm_ret_code can only be invoked via a getframe/ret sequence, ; r13 has the address of the procedure descriptor, not r27. $code_section .base r13, $ls $end_prologue stq r31, 8(fp) ; clear pointer to condition handler address $call op_unwind, set_arg_info=false, nonstandard=true ldq r0, A_msp ldl r28, (r0) ldq r1, A_frame_pointer ldl r22, (r28) stl r22, (r1) ; frame_pointer = msp lda r28, 4(r28) stl r28, (r0) ; msp += 4 ldq r28, A_mumps_status ldl r0, (r28) ; return code $return ; use standard $return macro to ensure epilogue uses values from the ; $routine macro as defined in the base_frame macro $end_routine name=gtm_ret_code .end fis-gtm-V6.0-003/sr_avms/gtm_zc.m640000644000032200000250000000065612201176167015641 0ustar librarygtc .title gtm_zc GTM ZCALL PSECT DEFINITIONS .psect gtm$zcalltabaaa pic,ovr,rel,gbl,shr,noexe,rd,nowrt,novec,long .long 0 gtm$startzc:: .psect gtm$zcalltabaac pic,ovr,rel,gbl,shr,noexe,rd,nowrt,novec,byte gtm$endzc:: .byte 0 .psect gtm$zcallpackaa pic,ovr,rel,gbl,shr,noexe,rd,nowrt,novec,long .long 0 gtm$startzcpack:: .psect gtm$zcallpackac pic,ovr,rel,gbl,shr,noexe,rd,nowrt,novec,byte gtm$endzcpack:: .byte 0 .end fis-gtm-V6.0-003/sr_avms/gtmi$def.m640000644000032200000250000000041412201176167016031 0ustar librarygtc .title gtmi$def definitions for gtm external interface gtmi$_global == 1 gtmi$_naked == 2 gtmi$_extgbl == 3 gtmi$_local == 4 gtmi$_extlcl == 5 gtmi$_lock == 6 gtmi$_zalloc == 7 gtmi$_zdealloc== 8 gtmi$_inclock == 9 gtmi$_declock == 10 gtmi$_unlock == 11 .end fis-gtm-V6.0-003/sr_avms/gtmsecplv.m640000644000032200000250000000445012201176167016356 0ustar librarygtc .title gtmsecplv - GTMSECSHR PLV (privileged library vector) ; PLV (privileged library vector) for GTMSECSHR. ; ; This is the Alpha AXP OpenVMS analogue for the VAX VMS PLV in the GT.M VAX source file: KERN_MODE.MAR ; ; NOTE: At the time this was written (10/29/93), the Alpha AXP OpenVMS documentation apparently did not ; match the actual implementation of this feature. In particular, many of the following fields were ; described as 64 bits wide when, apparently, they must be 32 bits wide due to an as-yet-undocumented ; change to VMS. Further, there seemed to be no system-supplied C header files or MACRO macro libraries ; that defined anything useful related to PLV's; if this situation changes, this file should be modified ; to use any system-supplied definitions that prove useful. ; ; References: ; OpenVMS Programming Concepts Manual ; OpenVMS Linker Utility Manual ; ; See also: ; Examples in files whose names start with "UWSS" (for User-Written System Service) in the ; directory SYS$EXAMPLES. Pay special attention to the comments and revision history comments. PLV$C_TYP_CMOD = 1 ; not yet defined in any usable system include file (see $PLVDEF in some future VMS release?) .psect gtmsecplv, QUAD, PIC, CON, LCL, SHR, NOEXE, NOWRT, VEC .long PLV$C_TYP_CMOD ; PLV$L_TYPE .long 0 ; PLV$L_VERSION - system version number (unused) .long /4 ; PLV$L_KERNEL_ROUTINE_COUNT .long 0 ; PLV$L_EXEC_ROUTINE_COUNT address_32 kernel_routine_list ; PLV$PS_KERNEL_ROUTINE_LIST address_32 0 ; PLV$PS_EXEC_ROUTINE_LIST address_32 rundown_dispatch ; PLV$PS_KERNEL_RUNDOWN_HANDLER .long 0 ; reserved address_32 0 ; PLV$PS_RMS_DISPATCHER .long 0 ; reserved .long 0 ; reserved ; NOTE: I believe these addresses need to be in the same order as they appear in the symbol_vector ; definition in the buildsec.com GTMSECSHR linker options file. That may not be the case, but it ; keeping them in the same order will probably not cause problems. kernel_routine_list: address_32 crit_wake address_32 del_sec address_32 init_sec address_32 gtm_enq address_32 gtm_enqw address_32 gtm_deq address_32 gtm_blkast address_32 get_proc_info address_32 init_secshr_addrs address_32 gtm_getlkiw address_32 secshr_db_clnup kernel_routine_list_end: .end fis-gtm-V6.0-003/sr_avms/gtmshrlink.axp0000644000032200000250000000452012201176167016714 0ustar librarygtc!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! ! Copyright 2001, 2013 Fidelity Information Services, Inc ! ! ! ! This source code contains the intellectual property ! ! of its copyright holder(s), and is made available ! ! under a license. If you do not know the terms of ! ! the license, please stop and do not read further. ! ! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! objlib/lib symbol_vector=( - gtm$compile = PROCEDURE, - gtm$startup = PROCEDURE, - gtm$gblget = PROCEDURE, - gtm$gblput = PROCEDURE, - gtm$gblnext = PROCEDURE, - gtm$gblorder = PROCEDURE, - gtm$gblprevious = PROCEDURE, - gtm$gbldata = PROCEDURE, - gtm$gblkill = PROCEDURE, - gtm$gblquery = PROCEDURE, - gtm$lock = PROCEDURE, - gtm$inclock = PROCEDURE, - gtm$declock = PROCEDURE, - gtm$zalloc = PROCEDURE, - gtm$zdealloc = PROCEDURE, - gtm$setgbldir = PROCEDURE, - gtm$ztstart = PROCEDURE, - gtm$ztcommit = PROCEDURE, - gtm$interrupt = PROCEDURE, - gtm$fgncall = PROCEDURE, - gtm$mval2subsc = PROCEDURE, - gtm$gblwithdraw = PROCEDURE, - gtm$lclget = PROCEDURE, - gtm$lclkill = PROCEDURE, - gtm$lclput = PROCEDURE, - gtm$lclwithdraw = PROCEDURE, - gtm$lcldata = PROCEDURE, - gtm$lclquery = PROCEDURE, - gtm$lclorder = PROCEDURE, - gtm$lclprevious = PROCEDURE, - gtm$xecute = PROCEDURE, - gtm$rundown = PROCEDURE, - gtm$get = PROCEDURE, - gtm$kill = PROCEDURE, - gtm$put = PROCEDURE, - gtm$withdraw = PROCEDURE, - gtm$data = PROCEDURE, - gtm$query = PROCEDURE, - gtm$order = PROCEDURE, - gtm$previous = PROCEDURE, - gtm$zkill = PROCEDURE, - gtm$lock2 = PROCEDURE, - gtm$zdealloc2 = PROCEDURE, - gtm$ce_establish = PROCEDURE,- gtm$ce_getinfo = PROCEDURE, - gtm$dyn_ch = PROCEDURE, - gtm_malloc = PROCEDURE, - gtm_free = PROCEDURE, - gtm$zstatus = PROCEDURE - ) gsmatch=lequal,11,0 ! Because the linker creates image sections on a per-cluster ! basis, create a cluster for all of the code Psect's (whose ! pages can be shared among processes) and collect all of the ! code Psect's into it so the pages corresponding to that image ! section can be shared. Note the MACRO/MIGRATION compiler ! names its code Psect "$CODE" (as do most of the VAX compilers), ! while the AXP C compiler and MACRO assembler name their code ! Psect's "$CODE$". cluster = code_clust collect = code_clust,$CODE,$CODE$ fis-gtm-V6.0-003/sr_avms/gtmstopzc.m640000644000032200000250000000137112201176167016403 0ustar librarygtc .TITLE GTMSTOPZC .LIBRARY "GTM$VRT:[PRO]GTMZCALL.MLB" .IDENT "V1.00-1" ; ; ZCALL table and routines for GTMSTOP.M and GTCMSTOP.M ; .EXTERNAL ERR_FORCEDHALT ZCINIT ROUTINE CALLNAME=FORCEX, LINKNAME=SYS$FORCEX, INPUTS=3, OUTPUTS=0 RETURN CLASS=VALUE, TYPE=LONG INPUT TYPE=LONG, MECHANISM=REFERENCE, POSITION=1, QUALIFIER=REQUIRED INPUT TYPE=LONG, MECHANISM=VALUE, POSITION=2, QUALIFIER=CONSTANT, VALUE=0 INPUT TYPE=LONG, MECHANISM=VALUE, POSITION=3, QUALIFIER=CONSTANT, VALUE=ERR_FORCEDHALT ROUTINE CALLNAME=DELPRC, LINKNAME=SYS$DELPRC, INPUTS=2, OUTPUTS=0 RETURN CLASS=VALUE, TYPE=LONG INPUT TYPE=LONG, MECHANISM=REFERENCE, POSITION=1, QUALIFIER=REQUIRED INPUT TYPE=LONG, MECHANISM=VALUE, POSITION=2, QUALIFIER=CONSTANT, VALUE=0 ZCALLFIN .END fis-gtm-V6.0-003/sr_avms/gtmzcall.max0000644000032200000250000003240712201176167016351 0ustar librarygtc; **************************************************************** ; * * ; * Copyright 2001, 2012 Fidelity Information Services, Inc * ; * This source code contains the intellectual property * ; * of its copyright holder(s), and is made available * ; * under a license. If you do not know the terms of * ; * the license, please stop and do not read further. * ; * * ; **************************************************************** ;---------------------------------------------------------------------------------------------------------------------------------- .macro package zcpackage_name .if ge zc$maxpos endrout .endc .if df zcpack_start endpack .endc .macro labelentry cname ; use of this macro is currently suppressed __GTM$ZC'zcpackage_name'.'cname':: .endm zcpack_start = zctalloc zcpack_name = zcvalloc .save_psect local_block .psect gtm$zcallvalues pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,quad . = zcvalloc .ascic "zcpackage_name" zcvalloc = . .psect gtm$zcalltabaab pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,long .restore_psect .endm ;---------------------------------------------------------------------------------------------------------------------------------- .macro routine callname, linkname, inputs=0, outputs=0, outofband=default zc$num_args = inputs + outputs .irp $$tmp, .if b $$tmp .print ;GT.M EXTERNAL CALL FORMAT ERROR: ROUTINE callname, linkname, inputs, outputs .error ;REQUIRED KEYWORD OMITTED .mexit .endc .endr .irp $$tmp, .if lt $$tmp .print ;GT.M EXTERNAL CALL FORMAT ERROR: ROUTINE callname, linkname, inputs, outputs .error ;INPUTS AND OUTPUTS MUST BE >= 0 .mexit .endc .endr .if ndf zc$rout_'outofband .print ;GT.M EXTERNAL CALL FORMAT ERROR: ROUTINE outofband .error ; UNDEFINED OUT-OF-BAND KEYWORD: outofband .mexit .endc .if ge zc$maxpos endrout .endc ;labelentry callname ;this is suppressed until case issues are resolved .align long .word <<<<<2+1+1+4+1+1+1+%length(callname)+2+3>/4>*4>+<8*inputs>+<8*outputs>+1+3>/4>*4 .byte inputs .byte outputs address_32 linkname .byte zc$rout_'outofband .byte 0 ; padding .ascic "callname" zc$maxpos = 0 zc$retlin = 0 zc$ip = 0 zc$op = 0 zc$ips = inputs zc$ops = outputs .endm ;---------------------------------------------------------------------------------------------------------------------------------- .macro return class=status, type .if ne zc$retlin .print ;GT.M EXTERNAL CALL FORMAT ERROR: .error ;RETURN LINE MUST IMMEDIATELY FOLLOW ROUTINE .mexit .endc .irp $$tmp, .if b $$tmp .print ;GT.M EXTERNAL CALL FORMAT ERROR: RETURN class, type .error ;REQUIRED KEYWORD OMITTED .mexit .endc .endr .if ndf zc$retc_'class .print ;GT.M EXTERNAL CALL FORMAT ERROR: RETURN class, type .error ; UNDEFINED RETURN_CLASS KEYWORD: class .mexit .endc .if eq zc$retc_'class - zc$retc_value .if b type .ift .print ;GT.M EXTERNAL CALL FORMAT ERROR: RETURN class, type .error ;REQUIRED KEYWORD OMITTED .mexit .iff .if ndf zc$dtype_'type .print ;GT.M EXTERNAL CALL FORMAT ERROR: RETURN class, type .error ; UNDEFINED RETURN_CLASS KEYWORD: class .mexit .endc .if eq zc$dtype_'type - zc$dtype_string .print ;GT.M EXTERNAL CALL FORMAT ERROR: RETURN class, type .error ;ILLEGAL COMBINATION .mexit .endc .if eq zc$dtype_'type - zc$dtype_h_floating .print ;GT.M EXTERNAL CALL FORMAT ERROR: RETURN class, type .error ;ILLEGAL COMBINATION .mexit .endc .endc .endc .byte zc$retc_'class .byte zc$dtype_'type .align long zc$retlin = 1 .endm ;---------------------------------------------------------------------------------------------------------------------------------- .macro input qualifier=required,type,mechanism,position,value .if eq zc$retlin return .endc .irp $$tmp, .if b $$tmp .print ;GT.M EXTERNAL CALL FORMAT ERROR: INPUT type, mechanism, position .error ;REQUIRED KEYWORD OMITTED .mexit .endc .endr .if ndf zc$dtype_'type .print ;GT.M EXTERNAL CALL FORMAT ERROR: INPUT type, mechanism, position .error ; UNDEFINED INPUT_TYPE KEYWORD: type .mexit .endc .if ndf zc$mech_'mechanism .print ;GT.M EXTERNAL CALL FORMAT ERROR: INPUT type, mechanism, position .error ; UNDEFINED INPUT_MECHANISM KEYWORD: mechanism .mexit .endc .if eq zc$dtype_string - zc$dtype_'type .if ne zc$mech_descriptor - zc$mech_'mechanism .if ne zc$mech_descriptor64 - zc$mech_'mechanism .print ;GT.M EXTERNAL CALL FORMAT ERROR: INPUT type, mechanism, position .error ; ILLEGAL COMBINATION .mexit .endc .endc .endc .if ndf zc$iqual_'qualifier .print ;GT.M EXTERNAL CALL FORMAT ERROR: INPUT type, mechanism, position .error ; UNDEFINED INPUT_QUALIFIER KEYWORD: qualifier .mexit .endc .if idn zc$iqual_block,zc$iqual_'qualifier .print ;GT.M EXTERNAL CALL FORMAT ERROR: INPUT type, mechanism, position .error ; UNSUPPORTED INPUT_QUALIFIER KEYWORD: qualifier .mexit .endc zc$iqual_constant = 1 zc$iqual_optional = 2 zc$iqual_optional_0 = 3 zc$iqual_default = 4 zc$iqual_required = 5 zc$iqual_block = 6 .if le position .print ;GT.M EXTERNAL CALL FORMAT ERROR: INPUT type, mechanism, position .error ; POSITION MUST BE POSITIVE: position .mexit .endc .if lt zc$num_args - position .print ;GT.M EXTERNAL CALL FORMAT ERROR: INPUT type, mechanism, position .error ; POSITION MUST NOT BE GREATER THAN NUMBER OF ARGUMENTS: position, zc$num_args .mexit .endc .byte zc$mech_'mechanism .byte zc$dtype_'type .byte position .byte zc$iqual_'qualifier .if b .ift .if eq zc$iqual_default - zc$iqual_'qualifier .iff .if eq zc$iqual_constant - zc$iqual_'qualifier .iff .long 0 .ift putval type,value .endc .ift putval type,value .endc .iff putval type, .endc zc$ip = zc$ip + 1 .if lt zc$maxpos - position zc$maxpos = position .endc .endm ;---------------------------------------------------------------------------------------------------------------------------------- .macro putval t,val address_32 zcvalloc .save_psect local_block .psect gtm$zcallvalues pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,quad . = zcvalloc .if eq zc$dtype_string - zc$dtype_'t .ift .ascid /val/ .iff .if eq zc$dtype_floating - zc$dtype_'t .ift .f_floating val .iff .'t val .endc .endc zcvalloc = . .psect gtm$zcalltabaab pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,long .restore_psect .endm ;---------------------------------------------------------------------------------------------------------------------------------- .macro output qualifier=required,type,mechanism,position,value .if eq zc$retlin .if eq zc$ips return .endc .endc .if ne zc$ips - zc$ip .print ;GT.M EXTERNAL CALL FORMAT ERROR: .error ;NOT ALL INPUT LINES DEFINED BEFORE OUTPUT .mexit .endc .irp $$tmp, .if b $$tmp .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position .error ;REQUIRED KEYWORD OMITTED .mexit .endc .endr .if ndf zc$dtype_'type .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position .error ; UNDEFINED OUTPUT_TYPE KEYWORD: type .mexit .endc .if ndf zc$mech_'mechanism .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position .error ; UNDEFINED OUTPUT_MECHANISM KEYWORD: mechanism .mexit .endc .if eq zc$dtype_string - zc$dtype_'type .if ne zc$mech_descriptor - zc$mech_'mechanism .if ne zc$mech_descriptor64 - zc$mech_'mechanism .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position .error ; ILLEGAL COMBINATION .mexit .endc .endc .endc .if ndf zc$oqual_'qualifier .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position .error ; UNDEFINED INPUT_QUALIFIER KEYWORD: qualifier .mexit .endc .if le position .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position .error ; POSITION MUST BE POSITIVE: position .mexit .endc .if lt zc$num_args - position .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position .error ; POSITION MUST NOT BE GREATER THAN NUMBER OF ARGUMENTS: position, zc$num_args .mexit .endc .if eq zc$mech_value - zc$mech_'mechanism .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position .error ; OUTPUT_MECHANISM MAY NOT BE BY VALUE .mexit .endc .if eq zc$oqual_'qualifier - zc$oqual_preallocate .if ne zc$dtype_string - zc$dtype_'type .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position .error ; PREALLOCATE QUALIFIER VALID ONLY WITH STRINGS .mexit .endc .if b value .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position .error ; VALUE REQUIRED WITH PREALLOCATE QUALIFIER .mexit .endc .if le value .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position .error ; PREALLOCATE SIZE MUST BE GREATER THAN ZERO .mexit .endc .if eq zc$mech_descriptor - zc$mech_'mechanism .if gt value - 65535 .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position .error ; PREALLOCATE SIZE CANNOT BE GREATER THAN 65535 WITH DESCRIPTOR .mexit .endc .endc .if eq zc$mech_descriptor64 - zc$mech_'mechanism .if gt value - 1048576 .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position .error ; PREALLOCATE SIZE CANNOT BE GREATER THAN 1048576 WITH DESCRIPTOR64 .mexit .endc .endc .endc .byte zc$mech_'mechanism .byte zc$dtype_'type .byte position .byte zc$oqual_'qualifier .if b value .ift .long 0 .iff .long value .endc zc$op = zc$op + 1 .if lt zc$maxpos - position zc$maxpos = position .endc .endm ;---------------------------------------------------------------------------------------------------------------------------------- .macro zcinit .macro labelentry cname ;use of this macro is currently suppressed __GTM$ZC.'cname':: .endm .psect gtm$zcallvalues pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,quad zcvalloc = . .psect gtm$zcalltabaab pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,long zctalloc = . zcdef zc$maxpos = -1 .endm ;---------------------------------------------------------------------------------------------------------------------------------- .macro zcallini .psect gtm$zcallvalues pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,quad zcvalloc = . .psect gtm$zcalltabaab pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,long zctalloc = . zcdef zc$maxpos = -1 .endm ;---------------------------------------------------------------------------------------------------------------------------------- .macro zcallfin .if df zc$maxpos endrout .endc .if df zcpack_start endpack .endc .endm ;---------------------------------------------------------------------------------------------------------------------------------- .macro endrout .if ne zc$ip - zc$ips .print ;GT.M EXTERNAL CALL FORMAT ERROR: .error ;INPUTS DO NOT MATCH INPUT LINES .mexit .endc .if ne zc$op - zc$ops .print ;GT.M EXTERNAL CALL FORMAT ERROR: .error ;OUTPUTS DO NOT MATCH OUTPUT LINES .mexit .endc .if eq zc$ips .if eq zc$ops .if eq zc$retlin return .endc .endc .endc .byte zc$maxpos zc$maxpos = -1 zctalloc = . .endm ;---------------------------------------------------------------------------------------------------------------------------------- .macro endpack .save_psect local_block .psect gtm$zcallpackab pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,long address_32 zcpack_start address_32 zctalloc address_32 zcpack_name .psect gtm$zcalltabaab pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,long .restore_psect .endm ;---------------------------------------------------------------------------------------------------------------------------------- .macro zcdef $dscdef zc$rout_default = 0 ; don't touch out-of-band handling zc$rout_reset = 1 ; set out-of-band handling back to normal zc$retc_ = 0 ; Return classes zc$retc_status = 1 zc$retc_value = 2 zc$retc_ignored = 3 zc$mech_ = 0 ; Argument-passing mechanisms zc$mech_value = 1 zc$mech_reference = 2 zc$mech_descriptor = 3 zc$mech_descriptor64 = 4 zc$dtype_ = 0 ; Native data types zc$dtype_string = DSC$K_DTYPE_T zc$dtype_byte = DSC$K_DTYPE_B zc$dtype_byteu = DSC$K_DTYPE_BU zc$dtype_word = DSC$K_DTYPE_W zc$dtype_wordu = DSC$K_DTYPE_WU zc$dtype_long = DSC$K_DTYPE_L zc$dtype_longu = DSC$K_DTYPE_LU zc$dtype_quad = DSC$K_DTYPE_Q zc$dtype_floating = DSC$K_DTYPE_F zc$dtype_double = DSC$K_DTYPE_G zc$dtype_g_floating = DSC$K_DTYPE_G zc$dtype_h_floating = DSC$K_DTYPE_H zc$iqual_ = 0 ; Input argument qualifiers zc$iqual_constant = 1 zc$iqual_optional = 2 zc$iqual_optional_0 = 3 zc$iqual_default = 4 zc$iqual_required = 5 zc$iqual_block = 6 zc$oqual_ = 0 ; Output argument qualifiers zc$oqual_required = 1 zc$oqual_dummy = 2 zc$oqual_preallocate = 3 .endm ;---------------------------------------------------------------------------------------------------------------------------------- ; create 32-bit address item .macro address_32 item .long item .endm address_32 fis-gtm-V6.0-003/sr_avms/i2s.mar0000644000032200000250000000157412201176167015224 0ustar librarygtc .title i2s converts integer to string VAX = 1 ;char *i2s(v->num.i) ; The function i2s() recieves an integer as input and returns ; an address to the first byte after the last character inserted ; in the globally defined stringpool. ; STRINGPOOL OFFSETS base = 0 free = 4 top = 8 code_psect .entry i2s,^m movl stringpool + free,r4 ;store address of stringpool.free movl @4(ap),r5 blss 10$ ;if input is negative insert "-" bneq 15$ movb #^A"0",(r4)+ ;insert "0" in stringpool movl r4,r0 ret 10$: mnegl r5,r5 movb #^A"-",(r4)+ 15$: subl2 #24,sp ;get space and convert integer to cvtlp r5,#10,(sp) ;packed decimal, then numeric string cvtps #10,(sp),#10,12(sp) skpc #^A"0",#10,13(sp) ;skip over leading zeroes movc3 r0,(r1),(r4) ;insert string into stringpool and movl r3,r0 ;return address of first byte after ret ;last character insert .end fis-gtm-V6.0-003/sr_avms/incr_link.c0000644000032200000250000004603012201176175016135 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #include #include #include #include #include "zcall.h" #include #include "compiler.h" #include "obj_gen.h" #include "objlangdefs.h" #include "urx.h" #include "vaxsym.h" #include "op.h" #include "incr_link.h" #include "inst_flush.h" #include "op_fgnlookup.h" #include "min_max.h" LITREF char gtm_release_name[]; LITREF int4 gtm_release_name_len; GBLREF mident_fixed zlink_mname; GBLREF unsigned char *gtm_main_address; /* GBLREF unsigned char *gtm_dyn_ch_address; */ /* if we need this variable, it should be defined in gtm$startup */ static short linker_stack_depth; static int4 stack_psect; static char loading_psect, *reloc_base, *stack; static char *load_base[GTM_LASTPSECT], *load_top[GTM_LASTPSECT]; static int zlink_mname_len; bool tir(char *buff, int size, urx_rtnref *urx_lcl_anchor); /* TIR - process Alpha text information and relocation subrecords from a GT.M MUMPS object file record. */ #define GTMMAIN "GTM$MAIN" #define GTMDYNCH "GTM$DYN_CH" error_def(ERR_INVOBJ); error_def(ERR_LOADRUNNING); /* locc is defined here so that it may be inlined * locc - locate first occurrence of character in string */ static char *locc(char c, char *string, int length) { while (0 < length--) { if (c == *string) return string; ++string; } return 0; } /* ZL_ERROR - perform cleanup and signal errors found in zlinking a mumps object module. */ void zl_error(unsigned char *fab, bool libr, int4 err, int4 len, char *addr) { if (load_base[GTM_LINKAGE]) free(load_base[GTM_LINKAGE]); if (!libr) sys$close(fab); else lbr$close(fab); /* close library */ if (0 == len) rts_error(VARLSTCNT(1) err); else rts_error(VARLSTCNT(4) err, 2, len, addr); } /* INCR_LINK - read and process a mumps object module. Link said module to currently executing image. */ bool incr_link(unsigned char *fab, bool libr) { struct RAB rab; rhdtyp *hdr, *old_rhead; lab_tabent *lbt_ent, *lbt_bot, *lbt_top, *olbt_ent, *olbt_bot, *olbt_top; int status, rec_count, n1; int4 linkage_size, lit_size, code_size; int4 rhd_diff; char *bptr, *subrec, buff[OBJ_EMIT_BUF_SIZE], fake[SIZEOF(rtn_tabent)]; unsigned char *cp, *cp1, tmpch; unsigned short rec_size; urx_rtnref urx_lcl_anchor; char module_name[SIZEOF(mident_fixed)]; int order; $DESCRIPTOR(buffdes, buff); bptr = buff; /* initialize buffer pointer to first buffer */ /* Safety initial values: */ loading_psect = -1; reloc_base = -1; load_base[GTM_CODE] = load_top[GTM_CODE] = 0; load_base[GTM_LITERALS] = load_top[GTM_LITERALS] = 0; load_base[GTM_LINKAGE] = load_top[GTM_LINKAGE] = 0; if (!libr) { rab = cc$rms_rab; rab.rab$l_fab = fab; rab.rab$l_ubf = buff; rab.rab$w_usz = OBJ_EMIT_BUF_SIZE; status = sys$connect(&rab); if (RMS$_NORMAL != status) zl_error(fab, libr, status, 0, 0); } /* Although we process the linker commands relating to the GTM_RNAMESAAAAB PSECT, * we never use the data, so we create the image on the stack and ignore it. */ load_base[GTM_RNAMESAAAAB] = &fake[0]; load_top[GTM_RNAMESAAAAB] = &fake[0] + SIZEOF(rtn_tabent); urx_lcl_anchor.len = 0; urx_lcl_anchor.addr = urx_lcl_anchor.lab = urx_lcl_anchor.next = 0; for (rec_count = 0; rec_count < 3; rec_count++) { if (!libr) { status = sys$get(&rab); rec_size = rab.rab$w_rsz; } else { status = lbr$get_record(fab, 0, &buffdes); rec_size = buffdes.dsc$w_length; bptr = buffdes.dsc$a_pointer; } if (RMS$_EOF == status) zl_error(fab, libr, ERR_INVOBJ, 0, 0); if (!(status & 1)) zl_error(fab, libr, status, 0, 0); switch(*(short *)(&bptr[EOBJ$W_RECTYP])) { case EOBJ$C_EMH: if (0 == rec_count) { /* First record must be module header record, subtype main module header. */ if (EMH$C_MHD != *(short *)(&bptr[EOBJ$W_SUBTYP])) zl_error(fab, libr, ERR_INVOBJ, 0, 0); zlink_mname_len = bptr[EMH$B_NAMLNG]; if (zlink_mname_len > MAX_MIDENT_LEN) zl_error(fab, libr, ERR_INVOBJ, 0, 0); memcpy(&zlink_mname.c[0], &bptr[EMH$B_NAMLNG+1], zlink_mname_len); /* copy module name */ zlink_mname.c[zlink_mname_len] = 0; continue; } else if (1 == rec_count) { /* Second record must be module header record, subtype language processor name header. */ if (EMH$C_LNM != *(short *)(&bptr[EOBJ$W_SUBTYP])) zl_error(fab, libr, ERR_INVOBJ, 0, 0); n1 = rec_size - 6; /* record size minus bytes used up by header information */ if (n1 > gtm_release_name_len) n1 = gtm_release_name_len; for (cp = &bptr[6], cp1 = gtm_release_name; n1 > 0; n1--) { if (*cp++ != (tmpch = *cp1++)) /* verify GT.M release name matches current name */ return FALSE; if ('-' == tmpch) break; } /* VMS Linker looks at major and minor version numbers to see if recompile is necessary. * That is, if the current GTM version is V5.2, any object file created using V5.1 * or lesser version will automatically be recompiled. But any object file created using * V5.2* version will NOT be automatically recompiled. On the other hand, we want * V5.2-000A to force unconditional recompile on all object files V5.2-000 (and previous) * GTM versions. We want to do that because of C9C05-002003 causing OC_NAMECHK opcode as well * as the xf_namechk/op_namechk transfer table entries to be removed. * * history of object file changes : * code gen changed in V4.4-003A, * dev params in V4.4-004, * $increment/longnames in V4.4-005 * OC_NAMECHK opcode nix in V5.2-000A */ /* Example &bptr[6] = "GT.M V5.2-000 VMS AXP16-FEB-2007 16:04" * We want the index into bptr where 5.2 starts which is bptr[12] */ if (0 > STRNCMP_LIT(&bptr[12], "5.2-000A")) /* was compiled using V5.2-000 */ return FALSE; continue; } else zl_error(fab, libr, ERR_INVOBJ, 0, 0); case EOBJ$C_EGSD: if (2 == rec_count) { /* Third record must be global symbol directory record. */ subrec = bptr + 8; /* skip over record header to first subrecord header */ /* GTM$CODE PSECT program section definition subrecord. */ if (EGSD$C_PSC != *(short *)(&subrec[EGPS$W_GSDTYP])) zl_error(fab, libr, ERR_INVOBJ, 0, 0); code_size = *(int4 *)(&subrec[EGPS$L_ALLOC]); subrec += *(short *)(&subrec[EGPS$W_SIZE]); /* skip to next subrecord */ /* GTM$LITERALS PSECT program section definition subrecord. */ if (EGSD$C_PSC != *(short *)(&subrec[EGPS$W_GSDTYP])) zl_error(fab, libr, ERR_INVOBJ, 0, 0); lit_size = *(int4 *)(&subrec[EGPS$L_ALLOC]); subrec += *(short *)(&subrec[EGPS$W_SIZE]); /* skip to next subrecord */ /* GTM$Rname PSECT program section definition subrecord. */ if (EGSD$C_PSC != *(short *)(&subrec[EGPS$W_GSDTYP])) zl_error(fab, libr, ERR_INVOBJ, 0, 0); subrec += *(short *)(&subrec[EGPS$W_SIZE]); /* skip to next subrecord */ /* $LINKAGE PSECT program section definition subrecord. */ if (EGSD$C_PSC != *(short *)(&subrec[EGPS$W_GSDTYP])) zl_error(fab, libr, ERR_INVOBJ, 0, 0); linkage_size = *(int4 *)(&subrec[EGPS$L_ALLOC]); subrec += *(short *)(&subrec[EGPS$W_SIZE]); /* skip to next subrecord */ load_base[GTM_LINKAGE] = malloc(code_size + lit_size + linkage_size); load_base[GTM_LITERALS] = load_top[GTM_LINKAGE] = load_base[GTM_LINKAGE] + linkage_size; load_base[GTM_CODE] = load_top[GTM_LITERALS] = load_base[GTM_LITERALS] + lit_size; load_top[GTM_CODE] = load_base[GTM_CODE] + code_size; assert(load_top[GTM_CODE] - load_base[GTM_LINKAGE] == linkage_size + lit_size + code_size); continue; } /* caution : fall through */ default: zl_error(fab, libr, ERR_INVOBJ, 0, 0); } break; } linker_stack_depth = 0; for(; ; rec_count++) { if (!libr) { status = sys$get(&rab); rec_size = rab.rab$w_rsz; } else { status = lbr$get_record(fab, 0, &buffdes); rec_size = buffdes.dsc$w_length; bptr = buffdes.dsc$a_pointer; } if (RMS$_EOF == status) { urx_free(&urx_lcl_anchor); zl_error(fab, libr, ERR_INVOBJ, 0, 0); } if (!(status & 1)) { urx_free(&urx_lcl_anchor); zl_error(fab, libr, status, 0, 0); } switch(*(short *)(&bptr[EOBJ$W_RECTYP])) { case EOBJ$C_ETIR: assert(*(short *)(&bptr[EOBJ$W_SIZE]) == rec_size); subrec = bptr + 4; /* skip over record header to first subrecord header */ if (!tir(subrec, *(short *)(&bptr[EOBJ$W_SIZE]) - (subrec - bptr), &urx_lcl_anchor)) { urx_free(&urx_lcl_anchor); zl_error(fab, libr, ERR_INVOBJ, 0, 0); } continue; case EOBJ$C_EGSD: continue; case EOBJ$C_EEOM: if (!libr) { if (RMS$_EOF != sys$get(&rab)) { urx_free(&urx_lcl_anchor); zl_error(fab, libr, ERR_INVOBJ, 0, 0); } } else { if (RMS$_EOF != lbr$get_record(fab, 0, &buffdes)) { urx_free(&urx_lcl_anchor); zl_error(fab, libr, ERR_INVOBJ, 0, 0); } } break; default: urx_free(&urx_lcl_anchor); zl_error(fab, libr, ERR_INVOBJ, 0, 0); } break; } if (0 != linker_stack_depth) { urx_free(&urx_lcl_anchor); zl_error(fab, libr, ERR_INVOBJ, 0, 0); } hdr = load_base[GTM_CODE]; if (!zlput_rname(hdr)) { urx_free(&urx_lcl_anchor); /* Copy routine name to local variable because zl_error frees it. */ memcpy(&module_name[0], hdr->routine_name.addr, hdr->routine_name.len); zl_error(fab, libr, ERR_LOADRUNNING, hdr->routine_name.len, &module_name[0]); } urx_add(&urx_lcl_anchor); old_rhead = hdr->old_rhead_ptr; lbt_bot = (lab_tabent *)((char *)hdr + hdr->labtab_ptr); lbt_top = lbt_bot + hdr->labtab_len; while (old_rhead) { lbt_ent = lbt_bot; olbt_bot = (lab_tabent *)((char *)old_rhead + old_rhead->labtab_ptr); olbt_top = olbt_bot + old_rhead->labtab_len; for (olbt_ent = olbt_bot; olbt_ent < olbt_top; ++olbt_ent) { for (; lbt_ent < lbt_top; lbt_ent++) { MIDENT_CMP(&olbt_ent->lab_name, &lbt_ent->lab_name, order); if (order <= 0) break; } if ((lbt_ent < lbt_top) && !order) { olbt_ent->lab_ln_ptr = lbt_ent->lab_ln_ptr; olbt_ent->has_parms = lbt_ent->has_parms; } else olbt_ent->lab_ln_ptr = 0; } rhd_diff = (char *)hdr - (char *)old_rhead; old_rhead->src_full_name = hdr->src_full_name; old_rhead->routine_name = hdr->routine_name; old_rhead->vartab_len = hdr->vartab_len; old_rhead->vartab_ptr = hdr->vartab_ptr + rhd_diff; old_rhead->ptext_ptr = hdr->ptext_ptr + rhd_diff; old_rhead->current_rhead_ptr = rhd_diff; old_rhead->temp_mvals = hdr->temp_mvals; old_rhead->temp_size = hdr->temp_size; old_rhead->linkage_ptr = hdr->linkage_ptr; old_rhead->literal_ptr = hdr->literal_ptr; old_rhead = (rhdtyp *)old_rhead->old_rhead_ptr; } urx_resolve (load_base[GTM_CODE], lbt_bot, lbt_top); inst_flush(NULL, 0); /* flush instruction cache for resolved references on VMS, this flushes whole pipe */ return TRUE; } bool tir( /* TRUE if no errors encountered; FALSE upon encountering any error */ char *buff, /* start of buffer containing TIR commands */ int size, /* size of buff */ urx_rtnref *urx_lcl_anchor) /* unresovled external local anchor */ { rhdtyp *rtn; lab_tabent *label, *labtop; mident_fixed rtnid, labid; mstr str; int4 sto_imm_length; unsigned char y; char *top, *loc; int len, len1, lab_len, n; urx_rtnref *urx_rp; urx_addr *urx_tmpaddr; unsigned char *cp1, *cp2, ch; bool now_lower; top = buff + size; for(; buff < top;) { switch (loading_psect) { case -1: assert(-1 == reloc_base); break; case GTM_CODE: case GTM_LITERALS: case GTM_RNAMESAAAAB: case GTM_LINKAGE: assert((load_base[loading_psect] <= reloc_base) && (reloc_base <= load_top[loading_psect])); break; default: return FALSE; } /* Note: although the following code uses the term "stack", it should be noted this only works if the * maximum depth of the stack is one (1). */ switch(*(short *)(&buff[ETIR$W_RECTYP])) { case ETIR$C_STA_PQ: /* stack PSECT base plus byte offset */ if ((0 != linker_stack_depth) || (0 != *(int4 *)(&buff[12]))) /* high-order 32 bits of quadword address */ return FALSE; stack_psect = *(int4 *)(&buff[4]); stack = load_base[stack_psect] + *(int4 *)(&buff[8]); linker_stack_depth++; buff += *(short *)(&buff[ETIR$W_SIZE]); continue; case ETIR$C_CTL_SETRB: /* set relocation base */ if (0 >= linker_stack_depth) return FALSE; loading_psect = stack_psect; reloc_base = stack; linker_stack_depth--; buff += *(short *)(&buff[ETIR$W_SIZE]); continue; case ETIR$C_STC_BOH_GBL: /* store conditional BSR or hint at global address */ case ETIR$C_STC_LDA_GBL: /* store conditional LDA at global address */ case ETIR$C_STC_NOP_GBL: /* store conditional NOP at global address */ /* These linker commands are used by the OpenVMS Alpha Linker to replace instructions in the * current image with alternative, faster instructions if certain conditions about those * instructions and the displacement from them to other addresses are true. The GT.M linker * does not use the same mechanisms, so these instructions are not generated except in the * routine header JSB prologue (which is never executed for a GT.M module that is dynamically * linked and can therefore be ignored by the GT.M linker). */ buff += *(short *)(&buff[ETIR$W_SIZE]); continue; case ETIR$C_STC_LP_PSB: /* store conditional linkage pair plus signature */ if (reloc_base + 4 * SIZEOF(int4) > load_top[loading_psect]) return FALSE; /* Store dummy values for now (GTM$MAIN and GTM$DYN_CH aren't really used) [lidral] */ *((int4 *)reloc_base)++ = 0; *((int4 *)reloc_base)++ = 0; *((int4 *)reloc_base)++ = 0; *((int4 *)reloc_base)++ = 0; buff += *(short *)(&buff[ETIR$W_SIZE]); continue; case ETIR$C_STO_GBL: /* store global */ if (reloc_base + 2 * SIZEOF(int4) > load_top[loading_psect]) return FALSE; len = buff[4]; if ((len > SIZEOF(ZCSYM_PREFIX)) && (0 == MEMCMP_LIT(&buff[5], ZCSYM_PREFIX))) { mval package, extent; len1 = len; package.mvtype = extent.mvtype = MV_STR; cp1 = &buff[5] + SIZEOF(ZCSYM_PREFIX) - 1; len1 -= SIZEOF(ZCSYM_PREFIX) - 1; package.str.addr = cp1; loc = locc('.', cp1, len1); assert(0 < loc); package.str.len = (unsigned char *)loc - cp1; len1 -= package.str.len + 1; /* take off package and . */ extent.str.len = len1; extent.str.addr = cp1 + 1; if (0 == extent.str.len) return FALSE; if ((package.str.len > 0) && ('_' == *package.str.addr)) *package.str.addr = '%'; if ('_' == *extent.str.addr) *extent.str.addr = '%'; *((int4 *)reloc_base)++ = (int4)op_fgnlookup(&package, &extent); *((int4 *)reloc_base)++ = 0; /* high-order 32 bits of address */ } else if (0 != (loc = locc('.', &buff[5], len))) /* global name contains a '.' */ { len1 = loc - &buff[5]; /* length of the routine part before the '.' */ assert(MAX_MIDENT_LEN >= len1); memcpy(&rtnid.c[0], &buff[5], len1); rtnid.c[len1] = 0; if ('_' == rtnid.c[0]) rtnid.c[0] = '%'; cp1 = loc + 1; lab_len = len - ((char *)cp1 - &buff[5]); /* length of the label part following the '.' */ assert(MAX_MIDENT_LEN >= lab_len); memcpy(&labid.c[0], cp1, lab_len); labid.c[lab_len] = 0; if ('_' == labid.c[0]) labid.c[0] = '%'; str.addr = &rtnid.c[0]; str.len = len1; if (0 != (rtn = find_rtn_hdr(&str))) /* Routine already resolved? */ { label = (lab_tabent *)((char *)rtn + rtn->labtab_ptr); labtop = label + rtn->labtab_len; for (; label < labtop && ((lab_len != label->lab_name.len) || memcmp(&labid.c[0], label->lab_name.addr, lab_len)); label++) ; if (label < labtop) { *((int4 *)reloc_base)++ = (char *)&label->lab_ln_ptr; *((int4 *)reloc_base)++ = 0; /* high-order 32 bits of address */ buff += *(short *)(&buff[ETIR$W_SIZE]); continue; } } /* This symbol is unknown. Put on the (local) unresolved extern chain -- * either for labels or routines */ urx_rp = urx_putrtn(&rtnid.c[0], len1, urx_lcl_anchor); urx_putlab(&labid.c[0], lab_len, urx_rp, reloc_base); *((int4 *)reloc_base)++ = 0; *((int4 *)reloc_base)++ = 0; } else if (0 != (loc = locc('$', &buff[5], len))) /* global name contains a '$' */ { if ((SIZEOF(GTMMAIN) - 1 == len) && (0 == memcmp(GTMMAIN, &buff[5], len))) *((int4 *)reloc_base)++ = gtm_main_address; else if ((SIZEOF(GTMDYNCH) - 1 == len) && (0 == memcmp(GTMDYNCH, &buff[5], len))) { /* *((int4 *)reloc_base)++ = gtm_dyn_ch_address; */ /* don't need */ *((int4 *)reloc_base)++ = 0; /* dummy value; GT.M frames are not machine frames */ } else return FALSE; *((int4 *)reloc_base)++ = 0; /* high-order 32 bits of address */ } else /* It's a bona fide global name. */ { memcpy(&rtnid.c[0], &buff[5], len); rtnid.c[len] = 0; assert(zlink_mname_len > 0 && zlink_mname_len <= MAX_MIDENT_LEN); if (zlink_mname_len == len && !memcmp(&zlink_mname.c[0], &rtnid.c[0], len)) /* program name */ { *((int4 *)reloc_base)++ = load_base[GTM_CODE]; *((int4 *)reloc_base)++ = 0; /* high-order 32 bits of address */ } else { if ('_' == rtnid.c[0]) rtnid.c[0] = '%'; str.addr = &rtnid.c[0]; str.len = len; if (0 != (rtn = find_rtn_hdr(&str))) *((int4 *)reloc_base)++ = rtn->linkage_ptr; else { urx_rp = urx_putrtn(&rtnid.c[0], len, urx_lcl_anchor); urx_tmpaddr = malloc(SIZEOF(urx_addr)); urx_tmpaddr->next = urx_rp->addr; urx_tmpaddr->addr = reloc_base; urx_rp->addr = urx_tmpaddr; *((int4 *)reloc_base)++ = 0; } *((int4 *)reloc_base)++ = 0; } } buff += *(short *)(&buff[ETIR$W_SIZE]); continue; case ETIR$C_STO_IMM: /* store immediate */ sto_imm_length = *(int4 *)(&buff[4]); if (reloc_base + sto_imm_length > load_top[loading_psect]) return FALSE; memcpy(reloc_base, &buff[8], sto_imm_length); reloc_base += sto_imm_length; buff += *(short *)(&buff[ETIR$W_SIZE]); continue; case ETIR$C_STO_LW: /* store longword */ if ((0 >= linker_stack_depth) || (reloc_base + SIZEOF(int4) > load_top[loading_psect])) return FALSE; *((int4 *)reloc_base)++ = stack; linker_stack_depth--; buff += *(short *)(&buff[ETIR$W_SIZE]); continue; case ETIR$C_STO_OFF: /* store offset to PSECT */ if ((0 >= linker_stack_depth) || (reloc_base + 2 * SIZEOF(int4) > load_top[loading_psect])) return FALSE; *((int4 *)reloc_base)++ = stack; /* low-order 32 bits of quadword address */ *((int4 *)reloc_base)++ = 0; /* high-order 32 bits always zero */ linker_stack_depth--; buff += *(short *)(&buff[ETIR$W_SIZE]); continue; default: return FALSE; } } return TRUE; } fis-gtm-V6.0-003/sr_avms/mdefsp.h0000644000032200000250000000717612201176167015461 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef MDEFSP_included #define MDEFSP_included #define INT8_SUPPORTED #define INT8_FMT "%llu" #define INT8_FMTX "[0x%llx]" #define INT8_NATIVE /* on Alpha processors, 8 byte operations are native to the chip and hence atomic */ #include #include #define insqhi vax_insqhi #define insqti vax_insqti #define remqhi vax_remqhi #define remqti vax_remqti /* Use our own malloc and free to guarantee return value is checked for error condition. */ #ifdef __cplusplus extern "C" void *gtm_malloc(int); extern "C" void gtm_free(void *); /* extern "C" int gtm_memcmp (const void *, const void *, int); */ #endif /* NOTE: this redefines stringpool.free as stringpool.gtm_free, but that appears benign. */ #define malloc gtm_malloc #define free gtm_free #define rts_error lib$signal #ifdef __cplusplus #define error_def(x) extern x #else #define error_def(x) globalvalue x #endif #define INTERLOCK_ADD(X,Y,Z) (__ATOMIC_ADD_LONG((sm_vint_ptr_t)(X), (Z)) + (Z)) #undef BIGENDIAN #ifdef __cplusplus #define GBLDEF #define GBLREF extern #define LITDEF const #define LITREF extern const #else #define GBLDEF globaldef #define GBLREF globalref #define LITDEF const globaldef #define LITREF const globalref #endif /* Reserve enough space in routine header for call to GTM$MAIN. */ #define RHEAD_JSB_SIZE 12 typedef struct { unsigned short mvtype; unsigned e : 7; unsigned sgn : 1; unsigned char fnpc_indx; /* Index to fnpc_work area this mval is using */ mstr str ; int4 m[2] ; } mval; /* Another version of mval with byte fields instead of bit fields */ typedef struct { unsigned short mvtype; unsigned char sgne; unsigned char fnpc_indx; /* Index to fnpc_work area this mval is using */ mstr str ; int4 m[2] ; } mval_b; #define VAR_START(a, b) va_start(a, b) #define VARLSTCNT(a) /* stub for argument count. VAX CALLS instruction pushes count automatically */ #define CHF_MCH_DEPTH chf$q_mch_depth #define CHF_MCH_SAVR0 chf$q_mch_savr0 typedef struct { short flags; short rsa_offset; unsigned char reserved_1; unsigned char fret; short signature_offset; void *entry; /* actually a pointer to a code address, but not representable directly in C */ int4 reserved_2; /* other half of quadword pointer (entry) not allocated by C compiler */ int4 size; short reserved_3; short entry_length; } alpha_procedure_descriptor; #define CODE_ADDRESS(func) gtm$code_address(func) #define GTM_CONTEXT(func) func /* External symbols (global symbols defined in another module) are represented as belonging to this PSECT: */ #define GTM_ANOTHER_MODULE -1 /* Under Alpha AXP OpenVMS, the procedure value of a module is defined in the PSECT used for linkage: */ #define GTM_MODULE_DEF_PSECT GTM_LINKAGE #define OS_PAGELET_SIZE 512 #define OS_VIRTUAL_BLOCK_SIZE OS_PAGELET_SIZE typedef volatile int4 latch_t; typedef volatile uint4 ulatch_t; #define INSIDE_CH_SET "ISO8859-1" #define OUTSIDE_CH_SET "ISO8859-1" #define EBCDIC_SP 0x40 #define NATIVE_SP 0x20 #define DEFAULT_CODE_SET ascii /* enum ascii defined in io.h */ #define util_out_print2 util_out_print int adawi(short x, short *y); #define CACHELINE_SIZE 256 /* alpha cache line size */ #endif /* MDEFSP_included */ fis-gtm-V6.0-003/sr_avms/mem_access.c0000644000032200000250000000325112201176167016263 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #define PRT$C_NA 0 /* Set a region of memory to be inaccessable */ void set_noaccess(na_page, prvprt) unsigned char *na_page[2]; /* array of addresses: the low and high addresses to be protected */ unsigned char *prvprt; /* A place to save the previous protection, should the caller later wish to restore the protection */ { unsigned status; unsigned char *actual[2]; /* array of addresses: actual range of addresses affected by sys$setprt */ return; /* STUB */ actual[0] = actual[1] = NULL; /* status = sys$setprt (na_page, 0, 0, PRT$C_NA, prvprt); /* [lidral] */ status = sys$setprt (na_page, actual, 0, PRT$C_NA, prvprt); if (!(status & 1)) rts_error(VARLSTCNT(1) status); return; } /* Return memory protection to the state of affairs which existed prior to a call to set_noaccess */ void reset_access(na_page, oldprt) unsigned char *na_page[2]; /* array of addresses: the low and high addresses to be protected */ unsigned char oldprt; /* A place to save the previous protection, should the caller later wish to restore the protection */ { unsigned status; return; /* STUB */ status = sys$setprt (na_page, 0, 0, oldprt, 0); if (!(status & 1)) rts_error(VARLSTCNT(1) status); return; } fis-gtm-V6.0-003/sr_avms/memcmp.mar0000644000032200000250000000053112201176167015775 0ustar librarygtc .title memcmp() compare two char strings ;memcmp(a,b,len) ;char *a,*b; ;int len; ;compare two character strings ;return 0 iff they are equal ;return < 0 if a < b and > 0 if a > b code_psect .entry memcmp,^m cmpc3 12(ap),@4(ap),@8(ap) blssu 10$ bnequ 20$ clrl r0 ret 10$: movl #-1,r0 ret 20$: movl #1,r0 ret .end fis-gtm-V6.0-003/sr_avms/mum_tstart.m640000644000032200000250000000664512201176167016561 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001, 2008 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .title mum_tstart (re)start a GT.M frame from a sys$unwind G_MSF base_frame ; The code PSECT must have the MIX attribute in order to have read access to it. $CODE$ = "MUM_TSTART,QUAD,PIC,CON,REL,LCL,SHR,EXE,RD,MIX,NOWRT" ; mum_tstart - (re)start a GT.M MUMPS stack frame ; ; mum_tstart calls trans_code if proc_act_type is non-zero. Then ; mum_tstart (re)loads the GT.M registers (including the code address) ; from the GT.M MUMPS stack frame, ensures the instruction cache and ; memory are consistent, reloads r10 with the current address of $TEST ; (mis-named "dollar_truth"), and then jumps to the code address indicated ; by the GT.M MUMPS stack frame. ; ; mum_tstart is only invoked by sys$unwind after unwinding from a ; signal and not via the standard call mechanism. Therefore, ; the context is that of the routine executing in the frame to ; which sys$unwind unwound and not to mum_tstart. Consequently, ; we do not know what value may be in any of the registers and ; must establish pseudo PC-relative addressing in order to refer ; to any data, including the addresses of external items. $code_section ; Pseudo linkage PSECT. A_dollar_truth: .address dollar_truth ; actually, $TEST A_frame_pointer: .address frame_pointer A_proc_act_type: .address proc_act_type L_trans_code: .linkage_pair trans_code L_error_return: .linkage_pair error_return $routine name=mum_tstart,entry=mum_tstart_ca,kind=null br r13, establish_base ; set up for PC-relative addressing establish_base: .base r13, establish_base lda sp, -ARG_AREA_SZ(fp) ; (re)establish argument list area ldq r0, A_proc_act_type ldq_u r28, (r0) extwl r28, r0, r28 beq r28, l1 ldq r26, L_trans_code ldq r27, L_trans_code+8 mov r31, r25 jsr r26, (r26) l1: ; We can't use getframe here with its imbedded $call invocation so hard code a getframe equivalent using ; the lobotomized manual linkages this module needs to use.. ; start GETFRAME expansion ; A_frame_pointer must be address of quadword containing the address of frame_pointer ldq r12, A_frame_pointer ldl r12, (r12) lda r8, msf$flags_off(r12) ldq_u r9, (r8) extbl r9, r8, r9 and r9, sff_etrap_err, r9 beq r9, l2 ; $call ERROR_RETURN, set_arg_info=false, nonstandard=true ldq r26, L_error_return ldq r27, L_error_return+8 mov r31, r25 jsr r26,(r26) ldq r12, A_frame_pointer ldl r12, (r12) l2: ldl r8, msf$l_symtab_off(r12) ldl r9, msf$temps_ptr_off(r12) ldl r13, msf$ctxt_off(r12) ldl r28, msf$literal_ptr_off(r12) cmovne r28, r28, r14 ; only copy to r14 if initialized to non-zero value ldl r26, msf$mpc_off(r12) ; end getframe expansion br r0, establish_base2 ; r13 modified by getframe, set up another (temporary) base establish_base2: .base r0, establish_base2 ldq r10, A_dollar_truth imb ; resynchronize instruction cache ret r26 $end_routine name=mum_tstart .end fis-gtm-V6.0-003/sr_avms/mumps_binding.max0000644000032200000250000000554412201176167017371 0ustar librarygtc;---------------------------------------------------------------------------------------------------------------------------------- .macro MUMPS_BINDING ENTRYREF, LINKNAME, OUTPUT=no, ?rtnaddr, ?lbladdr fgnout_yes = 1 fgnout_ye = 1 fgnout_y = 1 fgnout_no = 0 fgnout_n = 0 .irp $$tmp, .if b $$tmp .print ;MUMPS BINDING FORMAT ERROR: MUMPS ENTRYREF, LINKNAME, OUTPUT .error ;REQUIRED KEYWORD OMITTED .mexit .endc .endr .if ndf fgnout_%EDIT(OUTPUT,LOWERCASE) .print ;MUMPS BINDING FORMAT ERROR: MUMPS ENTRYREF, LINKNAME, OUTPUT .error ;OUTPUT MUST BE YES OR NO .mexit .endc lablen = %LOCATE(<^>,ENTRYREF) entlen = %LENGTH(ENTRYREF) .if eq %LENGTH(ENTRYREF)-lablen .print ;MUMPS BINDING FORMAT ERROR: MUMPS ENTRYREF, LINKNAME, OUTPUT .error ;MUMPS ENTRYREF MUST SPECIFY ROUTINE .mexit .endc rtnlen = entlen - lablen - 1 rstart = lablen+1 .if gt lablen-31 .print ;MUMPS BINDING FORMAT ERROR: MUMPS ENTRYREF, LINKNAME, OUTPUT .error ;LABELS ARE LIMITED TO 31 CHARACTERS .mexit .endc .if gt rtnlen-31 .print ;MUMPS BINDING FORMAT ERROR: MUMPS ENTRYREF, LINKNAME, OUTPUT .error ;ROUTINES ARE LIMITED TO 31 CHARACTERS .mexit .endc $routine LINKNAME, entry=%string(LINKNAME)_CA, kind=stack, - saved_regs=, - size=<<<$RSA_END+<7*8>+15>/16>*16> $linkage_section ; Always generate the routine symbol in upper case so that routine's linkage ; works correctly even if the call table contains lower case routine name and ; the table is compiled with /NAMES={LOWERCASE,AS_IS}. rtnaddr: .address %EDIT(%EXTRACT(rstart, rtnlen, ENTRYREF),UPCASE) L_GTM$MAIN: .linkage_pair GTM$MAIN .if le entlen-31 ; The total length is within 31 chars. Generate a symbolic reference ; in the $linkage_section. lbladdr: .address %EXTRACT(rstart, rtnlen, ENTRYREF).%EXTRACT(0, lablen, ENTRYREF) fgnlab_unresolved = 0 .else lbladdr: .address lblname fgnlab_unresolved = lablen ; The MACRO compiler doesn't allow the symbol names of the form routine.label ; if the total length exceeds 31. So, generate a reference to a location in ; $data_section that stores the label string. $data_section lblname: .ascii "%EXTRACT(0, lablen, ENTRYREF)" .endc $code_section .base r27, $ls ; Copy argument registers and argument information register to stack adjacent to any arguments that may be on stack. stq r21, $SIZE-8(fp) stq r20, $SIZE-16(fp) stq r19, $SIZE-24(fp) stq r18, $SIZE-32(fp) stq r17, $SIZE-40(fp) stq r16, $SIZE-48(fp) stq r25, $SIZE-56(fp) ldq r0, L_GTM$MAIN ldq r1, L_GTM$MAIN+8 ; gtm$fgncall (A(MUMPS routine), A(MUMPS label), OUTPUT (yes or no), A(start of arguments on stack)) $call GTM$FGNCALL, args= $return $end_routine name=LINKNAME .endm fis-gtm-V6.0-003/sr_avms/mutex.mar0000644000032200000250000010672012201176167015670 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2000, 2007 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .title MUTEX GT.M Mutex Control (VMS) ; ; General: ; Multiple readers are allowed at one time, but only one writer (no readers while there is a writer). ; A write request blocks access to additional readers until after the writer is granted crit and then ; releases it. Freeze allows readers, but not writers, and write pendings do not block new readers. ; ; Interface: ; void mutex_init(addr, n, crash) - Initialize a mutex at addr with n queue slots ; If crash is TRUE, then this is a "crash" reinitialization; ; otherwise, it's a "clean" initialization ; enum cdb_sc mutex_lockr(addr, seq, flag, spinparms) - Read access to mutex at addr ; enum cdb_sc mutex_lockw(addr, seq, flag, spinparms) - Write access to mutex at addr ; enum cdb_sc mutex_lockwim(addr, seq, flag) - Write access to mutex at addr; if cannot lock, immediately ; return cdb_sc_nolock ; enum cdb_sc mutex_lockw_ccp(addr, seq, flag, k) - Write access to mutex at addr; if cannot lock, place CCP in ; queue for "wakeup" and return cdb_sc_nolock (do NOT hibernate) ; enum cdb_sc mutex_wtor(addr, rflag, wflag) - Change write access to mutex at addr to read access, do a wakeup ; enum cdb_sc mutex_unlockr(addr, seq, flag) - Unlock read access to mutex at addr ; enum cdb_sc mutex_unlockw(addr, seq, flag) - Unlock write access to mutex at addr ; ; For routines taking the seq argument, if seq != crash count, return cdb_sc_critreset. ; ; See GDSBT.H for related C declarations ; ; Mutex structure (must be quadword aligned): ; ; --------------------------------- ; | write pending | ownership cnt | 0 ; --------------------------------- ; | # of que slots| crash count | ; --------------------------------- ; // // ; --------------------------------- ; |_ fl waiting process que head _| 64 MUTEX_PROCHEAD ; |_ bl _| ; |_ --- unused --- _| ; | --- unused --- | ; --------------------------------- ; // // ; --------------------------------- ; |_ fl unused slots queue head _| 128 MUTEX_FREEHEAD ; |_ bl _| ; |_ --- unused --- _| ; | --- unused --- | ; --------------------------------- ; |_ fl first queue entry _| ; |_ bl _| ; |_ pid _| ; | super_crit [CCP use only]* | ; --------------------------------- ; |_ fl second queue entry _| ; |_ bl _| ; |_ pid _| ; | super_crit [CCP use only]* | ; --------------------------------- ; : : : : : ; --------------------------------- ; |_ fl last queue entry _| ; |_ bl _| ; |_ pid _| ; | super_crit [CCP use only]* | ; --------------------------------- ; ; * Note: only one entry at a time (at the head of the waiting process queue) will ever use this field. ; Offsets from the beginning of the mutex structure: MUTEX_OWNCNT = 0 MUTEX_WRTPND_MASK = ^X10000 MUTEX_WRTPND_BIT = 16 MUTEX_WRTPND = 2 MUTEX_CRASHCNT = 4 MUTEX_QUESLOTS = 6 MUTEX_PROCHEAD = 64 ; 8 MUTEX_FREEHEAD = 128 ; 24 ; Offsets of spin counts in mutex_spin_parms, keep these offsets in sync with mutex_spin_parms_struct definition in gdsbt.h MUTEX_HARD_SPIN_COUNT_OFFSET = 0 MUTEX_SLEEP_SPIN_COUNT_OFFSET = 4 MUTEX_SPIN_SLEEP_MASK_OFFSET = 8 ; Offsets from the beginning of a queue entry: MUTEX_PID = 8 MUTEX_SUPER_CRIT = 12 ; Retry counts for interlocked queue instructions: QUANT_RETRY = 10000 QUEUE_RETRY = 255 MAX_WAKE = 37 ;not actually a retry count but another queue loop limiter REST_FREQ = ^X3 ;sleep mask of complemented low order bits ; NOTE: The following definitions correspond to items of the same name in CDB_SC.H. ; Make sure that they are maintained compatibly! cdb_sc_nolock = 3 cdb_sc_dbccerr = 81 ; 'Q' cdb_sc_critreset = 82 ; 'R' ; NOTE: The following definition corresponds to an item of the same name, ; defined in CCP.H via inclusion of CCPACT_TAB.H. ; Make sure that it is maintained compatibly! CCTR_SCRIT = 10 ; Super_crit granted $psldef $efndef code_psect ; void mutex_init(mutex_struct *addr, int N, bool crash); ; ; Initialize a mutex with N que entries. If crash is TRUE, then this is ; a "crash" reinitialization; otherwise it's a "clean" initialization. .entry mutex_init,^m movl 4(ap),r2 ;r2 -> mutex structure movl 8(ap),r3 ;r3 = number of queue entries blbs 12(ap),crash ;branch if this is a crash reinitialization ; Clean initialization clean: movw r3,MUTEX_QUESLOTS(r2) ;set the number of queue entries ;initialize the waiting process queue to be empty .disable flagging clrq MUTEX_PROCHEAD(r2) clrq MUTEX_PROCHEAD+8(r2) ;initialize the free queue to be empty movaq MUTEX_FREEHEAD(r2),r1 clrq (r1) clrq 8(r1) movaq 16(r1),r0 ;r0 -> first free entry clrq (r0) ;clear it clrq 8(r0) .enable flagging decl r3 ;insert each entry into the free queue 10$: insqti (r0),(r1) bcs 30$ ;branch if the secondary interlock failed addl #16,r0 sobgtr r3,10$ ;initialize the rest of the mutex structure movw #-1,(r2) ;initial semaphore value = -1 clrw MUTEX_WRTPND(r2) ;initial flags value = 0; blbs 12(ap),20$ ;if this was a crash, don't clear the count clrw MUTEX_CRASHCNT(r2) 20$: ret 30$: pushl #ERR_DBCCERR calls #1,G^LIB$SIGNAL ret ; Crash reinitialization crash: bbssi #0,MUTEX_WRTPND(r2),10$ ;set the write pending bit 10$: adawi #1,MUTEX_CRASHCNT(r2) ;increment the crash sequence number .disable flagging clrq MUTEX_FREEHEAD(r2) ;assure that no one goes into the wait queue .enable flagging ;wake up all sleeping processes; they will crash movab MUTEX_PROCHEAD(r2),r4 movl r4,r5 ;r4,r5 -> queue head addw3 #1,MUTEX_QUESLOTS(r2),r0 ;r0 = number of queue slots cvtwl r0,r0 ashl r0,#4,r0 ;scale by 16 movab MUTEX_PROCHEAD(r2)[r0],r6 ;r6 -> top of the queue array 20$: movl (r4),r0 beql clean ;the wait queue was empty; do a clean initialization addl r0,r4 ;r4 probably -> queue entry cmpl r4,r5 ;if r4 -> queue head, then loop is done blequ clean ;if r4 -> below queue head, then the queue is corrupt ;... either way, do a clean initialization cmpl r4,r6 ;if r4 -> above queue top, then the queue is corrupt bgequ clean ;... so do a clean initialization bitb r4,#3 ;if r4 is not quadword aligned, then the queue is corrupt beqlu 30$ brw clean ;... so do a clean initialization ;otherwise, wake up the process 30$: pushal MUTEX_PID(r4) calls #1,G^crit_wake brb 20$ ; enum cdb_sc mutex_lockr(mutex_struct *addr, int4 crash_count, uint4 *read_lock, mutex_spin_parms_ptr_t spin_parms); ; ; Lock read access to the mutex at addr .entry mutex_lockr,^m movl 4(ap),r2 ;r2 -> mutex structure movl 12(ap),r4 ;r4 -> read lock flag 10$: cmpw 8(ap),MUTEX_CRASHCNT(r2) ;has the crash count changed? bneq 30$ ;if so, return an error movl #1,(r4) ;set the read lock flag ;+ ; ; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001 ; ; Change manipulation of the mutex owner count and write pending flag ; to a single atomic operation using ldl_l/stl_c. ; adawi #1,(r2) ;increment the semaphore ; bbssi #1,MUTEX_WRTPND(r2),20$ ;force access to the write pending byte ;20$: blbs MUTEX_WRTPND(r2),40$ ;if write pending, sleep and try again later ;- ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2 evax_mb ; need memory barrier 15$: evax_ldll r16,(r2) ; read mutex locked bbs #16,r16,40$ ; skip, if write pending incw r16 ; incr owner count evax_stlc r16,(r2) ; store mutex .branch_unlikely evax_beq r16,15$ ; retry, if store failed evax_mb ; need memory barrier clrl r0 ;return success (cdb_sc_normal == 0) ret 30$: movzbl #cdb_sc_critreset,r0 ;return error ret 40$: movl 16(ap),r6 ;spin_parms movl MUTEX_HARD_SPIN_COUNT_OFFSET(r6),r6 ;spin_parms->mutex_hard_spin_count bsbw sleep ;(clears the read lock flag) brb 10$ ;try again ; enum cdb_sc mutex_lockw(mutex_struct *addr, int4 crash_count, uint4 *write_lock, mutex_spin_parms_ptr_t spin_parms); ; ; Lock write access to the mutex at addr .entry mutex_lockw,^m movl 4(ap),r2 ;r2 -> mutex structure movl 12(ap),r4 ;r4 -> write lock flag 10$: cmpw 8(ap),MUTEX_CRASHCNT(r2) ;has the crash count changed? bneq 40$ ;if so, return an error ;+ ; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001 ; ; Change manipulation of the mutex owner count and write pending flag ; to a single atomic operation using ldl_l/stl_c. ; ; bbssi #0,MUTEX_WRTPND(r2),20$ ;set the write pending bit ;20$: movl #1,(r4) ;set the write lock flag ; adawi #1,(r2) ;increment the semaphore ; bgtr 50$ ;branch if semaphore > 0 - there are other owners ; ; bbssi #0,MUTEX_WRTPND(r2),30$ ;set write pending again ;30$: tstw (r2) ;see if any other process has entered crit ; bneq 60$ ;if so, sleep and try again later ;- evax_mb ; need memory barrier movl #MUTEX_WRTPND_MASK,r18 ; Get a write pending mask in R18 ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2 15$: evax_ldll r16,(r2) ; read mutex locked evax_extwl r16,#0,r17 ; extract owner count from low word evax_addq r17,#1,r28 ; Owner plus 1 evax_extwl r28,#0,r28 ; maintain owner count as a word evax_cmoveq r28,#0,r17 ; If zero we can own, otherwise don't change evax_addq r18,r17,r16 ; set write pending bit evax_stlc r16,(r2) ; store mutex .branch_unlikely evax_beq r16,15$ ; retry, if store failed evax_mb ; need memory barrier evax_bne r28,60$ ; branch, if wait flag set movl #1,(r4) ;set the write lock flag clrl r0 ;return success (cdb_sc_normal == 0) ret 40$: movzbl #cdb_sc_critreset,r0 ;return error ret ;+ ; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001 ; ; The additional bbssi is not required - with the prior use of ; multiple interlock operations, the probablity that a writer ; unlocked the mutex was much greater. ;50$: bbssi #0,MUTEX_WRTPND(r2),60$ ;set write pending again ;- 60$: movl 16(ap),r6 ;spin_parms movl MUTEX_HARD_SPIN_COUNT_OFFSET(r6),r6 ;spin_parms->mutex_hard_spin_count bsbw sleep ;(clears the write lock flag) brb 10$ ;try again ; enum cdb_sc mutex_lockwim(mutex_struct *addr, int4 crash_count, uint4 *write_lock); ; ; Lock write access to the mutex at addr; if cannot lock, immediately return cdb_sc_nolock .entry mutex_lockwim,^m movl 4(ap),r2 ;r2 -> mutex structure cmpw 8(ap),MUTEX_CRASHCNT(r2) ;has the crash count changed? bneq 30$ ;if so, return error condition ;+ ; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001 ; ; Change manipulation of the mutex owner count and write pending flag ; to a single atomic operation using ldl_l/stl_c. ; ; bbssi #0,MUTEX_WRTPND(r2),10$ ;set the write pending bit ;10$: adawi #1,(r2) ;increment the semaphore ; bgtr 40$ ;branch if semaphore > 0 - there are other owners ; ; bbssi #0,MUTEX_WRTPND(r2),20$ ;set write pending again ;20$: tstw (r2) ;see if any other process has entered crit ; bneq 40$ ;branch if so ;- evax_mb ; need memory barrier to force all writes out 15$: movl #MUTEX_WRTPND_MASK,r19 ; Get a write pending mask in R19 ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2 evax_ldll r16,(r2) ; read mutex locked evax_addq r16,#1,r19 ; Owner plus 1 evax_extwl r19,#0,r28 ; extract owner count tstl r28 ; Can we obtain the mutex? bneq 40$ ; If other owners then no, branch and return error evax_stlc r19,(r2) ; store mutex .branch_unlikely evax_beq r19,15$ ; retry, if store failed evax_mb ; need memory barrier movl #1,@12(ap) ;set the write lock flag clrl r0 ;return success (cdb_sc_normal == 0) ret 30$: movzbl #cdb_sc_critreset,r0 ;return error ret ;+ ; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001 ; ; The mutex manipulation no longer leaves the owner count incremented ; when the mutex is not acquired. The decrement is thus no longer ; required. In addition, the Note below no longer applies since ; the atomic manipulation above can not incorrectly leave the ; write pending flag set. ; ; adawi #-1,(r2) ;decrement the semaphore ; blss 10$ ; ;40$: ; ; ;Note: this may incorrectly leave write pending set, but as long as there is ; ; a process in crit, this will produce only a temporary inefficiency ; - 40$: movzbl #cdb_sc_nolock,r0 ;return failure ret ; enum cdb_sc mutex_lockw_ccp(mutex_struct *addr, short crash_count, uint4 *write_lock, long super_crit); ; ; Lock write access to the mutex at addr; if cannot lock, queue the CCP process for "wakeup", ; and return cdb_sc_nolock (do NOT hibernate) .entry mutex_lockw_ccp,^m movl 4(ap),r2 ;r2 -> mutex structure cmpw 8(ap),MUTEX_CRASHCNT(r2) ;has the crash count changed? bneq 30$ ;if so, return an error ;+ ; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001 ; ; Change manipulation of the mutex owner count and write pending flag ; to a single atomic operation using ldl_l/stl_c. ; ; bbssi #0,MUTEX_WRTPND(r2),10$ ;set the write pending bit ;10$: adawi #1,(r2) ;increment the semaphore ; bgtr 40$ ;branch if semaphore > 0 - there are other owners ; ; bbssi #0,MUTEX_WRTPND(r2),20$ ;set write pending again ;20$: tstw (r2) ;see if any other process has entered crit ; bneq 40$ ;branch if so ; ;- evax_mb ; need memory barrier to force all writes out 15$: movl #MUTEX_WRTPND_MASK,r18 ; Get a write pending mask in R18 ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2 evax_ldll r16,(r2) ; read mutex locked evax_extwl r16,#0,r17 ; extract owner count from low word evax_addq r17,#1,r28 ; Owner plus 1 evax_extwl r28,#0,r28 ; maintain owner count as a word evax_cmoveq r28,#0,r17 ; If zero we can own, otherwise don't change evax_addq r18,r17,r16 ; set write pending bit evax_stlc r16,(r2) ; store mutex .branch_unlikely evax_beq r16,15$ ; retry, if store failed evax_mb ; need memory barrier evax_bne r28,40$ ; branch, if wait flag set movl #1,@12(ap) ;set the write lock flag clrl r0 ;return success (cdb_sc_normal == 0) ret 30$: movzbl #cdb_sc_critreset,r0 ;return error ret ;+ ; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001 ; ; Change manipulation of the mutex owner count and write pending flag ; to a single atomic operation using ldl_l/stl_c. ; ;40$: adawi #-1,(r2) ;decrement the semaphore ; blss 10$ ;- 40$: ; Insert the CCP process at the HEAD of the wakeup queue, but do NOT hibernate ;+ ; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001 ; ; Change manipulation of the mutex owner count and write pending flag ; to a single atomic operation using ldl_l/stl_c. ; ; bbssi #0,MUTEX_WRTPND(r2),50$ ;set write pending again ; ; I don't know enough about how this mutex code is used and wheter or not ; this is an issue, but there is a window such that when we are placing a ; CCP process in the wait queue for a mutex, if the existing owner should release ; the mutex prior to us getting an entry on the wait queue, then no one will ; try to wake up the CCP process. ;- 50$: movl #QUANT_RETRY,r5 60$: movzbl #QUEUE_RETRY,r1 70$: remqhi MUTEX_FREEHEAD(r2),r3 ;get a free slot bvs 130$ ;branch if the queue was empty or the secondary interlock failed movl 16(ap),MUTEX_SUPER_CRIT(r3) ;stash the super_crit value (no need to stash the pid) movl #QUANT_RETRY,r5 80$: movzbl #QUEUE_RETRY,r1 90$: insqhi (R3),MUTEX_PROCHEAD(r2) ;insert at the HEAD of the wait queue bcs 100$ ;branch if the secondary interlock failed movzbl #cdb_sc_nolock,r0 ;return failure to lock - successfully queued ret ;the secondary interlock failed on an attempt to insert into the wait queue 100$: sobgtr r1,90$ sobgtr r5,120$ ;too many queue failures 110$: movzbl #cdb_sc_dbccerr,r0 ;return error ret 120$: calls #0,G^rel_quant brb 80$ ;the free queue was empty or the secondary interlock failed 130$: sobgtr r1,70$ sobgtr r5,140$ ;too many queue failures brb 110$ 140$: calls #0,G^rel_quant brb 60$ ; enum cdb_sc mutex_wtor(mutex_struct *addr, uint4 *read_lock, uint4 *write_lock); ; ; Change write access to the mutex at addr to read access, and do a wakeup .entry mutex_wtor,^m movl 4(ap),r2 ;r2 -> mutex structure movl #1,@8(ap) ;set the read lock flag ; bbcci #0,MUTEX_WRTPND(r2),10$ ;clear the write pending bit ;10$: ;- ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2 evax_mb ; need memory barrier 15$: evax_ldll r16,(r2) ; read mutex locked clrl r16 evax_stlc r16,(r2) ; store mutex as 0 .branch_unlikely evax_beq r16,15$ ; retry, if store failed evax_mb ; need memory barrier bsbw mutex_wakeup clrl r0 ;return success (cdb_sc_normal == 0) ret ; enum cdb_sc mutex_unlockr(mutex_struct *addr, short crash_count, uint4 *read_lock); ; ; Unlock read access to the mutex at addr .entry mutex_unlockr,^m movl 4(ap),r2 ;r2 -> mutex structure cmpw 8(ap),MUTEX_CRASHCNT(r2) ;has the crash count changed? bneq 20$ ;if so, return an error clrl @12(ap) ;clear the read lock flag ;+ ; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001 ; ; Change manipulation of the mutex owner count and write pending flag ; to a single atomic operation using ldl_l/stl_c. ; ; adawi #-1,(r2) ;decrement the semaphore ;- ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2 evax_mb ; need memory barrier 15$: evax_ldll r16,(r2) ; read mutex locked decw r16 ; decr owner count evax_stlc r16,(r2) ; store mutex .branch_unlikely evax_beq r16,15$ ; retry, if store failed evax_mb ; ; ; The following two source lines seem to be an attempt at recovering ; from a situation in which a writer dies after setting it (and before ; incrementing the semaphore) causing later readers to block. They are being ; commented out for the following reasons - ; a. If this reader clears wrtpnd after a new writer has set wrtpnd (and before ; incrementing semaphore), a new reader coming after the new writer might ; successfully grab read crit forcing the new writer to wait in violation of ; "A write request blocks access to additional readers until after ; the writer is granted crit and then releases it" ; as stated above. ; b. Recovery from failures is anyway incomplete. We can live without this one! ; ; Vinaya, 07/21/98 ; ; bgeq 10$ ;if less than zero, there are no more ; ;owners <--??? is this logic correct? ; bbcci #0,MUTEX_WRTPND(r2),10$ ;clear the write pending bit; ; ;if already clear, skip the wakeup bsbw mutex_wakeup ;Label no longer required. See comments above. Vinaya, 07/21/98 ;10$: clrl r0 ;return success (cdb_sc_normal == 0) clrl r0 ;return success (cdb_sc_normal == 0) ret 20$: movzbl #cdb_sc_critreset,r0 ;return error ret ; enum cdb_sc mutex_unlockw(mutex_struct *addr, short crash_count, uint4 *write_lock); ; ; Unlock write access to the mutex at addr .entry mutex_unlockw,^m movl 4(ap),r2 ;r2 -> mutex structure cmpw 8(ap),MUTEX_CRASHCNT(r2) ;has the crash count changed? bneq 20$ ;if so, return an error clrl @12(ap) ;clear the write lock flag ; ;The order in which the semaphore is decremented and wrtpnd is cleared is ;important. The order "decrement semaphore" and then "clear wrtpnd" might ;lead to a writer and multiple readers all acquiring crit successfully ;(violation of mutual exclusion). An example scenario - ; 0. Writer A in the process of releasing crit, decrements semaphore ; 1. Writer B acquires crit ; 2. Writer A clears wrtpnd ; 3. Readers C, D, etc grab read crit successfully ;By changing the order to "clear wrtpnd" and then "decrement semaphore", we ;prevent such scenarios from occuring. But we now have the possibility of ;new readers beating a prior writer in violation of - ; "A write request blocks access to additional readers until after ; the writer is granted crit and then releases it" ;as stated above. This might happen in the window between clearing wrtpnd and ;decrementing the semaphore. Note that this won't violate mutual exclusion and ;hence a better choice. ; ; Vinaya, 07/21/98 ; ; adawi #-1,(r2) ;decrement the semaphore ; ; bbcci #0,MUTEX_WRTPND(r2),10$ ;clear the write pending bit ;10$: bsbw mutex_wakeup ;+ ; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001 ; ; Change manipulation of the mutex owner count and write pending flag ; to a single atomic operation using ldl_l/stl_c. With the single ; atomic operation, the ordering issue described above are no longer ; possible. ; ; bbcci #0,MUTEX_WRTPND(r2),10$ ;clear the write pending bit ;10$: adawi #-1,(r2) ;decrement the semaphore ;- ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2 evax_mb ; need memory barrier 15$: evax_ldll r16,(r2) ; read mutex locked movl #^xffff,r17 ; create free mutex state evax_stlc r17,(r2) ; store mutex .branch_unlikely evax_beq r17,15$ ; retry, if store failed evax_mb bsbw mutex_wakeup clrl r0 ;return success (cdb_sc_normal == 0) ret 20$: movzbl #cdb_sc_critreset,r0 ;return error ret ; Insert this process at the tail of the wait queue, ; and hibernate for 10 seconds ; ; On entry, r2 -> mutex structure ; r4 -> read lock flag or write lock flag sleep: .jsb32_entry input= clrl (r4) ;clear the lock flag (read or write) ;+ ; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001 ; ; The mutex manipulation no longer leaves the owner count incremented ; when the mutex is not acquired. The decrement is thus no longer ; required. ; ; adawi #-1,(r2) ;decrement the semaphore ; bgeq 10$ ;branch if there are other owners ;- tstl num_additional_processors ; If no other processors beql 10$ ; .. avoid spinlock and go right to sleep evax_mb ; complete all reads/writes prior to lock ref 5$: tstw (r2) blss 7$ ; branch if lock is available sobgeq r6,5$ brb 10$ 7$: ; 06/19/2002 se: In previous incarnations of GT.M we used read locks. Because of that, ; the jsb to mutex_wakeup below was warranted because we might need to wake up some ; readers. Now with all locks being write locks what is happening is that if we fail ; to get a write lock the first time and come here, then within some few number of hard-spin ; iterations we see the lock available, we don't return to try and get the lock until after ; we have gone to mutex_wakeup and woken up the first of any sleepers. This is also ; another potential cause for the AST thrashing being seen at the VA. This sleep ; routine has no reason to wake up anybody except itself. ; jsb mutex_wakeup rsb 10$: movl #QUANT_RETRY,r5 20$: movzbl #QUEUE_RETRY,r1 30$: remqhi MUTEX_FREEHEAD(r2),r3 ;get a free slot bvs 100$ ;branch if the queue was empty or the secondary interlock failed movl process_id,MUTEX_PID(r3) movl #QUANT_RETRY,r5 40$: movzbl #QUEUE_RETRY,r1 50$: insqti (R3),MUTEX_PROCHEAD(r2) ;insert at the tail of the wait queue bcs 70$ ;branch if the secondary interlock failed ;08/20/2002 nars : we need to redo the crit test after inserting ourselves into the wait queue. ; this is because it is possible that crit became free in the time between our hard spin loop and ; insertion into the wait queue in which case, if we otherwise decide to hibernate for ; 10 seconds there will be nobody to wake us up. ; also note that we will do a mutex_wakeup ONLY IF we see noone holding crit. this is therefore ; not likely to result in cascading wakeups (for large number of processes) since the very ; first process to be woken up and obtain crit will stop future wakeups. tstw (r2) ;see if any other process has entered crit bgeq 60$ ;branch if so jsb mutex_wakeup ;hibernate for 10 seconds 60$: clrl crit_sleep_expired ;clear timer so can know if it expired or we were woken up pushl #-1 ;build the timer quadword on the stack... pushl #-100000000 ;... 10 seconds delta time movl sp,r0 ;save its address clrl -(sp) ;flags argument: elapsed time pushl r2 ;reqidt argument: address of the mutex structure pushab mutex_tickle ;astadr argument: see routine below pushl r0 ;daytim argument: address of the timer quadword on the stack pushl #efn$c_enf ;use no efn argument calls #5,G^sys$setimr addl #8,sp ;pop the timer quadword calls #0,G^sys$hiber tstl crit_sleep_expired ;if not expired, return now to try to get lock immediately bnequ 65$ ;branch if expired. pushl #PSL$C_USER ;acmode argument pushl r2 ;reqidt argument: address of the mutex structure calls #2,G^sys$cantim ; kill unpopped timer rsb ; retry lock 65$: pushl r2 ; address of mutex structure calls #1,mutex_deadlock_check ;crit deadlock detection check rsb ;retry lock even though we were not awakened. ;the secondary interlock failed on an attempt to insert into the wait queue 70$: sobgtr r1,50$ sobgtr r5,90$ ;too many queue failures 80$: movzbl #cdb_sc_dbccerr,r0 ;return error ; ret *** replaced with rsb below to eliminate compiler warnings. Using a ret here is not valid in the ; cross compiled environment due to not keeping args/save areas on the stack in ; the same way the vax did. se 8/2002 rsb 90$: calls #0,G^rel_quant brb 40$ ;the free queue was empty or the secondary interlock failed 100$: bcs 110$ ;branch if the secondary interlock failed ;the free queue was empty - wait a second, then try again ; 2000/1/25 smw avoid link error for amac$flt_tsf ; movf #1.0,-(sp) ;store the value on the stack so that it can be passed by reference ; movl sp,r0 ;the argument to lib$wait is the address of the value ; pushl r0 ; calls #1,G^lib$wait ; addl #4,sp ;clean up the stack pushl #1000 ; 1 second calls #1,G^hiber_start ; wait brw 10$ ;the secondary interlock failed on an attempt to remove an entry from the free queue 110$: sobgtr r1,120$ sobgtr r5,130$ ;too many queue failures brb 80$ 120$: brw 30$ 130$: calls #0,G^rel_quant brw 20$ ; AST routine for the timer in sleep, above ; ; The argument is the address of a mutex structure .entry mutex_tickle,^m movl #1,crit_sleep_expired ;we waited long and hard.. clrl -(sp) clrl -(sp) calls #2,G^sys$wake movl 4(ap),r2 bsb mutex_wakeup ret ; Wake up the process at the head of the wait queue ; ; On entry, r2 -> mutex structure mutex_wakeup: .jsb32_entry input= ;+ ; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001 ; ; Perform a quick test to see if there are any processes waiting for the ; mutex. This avoids the more expensive REMQTI PAL Call at 20$ from ; performing this test. ;- movzbl #MAX_WAKE,r6 3$: evax_mb ; make sure we see changes done by other processor tstl MUTEX_PROCHEAD(r2) ; Are there any waiters? bneq 5$ ; if neq, yes go release them rsb ; otherise return quickly 5$: movl #QUANT_RETRY,r5 10$: movzbl #QUEUE_RETRY,r1 20$: remqhi MUTEX_PROCHEAD(r2),r3 ;get the first entry from the wait queue bvs 90$ ;branch if the queue was empty or the secondary interlock failed ; movl MUTEX_SUPER_CRIT(r3),r6 ;save the super_crit value in r6 for wake_process - no more CCP 3/2007 RP ; clrl MUTEX_SUPER_CRIT(r3) movl #QUANT_RETRY,r5 30$: movzbl #QUEUE_RETRY,r1 movl MUTEX_PID(r3),r0 ;save the pid in r0 for wake_process 40$: insqti (r3),MUTEX_FREEHEAD(r2) bcs 60$ ;branch if the secondary interlock failed bsb wake_process ;+ ; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001 ; ; There is no need to force an interlock read on the write pending bit here. ; ; bbssi #1,MUTEX_WRTPND(r2),50$ ;force access to the write pending byte ;50$: ;- sobgtr r6,50$ rsb ;enough waking for one process 50$: bicl3 #REST_FREQ,r6,r0 bneq 55$ calls #0,G^rel_quant ;to be sure that some process is awakened, pause and try another if still no pending rp 3/2007 55$: blbc MUTEX_WRTPND(r2),3$ rsb ;write pending is set - stop wakeups ;the secondary interlock failed on an attempt to insert into the free queue 60$: sobgtr r1,40$ sobgtr r5,80$ bsb wake_process ;too many queue failures 70$: movzbl #cdb_sc_dbccerr,r0 ;return error ; ret *** replaced with rsb below to eliminate compiler warnings. Using a ret here is not valid in the ; cross compiled environment due to not keeping args/save areas on the stack in ; the same way the vax did. se 8/2002 rsb 80$: calls #0,G^rel_quant brb 30$ ;the wait queue was empty or the secondary interlock failed 90$: bcs 100$ ;branch if the secondary interlock failed rsb ;the secondary interlock failed on an attempt to remove an entry from the wait queue 100$: sobgtr r1,20$ sobgtr r5,110$ ;too many queue failures brb 70$ 110$: calls #0,G^rel_quant brb 10$ ; Wake up a process ; ; This is a subroutine because we wish to insert the queue entry into the free queue prior to ; doing the wakeup, in order to minimize the time that the queue entry is unattached. ; Also, we wish to wake up the process even if the insq fails. ; ; On entry, r0 == process id, ; r6 == super_crit value wake_process: .jsb32_entry input= ; 07/30/2002 se: Don't disturb pipe for a condition that is no longer needed ; tstl r6 ;was super_crit set? ; bneq wake_ccp ;branch if so pushl r0 ;store the pid on the stack, so that it can be passed by reference movl sp,r0 ;the argument to crit_wake is the address of the pid pushl r0 ;use two instructions for safety calls #1,G^crit_wake addl #4,sp ;clean up the stack rsb ; 07/30/2002 se: The following code is disabled because it is no longer used and the compiler ; complains about dead (unreachable) code. ; The CCP never hibernated, so it doesn't get awakened per se; ; rather, we send it an appropriate message: ;wake_ccp: ; pushl r6 ;store the super_crit value on the stack, so that it can be passed by reference ; movl sp,r0 ;the second argument to ccp_sendmsg is the address of the super_crit value ; pushl r0 ;use two instructions for safety ; pushl #CCTR_SCRIT ;the first argument to ccp_sendmsg is the action code: super_crit granted ; calls #2,G^ccp_sendmsg ; addl #4,sp ;clean up the stack ; ; rsb .end fis-gtm-V6.0-003/sr_avms/mutex_stoprel.mar0000644000032200000250000000763512201176167017445 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2000, 2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .title mutex_stoprel gtm mutex control MUTEX_OWNCNT = 0 MUTEX_WRTPND = 2 MUTEX_PROCHEAD = 64 ; 8 MUTEX_FREEHEAD = 128 ; 24 MQUE_PID = 8 QUE_RETRY = 128 ; NOTE: The following definition corresponds to an item of the same name in CDB_SC.H. ; Make sure that it is maintained compatibly! cdb_sc_dbccerr = 81 ; 'Q' code_psect .entry mutex_stoprelr,^m movl 4(ap),r2 ;r2 points to head of structure ;+ ; Moser and Jordan (Compaq Computer Corporation)) 2-APR-2001 ; ; Change manipulation of the mutex owner count and write pending flag ; to a single atomic operation using ldl_l/stl_c. With the single ; atomic operation, the ordering issue described above are no longer ; possible. ; ; adawi #-1,(r2) ;decrement semaphore ; bgeq 20$ ; bbcci #0,MUTEX_WRTPND(r2),20$ ;if was a write pending do wakeup ;- ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2 15$: evax_ldll r16,(r2) ; read mutex locked evax_sll r16,#16,r28 ; Move WRTPND to bit pos 0 decw r16 ; decr owner count evax_and r16,#^xffff,r16 ; clear WRTPND bit evax_stlc r16,(r2) ; store mutex .branch_unlikely evax_beq r16,15$ ; retry, if store failed evax_mb blbs r28,20$ ; skip, if no write pending bsbw mutex_wakeup 20$: clrl r0 ;return success: cdb_sc_normal == 0 ret .entry mutex_stoprelw,^m movl 4(ap),r2 ;r2 points to head of structure ;+ ; Moser and Jordan (Compaq Computer Corporation)) 2-APR-2001 ; ; Change manipulation of the mutex owner count and write pending flag ; to a single atomic operation using ldl_l/stl_c. ; ; adawi #-1,(r2) ;decrement the semaphore ; bbcci #0,MUTEX_WRTPND(r2),10$ ;- ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2 15$: evax_ldll r16,(r2) ; read mutex locked decw r16 ; decr owner count evax_and r16,#^xffff,r16 ; clear WRTPND bit evax_stlc r16,(r2) ; store mutex .branch_unlikely evax_beq r16,15$ ; retry, if store failed evax_mb bsb mutex_wakeup clrl r0 ;return success: cdb_sc_normal == 0 ret mutex_wakeup: .jsb32_entry movzbl #QUE_RETRY,r1 5$: remqhi MUTEX_PROCHEAD(r2),r3 ;get first entry in queue bvc 20$ ;got a que entry bcc 70$ ;no entries left...all done sobgtr r1,5$ ;secondary interlock failed 10$: movl #cdb_sc_dbccerr,r0 ret 20$: movl MQUE_PID(r3),r0 movzbl #QUE_RETRY,r1 40$: insqti (r3),MUTEX_FREEHEAD(r2) bcc 50$ sobgtr r1,40$ bsb wake_job brb 10$ 50$: bsb wake_job ;+ ; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001 ; ; There is no need to foce an interlock read on the write pending bit here. ; ; bbssi #1,MUTEX_WRTPND(r2),60$ ;force access to the write pending byte ;60$: ;- blbs MUTEX_WRTPND(r2),70$ ;if write pending set stop wakeups brb mutex_wakeup 70$: rsb ; wake up a job ; enter with r0 containing the pid ; exit with job awakened, r0,r1 destroyed ; this is a subroutine, because we wish to insert que entry in free ; list prior to making service call in order to minimize the time ; that the que entry is unattached. Also we wish to wake up the ; job, even if the insq fails wake_job: .jsb32_entry pushl r0 ;store pid on stack, so that it can be ;referenced by address movl sp,r0 ;argument to crit_wake is address of pid pushl r0 ;use two instructions for safety calls #1,G^crit_wake moval 4(sp),sp ;clean-up the stack rsb ;return to calling program .end fis-gtm-V6.0-003/sr_avms/mval$def.max0000644000032200000250000000700712201176167016214 0ustar librarygtc;################################################################# ;# # ;# Copyright 2006, 2012 Fidelity Information Services, Inc # ;# # ;# This source code contains the intellectual property # ;# of its copyright holder(s), and is made available # ;# under a license. If you do not know the terms of # ;# the license, please stop and do not read further. # ;# # ;################################################################# .macro mval$def mval$v_nm = 0 mval$v_int = 1 mval$v_str = 2 mval$v_num_approx = 3 mval$v_canonical = 4 mval$v_sym = 5 mval$v_sublit = 6 mval$v_retarg = 7 mval$v_utflen = 8 mval$v_aliascont = 9 mval$m_nm = ^x1 mval$m_int = ^x3 mval$m_str = ^x4 mval$m_num_approx = ^x8 mval$m_canonical = ^x10 mval$m_sym = ^x20 mval$m_sublit = ^x40 mval$m_retarg = ^x80 mval$m_utflen = ^x100 mval$m_aliascont = ^x200 mval$w_mvtype = 0 mval$b_exp = 2 mval$l_strlen = 4 mval$a_straddr = 8 mval$q_num = 12 mval$l_m0 = 12 mval$l_m1 = 16 mval$size = 20 MV_BIAS = 1000 MANT_LO = 100000000 MANT_HI = 1000000000 INT_HI = 1000000 .macro mv_force_defined mval, ?label mv_if_defined (mval), label $call underr, args=, nonstandard=true mov r0, mval label: .endm mv_force_defined .macro mv_force_defined_strict mval, ?label mv_if_defined (mval), label $call underr_strict, args=, nonstandard=true label: .endm mv_force_defined_strict .macro mv_force_str mval, ?label mv_if_string mval, label $call n2s, args=, nonstandard=true label: .endm mv_force_str .macro mv_force_num mval, ?label mv_if_number mval, label $call s2n, args=, nonstandard=true label: .endm mv_force_num .macro mv_force_str_if_num_approx mval, ?label mv_if_notnumapprox mval, label $call n2s, args=, nonstandard=true label: .endm mv_force_str_if_num_approx .macro mv_i2mval int, mval mov MV_BIAS, r22 ldl r24, mval$w_mvtype(mval) mov mval$m_int, r23 mskwl r24, 0, r24 ; clear mval$w_mvtype mull r22, int, r28 or r24, r23, r24 stl r28, mval$l_m1(mval) stl r24, (mval) .endm mv_i2mval .macro mv_if_string mval, label ldl r28, mval and r28, mval$m_str, r28 bne r28, label .endm mv_if_string .macro mv_if_notstring mval, label ldl r28, mval and r28, mval$m_str, r28 beq r28, label .endm mv_if_notstring .macro mv_if_number mval, label ldl r28, mval blbs r28, label .endm mv_if_number .macro mv_if_notnumber mval, label ldl r28, mval blbc r28, label .endm mv_if_notnumber .macro mv_if_notnumapprox mval, label ldl r28, mval and r28, mval$m_num_approx, r28 beq r28, label .endm mv_if_notnumapprox .macro mv_if_int mval, label ldl r28, mval and r28, mval$m_int-mval$m_nm, r28 bne r28, label .endm mv_if_int .macro mv_if_notint mval, label ldl r28, mval and r28, mval$m_int-mval$m_nm, r28 beq r28, label .endm mv_if_notint .macro mv_if_defined mval, label ldl r28, mval and r28, mval$m_nm+mval$m_str, r28 bne r28, label .endm mv_if_defined .macro mv_if_notdefined mval, label ldl r28, mval and r28, mval$m_nm+mval$m_str, r28 beq r28, label .endm mv_if_notdefined .macro mv_if_canonical mval, label, ?label1, ?label2 mv_if_notnumber mval, label1 and r28, mval$m_num_approx, r28 bne label2 br label label1: $call val_iscan, args=, nonstandard=true bne r0, label label2: .endm mv_if_canonical .endm mval$def fis-gtm-V6.0-003/sr_avms/mval2num.m640000644000032200000250000000206712201176167016115 0ustar librarygtc;################################################################# ;# # ;# Copyright 2006, 2008 Fidelity Information Services, Inc # ;# # ;# This source code contains the intellectual property # ;# of its copyright holder(s), and is made available # ;# under a license. If you do not know the terms of # ;# the license, please stop and do not read further. # ;# # ;################################################################# .title mval2num "Convert an mval to a number" ; On entry, r1 -> mval mval$def $routine MVAL2NUM, entry=MVAL2NUM_CA, kind=null subq sp, 24, sp stq r26, (sp) stq r13, 8(sp) stq r2, 16(sp) mov r27, r13 .base r13, $ls mov r1, r2 mv_force_defined r2 mv_force_num (r2) mv_force_str_if_num_approx (r2) ldq r28, (sp) ldq r13, 8(sp) ldq r2, 16(sp) addq sp, 24, sp ret r28 $end_routine .end fis-gtm-V6.0-003/sr_avms/obj_file.c0000644000032200000250000011731212201176175015740 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include #include "compiler.h" #include #include "obj_gen.h" #include "pdscdef.h" #include "objlangdefs.h" #include "cmd_qlf.h" #include "mdq.h" #include "stringpool.h" #include "axp_registers.h" #include "axp_gtm_registers.h" #include "axp.h" #include "proc_desc.h" #include "mmemory.h" #include "obj_file.h" struct sym_table { struct sym_table *next; int4 linkage_offset; int4 psect; uint4 value; unsigned short name_len; unsigned char name[1]; }; struct linkage_entry { struct linkage_entry *next; struct sym_table *symbol; }; /* values used in the RMS calls and header records */ #define INITIAL_ALLOC 2 #define DEFAULT_EXTEN_QUAN 10 /* N.B., a useful value for the Alpha is 8192 */ #define MAX_REC_SIZE OBJ_EMIT_BUF_SIZE #define MAX_REC_NUM 1024 #define VERSION_NUM "V1.0" #define VERSION_NUM_SIZE SIZEOF(VERSION_NUM) - 1 #define MAX_IMMED (MAX_REC_SIZE - 2 * SIZEOF(short) - 2 * SIZEOF(short) - SIZEOF(int4)) #define NO_IMMED 0 #define MIN_LINK_PSECT_SIZE 56 LITREF char gtm_release_name[]; LITREF int4 gtm_release_name_len; GBLREF command_qualifier cmd_qlf; GBLREF mident routine_name; GBLREF mident module_name; GBLREF char rev_time_buf[]; GBLREF boolean_t run_time; GBLREF uint4 code_size, lits_size; GBLREF unsigned char *runtime_base; GBLDEF int4 psect_use_tab[GTM_LASTPSECT]; /* bytes of each psect this module */ GBLREF char object_file_name[256]; GBLREF short object_name_len; GBLREF struct FAB obj_fab; /* file access block for the object file */ static short int current_psect; static int4 linkage_size; static struct RAB obj_rab; /* record access block for the object file */ static char sym_buff[OBJ_SYM_BUF_SIZE]; /* buffer for global symbol defs */ static short int sym_buff_used; /* number of chars in sym_buff */ static char emit_buff[OBJ_EMIT_BUF_SIZE]; /* buffer for emit output (must match size of buffer used by incr_link */ static short int emit_buff_used; /* number of chars in emit_buff */ static short int emit_last_immed; /* index of last STO_IMM */ static short int linker_stack_depth; /* linker stack depth */ /* Values that appear in the psect definitions. */ #define CODE_PSECT_ALIGN 4 /* octaword aligned */ #define LIT_PSECT_ALIGN 3 /* quadword aligned */ #define RNAMB_PSECT_ALIGN 2 /* longword aligned */ #define LINK_PSECT_ALIGN 4 /* octaword aligned */ #define CODE_PSECT_FLAGS EGPS$M_PIC|EGPS$M_REL|EGPS$M_SHR|EGPS$M_EXE|EGPS$M_GBL|EGPS$M_RD #define LIT_PSECT_FLAGS EGPS$M_PIC|EGPS$M_REL|EGPS$M_SHR|EGPS$M_GBL|EGPS$M_RD #define RNAMB_PSECT_FLAGS EGPS$M_PIC|EGPS$M_REL|EGPS$M_GBL|EGPS$M_RD|EGPS$M_WRT #define LINK_PSECT_FLAGS EGPS$M_REL|EGPS$M_RD|EGPS$M_WRT #define CODE_PSECT_NAME "GTM$CODE" #define LIT_PSECT_NAME "GTM$LITERALS" #define LINK_PSECT_NAME "GTM$LINK" #define OBJ_STRUCTURE_LEVEL 2 #define OBJ_ARCH_1 0 #define OBJ_ARCH_2 0 /* Values that appear in procedure descriptors. These values MUST match values in gtm$main in gtm_main.m64. */ /* Note: both RSA_END and STACK_SIZE must be multiples of 16; this may introduce padding at the beginning of each region. */ #define RSA_END ROUND_UP((1 + 1 + 9)*8, 16) /* r27 + A(condition handler) + 9 saved registers */ #define RSA_OFFSET (RSA_END - 9*8) /* beginning of register save area */ #define STACK_SIZE ROUND_UP(RSA_END + (1+6)*8, 16) /* add room for r25 (arg info), r16-r21 (arguments) */ static MSTR_CONST(gtm_dyn_ch_name,"GTM$DYN_CH"); static MSTR_CONST(main_call_name,"GTM$MAIN"); /* Linkage pair index values. In order to take advantage of linker-time procedure call optimization, we need one linkage pair for each external procedure called. The linkage pair consists of two pointers, each with its own index (the index of the second pointer is 1 plus the index of the first: the first is the address of the called procedure's entry point and the second is the address of its procedure descriptor. */ #define LP_MAIN 1 error_def(ERR_OBJFILERR); typedef struct _Addr_ref { struct _Addr_ref * next; int psect; int offset; int index; } Addr_ref; static Addr_ref *addr_list = (void *) 0; static Addr_ref *addr_list_end = (void *) 0; static int addr_index; void emit_linkages(void); void emit_lp_rel( int reltype, int lpx, int psect1, int off1, int repl_ins, int psect2, int off2, int namelen, char *name); void emit_sta_pq(int psect, int offset); void emit_stc_lp_psb(int lpx, int len, char *name); void emit_sto_gbl(int len, char *name); void emit_sto_lw(void); void set_psect( int psect, int offset); void output_symbol(void); void buff_emit( char *buff, short size); char *emit_psc( char *buf, int align, int flags, int alloc, int length, char *name); void emit_sto_off(void); void flush_addrs(void); /* * create_object_file * * Args: routine header for object module * * Description: Create and open object file. * Write module and language processor header records. * Write global symbol directory (GSD) psect definition records. * Write routine procedure descriptor to beginning of linkage psect. * Write linkage pair and address records to linkage section for external procedures. * Generate and write to code psect procedure prologue portion of routine header. * Write rest of routine header to code psect. * */ void create_object_file(rhdtyp *rhead) { char obj_name_buff[SIZEOF(mident_fixed) + SIZEOF(".OBJ") - 1]; struct NAM nam; int stat, mname_len; register char *fast; mstr maincall; char psect_def_rec[MAX_REC_SIZE]; /* psect definition records */ /* All object files have a PSECT named "GTM$R" followed by the first 8 characters of the name of the routine. This PSECT contains the routines table entry (rtn_tables) for the routine. Because the linker sorts PSECT's with the same significant attributes alphabetically in the same image section, this naming convention causes the linker to build the initial routines table for GT.M native object files that are included in the initial (static) link. Two dummy PSECT's named "GTM$R" and "GTM$RZZZZZZZZZZ" are defined in GTM_MAIN.M64 and will be sorted by the linker to delimit the beginning and end, respectively, of the initial routines table. In order for this to work properly, the GTM_RNAMESAAAAB PSECT generated here must have the same significant linker attributes as those in GTM_MAIN.M64 and their alignment requirements must be identical to those of entries of the routines name table. */ /* GTM_RNAMESAAAAB PSECT name prefix */ char rnambuf[RNAMB_PREF_LEN + SIZEOF(mident_fixed) + 1]; /* First quadword of procedure descriptor contains flags and offset fields. */ short pdbuf_head[4] = { PDSC_FLAGS, RSA_OFFSET, /* register save area offset in stack frame */ 0, /* includes FRET field */ 0 /* offset of call signature */ }; /* Last 2 quadwords of procedure descriptor before handler information. */ int4 pdbuf_tail[4] = { STACK_SIZE, /* size of stack frame */ 0, /* includes ENTRY_LENGTH field */ (1 << ALPHA_REG_FP) /* IREG_MASK (N.B. don't set bit for ALPHA_REG_RA) */ | (1 << ALPHA_REG_S0) /* r2 */ | (1 << ALPHA_REG_S1) /* r3 */ | (1 << ALPHA_REG_S2) /* r4 */ | (1 << ALPHA_REG_S3) /* r5 */ | (1 << ALPHA_REG_S4) /* r6 */ | (1 << ALPHA_REG_S5) /* r7 */ | (1 << GTM_REG_FRAME_VAR_PTR) /* r8 */ | (1 << GTM_REG_FRAME_TMP_PTR) /* r9 */ | (1 << GTM_REG_DOLLAR_TRUTH) /* r10 */ | (1 << GTM_REG_XFER_TABLE) /* r11 */ | (1 << GTM_REG_FRAME_POINTER) /* r12 */ | (1 << GTM_REG_PV) /* r13 */ | (1 << GTM_REG_LITERAL_BASE), /* r14 */ 0 /* FREG_MASK */ }; int length; int4 code_buf[MAX_REC_SIZE / 4]; int4 *codep; int gtm_main_call, gtm_main_lp; assert(!run_time); /* create the object file */ obj_fab = cc$rms_fab; /* initialize to default FAB values supplied by */ obj_fab.fab$l_dna = obj_name_buff; mname_len = module_name.len; assert(mname_len <= MAX_MIDENT_LEN); if (!mname_len) { MEMCPY_LIT(obj_name_buff, "MDEFAULT.OBJ"); obj_fab.fab$b_dns = SIZEOF("MDEFAULT.OBJ") - 1; } else { memcpy(obj_name_buff, module_name.addr, mname_len); MEMCPY_LIT(&obj_name_buff[mname_len], ".OBJ"); obj_fab.fab$b_dns = mname_len + SIZEOF(".OBJ") - 1; } obj_fab.fab$l_fop = FAB$M_CBT | FAB$M_TEF | FAB$M_MXV; obj_fab.fab$l_alq = INITIAL_ALLOC; obj_fab.fab$w_deq = DEFAULT_EXTEN_QUAN; obj_fab.fab$b_fac = FAB$M_PUT | FAB$M_UPD | FAB$M_GET; obj_fab.fab$w_mrs = MAX_REC_SIZE; obj_fab.fab$l_mrn = MAX_REC_NUM; obj_fab.fab$b_rfm = FAB$C_VAR; obj_fab.fab$b_org = FAB$C_SEQ; obj_fab.fab$l_nam = &nam; nam = cc$rms_nam; /* initialize to default NAM values supplied by */ nam.nam$l_esa = object_file_name; nam.nam$b_ess = 255; if (MV_DEFINED(&cmd_qlf.object_file)) { obj_fab.fab$b_fns = cmd_qlf.object_file.str.len; obj_fab.fab$l_fna = cmd_qlf.object_file.str.addr; } stat = sys$create(&obj_fab); obj_fab.fab$l_nam = 0; object_name_len = nam.nam$b_esl; object_file_name[object_name_len] = 0; switch (stat) { case RMS$_NORMAL: case RMS$_CREATED: case RMS$_SUPERSEDE: case RMS$_FILEPURGED: break; default: rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv); } obj_rab = cc$rms_rab; /* initialize to default RAB values supplied by */ obj_rab.rab$l_fab = &obj_fab; stat = sys$connect(&obj_rab); if(stat!=RMS$_NORMAL) rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv); linker_stack_depth = 0; /* output the Main Module Header Record */ fast = emit_buff; *((short *) fast)++ = EOBJ$C_EMH; *((short *) fast)++ = 0; /* record length */ *((short *) fast)++ = EMH$C_MHD; *((short *) fast)++ = OBJ_STRUCTURE_LEVEL; *((int4 *) fast)++ = OBJ_ARCH_1; *((int4 *) fast)++ = OBJ_ARCH_2; *((int4 *) fast)++ = MAX_REC_SIZE; *((char *) fast)++ = mname_len; memcpy(fast, module_name.addr, mname_len); fast += mname_len; *((char *) fast)++ = VERSION_NUM_SIZE; memcpy(fast,VERSION_NUM,VERSION_NUM_SIZE); fast += VERSION_NUM_SIZE; memcpy(fast,rev_time_buf,17); fast += 17; memcpy(fast," ",17); fast += 17; length = fast - emit_buff; ((short *) emit_buff)[1] = length; obj_rab.rab$l_rbf = emit_buff; obj_rab.rab$w_rsz = length; stat = sys$put(&obj_rab); if(stat != RMS$_NORMAL) rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv); /* output the Language Name Header Record */ fast = emit_buff; *((short *) fast)++ = EOBJ$C_EMH; *((short *) fast)++ = 6 + gtm_release_name_len; *((short *) fast)++ = EMH$C_LNM; memcpy(fast,>m_release_name[0],gtm_release_name_len); fast += gtm_release_name_len; length = fast - emit_buff; obj_rab.rab$w_rsz = length; stat = sys$put(&obj_rab); if(stat != RMS$_NORMAL) rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv); /* define psect's */ length = routine_name.len; MEMCPY_LIT(&rnambuf[0], RNAMB_PREF); memcpy(&rnambuf[RNAMB_PREF_LEN], routine_name.addr, length); if ('%' == rnambuf[RNAMB_PREF_LEN]) rnambuf[RNAMB_PREF_LEN] = '.'; length += RNAMB_PREF_LEN; if (length > EGPS$S_NAME) /* Truncate the PSECT name if it exceeeds the maximum allowed length (31) */ length = EGPS$S_NAME; if (routine_name.len >= RNAME_SORTED_LEN && !memcmp(routine_name.addr, RNAME_ALL_Z, RNAME_SORTED_LEN)) { /* If the first 26 chars of the routine name are all lower case z's (currently routine names cannot be in lower case, but if supported in future), we should not generate the psect name containing the routine name as it could conflict with the dummy anchor gtm$rrzzzzzzzzzzzzzzzzzzzzzzzzzz defined in gtm_main.m64. If such a conflict occurs, linker may not guarantee that the dummy anchor to be the last entry in the routine table. So, if the routine name starts with 26 z's, we generate the psect name changing the last (31st) character to '$' so that all such routines will be concatenated between the anchors. However, they need to be sorted at runtime startup based on the complete routine name (see rtn_tbl_sort.c) */ assert(length == EGPS$S_NAME); rnambuf[length - 1] = '$'; } ((short *) psect_def_rec)[0] = EOBJ$C_EGSD; fast = psect_def_rec+8; fast = emit_psc(fast, CODE_PSECT_ALIGN, CODE_PSECT_FLAGS, code_size, LEN_AND_LIT(CODE_PSECT_NAME)); fast = emit_psc(fast, LIT_PSECT_ALIGN, LIT_PSECT_FLAGS, lits_size, LEN_AND_LIT(LIT_PSECT_NAME)); fast = emit_psc(fast, RNAMB_PSECT_ALIGN, RNAMB_PSECT_FLAGS, SIZEOF(rtn_tabent), length, rnambuf); fast = emit_psc(fast, LINK_PSECT_ALIGN, LINK_PSECT_FLAGS, linkage_size, LEN_AND_LIT(LINK_PSECT_NAME)); length = fast - psect_def_rec; ((short *) psect_def_rec)[1] = length; obj_rab.rab$l_rbf = psect_def_rec; obj_rab.rab$w_rsz = length; stat = sys$put(&obj_rab); if (stat != RMS$_NORMAL) rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv); /* set the appropriate buffer counts */ ((short *) sym_buff)[0] = EOBJ$C_EGSD; ((short *) sym_buff)[1] = 0; sym_buff_used = 8; ((short *) emit_buff)[0] = EOBJ$C_ETIR; ((short *) emit_buff)[1] = 0; emit_buff_used = 4; emit_last_immed = NO_IMMED; memset(psect_use_tab, 0, SIZEOF(psect_use_tab)); /* Build GTM_LINKAGE ("$LINKAGE") psect. */ set_psect(GTM_LINKAGE, 0); /* Generate a procedure descriptor pointing to prologue code (beginning of GTM_CODE psect). */ /* N.B. This procedure descriptor must be at offset 0 in $LINKAGE; that's the way it's defined in obj_code. */ emit_immed(pdbuf_head, SIZEOF(pdbuf_head)); emit_sta_pq(GTM_CODE, 0); emit_sto_off(); emit_immed(pdbuf_tail, SIZEOF(pdbuf_tail)); (void)define_symbol(GTM_ANOTHER_MODULE, >m_dyn_ch_name, 0); emit_sto_gbl(gtm_dyn_ch_name.len, gtm_dyn_ch_name.addr); /* Emit a linkage pair for to GTM$MAIN. */ set_psect(GTM_LINKAGE, ROUND_UP(psect_use_tab[GTM_LINKAGE],8)); /* align to quadword boundary */ gtm_main_lp = psect_use_tab[GTM_LINKAGE]; /* remember for later */ (void)define_symbol(GTM_ANOTHER_MODULE, &main_call_name, 0); emit_stc_lp_psb(LP_MAIN, main_call_name.len, main_call_name.addr); assert (psect_use_tab[GTM_LINKAGE] == MIN_LINK_PSECT_SIZE); emit_linkages (); addr_index = 48; set_psect(GTM_CODE, 0); /* Emit the routine header, including procedure prologue (initialization call to GTM$MAIN). */ /* Emit initialization call to GTM$MAIN. */ /* (This is the routine header jsb field.) */ codep = code_buf; gtm_main_call = (char *) codep - (char *) code_buf; *codep++ = ALPHA_MEM(ALPHA_INS_LDQ, ALPHA_REG_R0, ALPHA_REG_PV, gtm_main_lp); *codep++ = ALPHA_MEM(ALPHA_INS_LDQ, ALPHA_REG_R1, ALPHA_REG_PV, gtm_main_lp+8); *codep++ = ALPHA_JMP(ALPHA_INS_JSR, ALPHA_REG_R0, ALPHA_REG_R0); /* call GTM$MAIN */ assert ((char *)codep - (char *)code_buf == RHEAD_JSB_SIZE); emit_immed(code_buf, (char *) codep - (char *) code_buf); /* Emit conditional stores for instruction optimization of call to GTM$MAIN: */ emit_lp_rel(ETIR$C_STC_NOP_GBL, LP_MAIN, GTM_CODE, gtm_main_call, ALPHA_OPR(ALPHA_INS_BIS, ALPHA_REG_ZERO, ALPHA_REG_ZERO, ALPHA_REG_ZERO), GTM_CODE, gtm_main_call + 12, main_call_name.len, main_call_name.addr); emit_lp_rel(ETIR$C_STC_LDA_GBL, LP_MAIN + 1, GTM_CODE, gtm_main_call + 4, ALPHA_MEM(ALPHA_INS_LDA, ALPHA_REG_R1, ALPHA_REG_PV, 0), GTM_LINKAGE, 0, main_call_name.len, main_call_name.addr); emit_lp_rel(ETIR$C_STC_BOH_GBL, LP_MAIN, GTM_CODE, gtm_main_call + 8, ALPHA_BRA(ALPHA_INS_BSR, ALPHA_REG_R0, 0), GTM_CODE, gtm_main_call + 12, main_call_name.len, main_call_name.addr); /* Now emit the rest of the common part of the routine header (from src_full_name through temp_size). */ /* src_full_name (mstr) */ emit_immed(&rhead->src_full_name.len, SIZEOF(rhead->src_full_name.len)); emit_pidr((int4)rhead->src_full_name.addr, GTM_LITERALS); /* routine_name (mident) */ emit_immed(&rhead->routine_name.len, SIZEOF(rhead->routine_name.len)); emit_pidr((int4)rhead->routine_name.addr, GTM_LITERALS); /* From vartab_off to the end of rhead. */ emit_immed((char *)&rhead->vartab_off, ((char *)&rhead->linkage_ptr - (char *)&rhead->vartab_off)); emit_pidr(0, GTM_LINKAGE); /* Fill in linkage_ptr with the address of the beginning of the linkage Psect. */ emit_pidr(0, GTM_LITERALS); /* Fill in literal_ptr with the address of the beginning of the literal Psect. */ } /* * close_object_file * * Description: Write routine table entry psect. * Write global symbol specifications records for defined global symbols. * Generate and write end of module record. * Close file. * */ void close_object_file(rhdtyp *rhead) { int stat; register char *fast; flush_addrs(); /* emit the routine table entry (rtn_tabent) */ set_psect(GTM_RNAMESAAAAB, 0); emit_immed(&rhead->routine_name.len, SIZEOF(rhead->routine_name.len)); emit_pidr((int4)rhead->routine_name.addr, GTM_LITERALS); emit_pidr(0, GTM_CODE); /* flush emit buffer */ if (emit_buff_used > 4) { ((short *) emit_buff)[0] = EOBJ$C_ETIR; ((short *) emit_buff)[1] = emit_buff_used; obj_rab.rab$l_rbf = emit_buff; obj_rab.rab$w_rsz = emit_buff_used; stat = sys$put(&obj_rab); if (stat != RMS$_NORMAL) rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv); } output_symbol(); /* output the End of Module Record */ fast = emit_buff; *((short *) fast)++ = EOBJ$C_EEOM; *((short *) fast)++ = 24; *((int4 *) fast)++ = 2; /* total linkage indices (= linkage pairs / 2) */ *((short *) fast)++ = EEOM$C_SUCCESS; /* should be completion code in range [0,3] [lidral] */ *((unsigned char *) fast)++ = 1 << EEOM$V_WKTFR; /* EEOM$V_WKTFR = 1 => weak transfer address */ *((unsigned char *) fast)++ = 0; /* alignment byte (must be zero) */ *((int4 *) fast)++ = GTM_LINKAGE; /* program section index of program section containing transfer address */ *((int4 *) fast)++ = 0; /* offset of transfer address within program section */ *((int4 *) fast)++ = 0; obj_rab.rab$l_rbf = emit_buff; obj_rab.rab$w_rsz = 24; stat = sys$put(&obj_rab); if (stat != RMS$_NORMAL) rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv); /* close up */ stat = sys$disconnect(&obj_rab); if (stat != RMS$_NORMAL) rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv); assert (linker_stack_depth == 0); } /* * drop_object_file * * Description: Delete object file. */ void drop_object_file(void) { obj_fab.fab$l_fop |= FAB$M_DLT; sys$close(&obj_fab); obj_fab = cc$rms_fab; } /* * define_symbol * * Args: psect index, symbol name, symbol value. * * Description: Buffers a definition of a global symbol with the given name and value in the given psect. * psect == GTM_ANOTHER_MODULE => external (not defined in this module) symbol * * N.B. the return value for define_symbol is only used in this module; all other modules refer to it as type void. */ static struct sym_table *symbols; struct sym_table* define_symbol(int4 psect, mstr *name, int4 value) { int4 cmp; struct sym_table **sym, *newsym; sym = &symbols; while(*sym != 0) { if ((cmp = memvcmp(name->addr, name->len, &((*sym)->name[0]), (*sym)->name_len)) <= 0) break; sym = &((*sym)->next); } if (cmp != 0 || *sym == 0) { /* Add new symbol in alphabetic order. */ newsym = (struct sym_table *) mcalloc(SIZEOF(struct sym_table) + name->len - 1); newsym->name_len = name->len; memcpy(&newsym->name[0], name->addr, name->len); newsym->linkage_offset = 0; /* don't assign linkage psect offset until used */ newsym->psect = psect; newsym->value = value; newsym->next = *sym; *sym = newsym; } else if (psect == GTM_CODE) /* if psect is GTM_CODE, this is a def, not a ref */ { (*sym)->psect = psect; (*sym)->value = value; } return *sym; } /* * emit_immed * * Args: buffer of executable code, and byte count to be output. * * Description: Issues TIR records to store the given number of bytes * from the buffer directly into the image at the current image * location. */ GBLREF spdesc stringpool; error_def(ERR_STRINGOFLOW); #define CRITICAL 5 void emit_immed(char *source, uint4 size) { char buff[MAX_IMMED + 8]; /* MAX_IMMED + 2 * SIZEOF(short) + SIZEOF(int4) */ int amount, r, s; if (run_time) { if (stringpool.free + size > stringpool.top) rts_error(VARLSTCNT(1) ERR_STRINGOFLOW); memcpy(stringpool.free, source, size); stringpool.free += size; } else { /* Check whether the last piece in the emit_buff is a STO_IMM, and calculate how much of the source can be concatenated with it. Do not make the last immediate longer than the maximum allowed, do not overflow the buffer, and do not bother if we can only add 4 bytes or less. */ if (emit_last_immed == NO_IMMED) { r = 0; } else { r = MAX_IMMED - *((int4 *) (emit_buff + emit_last_immed + 2 * SIZEOF(short))); } s = OBJ_EMIT_BUF_SIZE - emit_buff_used; if(r >= CRITICAL && s >= CRITICAL) { r = (r < s) ? r : s; amount = (size < r) ? size : r; memcpy(emit_buff + emit_buff_used, source, amount); /* emit_last_immed is the offset of the start of the last ETIR$C_STO_IMM command; increment the command size and data count fields. */ *((short *) (emit_buff + emit_last_immed + SIZEOF(short))) += amount; /* command size */ *((int4 *) (emit_buff + emit_last_immed + 2 * SIZEOF(short))) += amount; /* data size */ size -= amount; source += amount; psect_use_tab[current_psect] += amount; emit_buff_used += amount; } while(size>0) { amount = (size <= MAX_IMMED) ? size : MAX_IMMED; *(short *)(&buff[ETIR$W_RECTYP]) = ETIR$C_STO_IMM; *(short *)(&buff[ETIR$W_SIZE]) = amount + 2 * SIZEOF(short) + SIZEOF(int4); /* command size */ *(int4 *) (&buff[ETIR$W_SIZE + SIZEOF(short)]) = amount; /* data size */ memcpy(buff + 2 * SIZEOF(short) + SIZEOF(int4), source, amount); emit_last_immed = emit_buff_used; buff_emit(buff, amount + 2 * SIZEOF(short) + SIZEOF(int4)); size -= amount; source += amount; psect_use_tab[current_psect] += amount; } } } /* emit_linkages * * Description: Write symbol addresses to linkage psect. */ static struct linkage_entry *linkage_first, *linkage_last; void emit_linkages(void) { struct linkage_entry *linkagep; for (linkagep = linkage_first; linkagep != 0; linkagep = linkagep->next) { assert (psect_use_tab[GTM_LINKAGE] == linkagep->symbol->linkage_offset); emit_sto_gbl (linkagep->symbol->name_len, linkagep->symbol->name); } assert (psect_use_tab[GTM_LINKAGE] == linkage_size); } /* * emit_literals * * Description: Write each value in the literal chain to the literal psect. */ GBLREF mliteral literal_chain; GBLREF char source_file_name[]; GBLREF unsigned short source_name_len; void emit_literals(void) { uint4 offset, padsize; mliteral *p; assert (psect_use_tab[GTM_LITERALS] == 0); set_psect(GTM_LITERALS, 0); offset = stringpool.free - stringpool.base; emit_immed(stringpool.base, offset); padsize = PADLEN(offset, NATIVE_WSIZE); /* comp_lits aligns the start of source path on NATIVE_WSIZE boundary.*/ if (padsize) { emit_immed(PADCHARS, padsize); offset += padsize; } emit_immed(source_file_name, source_name_len); offset += source_name_len; padsize = PADLEN(offset, NATIVE_WSIZE); /* comp_lits aligns the start of routine_name on NATIVE_WSIZE boundary.*/ if (padsize) { emit_immed(PADCHARS, padsize); offset += padsize; } emit_immed(routine_name.addr, routine_name.len); offset += routine_name.len; padsize = PADLEN(offset, NATIVE_WSIZE); /* comp_lits aligns the start of literal area on NATIVE_WSIZE boundary.*/ if (padsize) { emit_immed(PADCHARS, padsize); offset += padsize; } dqloop(&literal_chain, que, p) { assert (p->rt_addr >= 0); MV_FORCE_NUMD(&p->v); if (p->v.str.len != 0) { emit_immed(&p->v, (int)&p->v.str.addr - (int)&p->v); emit_pidr(p->v.str.addr - (char *)stringpool.base, GTM_LITERALS); emit_immed(&p->v.m, SIZEOF(p->v.m)); /* assumes no fill between end of p->v.str.addr and start of p->m */ } else { p->v.str.addr = 0; emit_immed(&p->v, SIZEOF(p->v)); } offset += SIZEOF(p->v); } assert(offset == lits_size); } /* * find_linkage * * Arg: the name of a global symbol. * * Description: Return the offset into the linkage psect for the address of a global symbol. */ int4 find_linkage(mstr* name) { struct linkage_entry *newlnk; struct sym_table *sym; sym = define_symbol(GTM_LITERALS, name, 0); if (sym->linkage_offset == 0) { /* Add new linkage psect entry at end of list. */ sym->linkage_offset = linkage_size; newlnk = (struct linkage_entry *) mcalloc(SIZEOF(struct linkage_entry)); newlnk->symbol = sym; newlnk->next = 0; if (linkage_first == 0) linkage_first = newlnk; if (linkage_last != 0) linkage_last->next = newlnk; linkage_last = newlnk; linkage_size += 2 * SIZEOF(int4); } return sym->linkage_offset; } /* * flush_addrs * * Description: For every entry in the address pointer list, generate corresponding linkage psect entry. */ void flush_addrs(void) { Addr_ref *addrp; if (!addr_list) return; set_psect(GTM_LINKAGE, addr_list->index); for (addrp = addr_list; addrp != (void *) 0; addrp = addrp->next) { emit_sta_pq(addrp->psect, addrp->offset); emit_sto_off(); } } /* * literal_offset * * Description: Return offset to literal from context register. * * Argument: Offset of literal in literal psect. */ int4 literal_offset (UINTPTR_T offset) { return (int4)((run_time ? (offset - (UINTPTR_T)runtime_base) : offset)); } /* * obj_init * * Description: Initialize symbol list, linkage psect list, linkage_size. */ void obj_init(void) { symbols = 0; linkage_first = linkage_last = 0; linkage_size = MIN_LINK_PSECT_SIZE; /* minimum size of linkage psect, assuming no references from generated code */ return; } /* * buff_emit * * Args: buffer pointer, number of bytes to emit * * Description: Does buffered i/o of TIR records. Assumes that it will * never be given more than OBJ_EMIT_BUF_SIZE-1 bytes to output; * such overlength records should only arise from emit_immed, which * handles the situation by itself. */ void buff_emit( char *buff, short size) { int stat; if (OBJ_EMIT_BUF_SIZE < (emit_buff_used + size)) { *(short *)(&emit_buff[EOBJ$W_RECTYP]) = EOBJ$C_ETIR; *(short *)(&emit_buff[EOBJ$W_SIZE]) = emit_buff_used; obj_rab.rab$l_rbf = emit_buff; obj_rab.rab$w_rsz = emit_buff_used; stat = sys$put(&obj_rab); if (stat != RMS$_NORMAL) lib$stop(stat); emit_buff_used = 2 * SIZEOF(short); emit_last_immed = NO_IMMED; } assert (SIZEOF(emit_buff) >= (emit_buff_used + size)); memcpy(emit_buff + emit_buff_used, buff, size); emit_buff_used += size; } /* * emit_lp_rel Emit Linkage Pair Relocation (via instruction-related store conditional command for linkage) * * Args: TIR store conditional command, linkage index, * psect, offset at which to replace instruction, * replacement instruction, * psect, offset from which to calculate displacement in determining whether to replace instruction, * length of global symbol name, global symbol name * * Description: Issues specified TIR store conditional command. * These TIR commands instruct the linker to replace the instruction at (psect1 + offset1) * with the specified replacement instruction if the displacement from (psect2 + offset2) to * the procedure descriptor or procedure entry associated with the specified global name * is less than some threshhold value (i.e. will fit into some appropriately-sized bit field). * These commands are typically used to allow the linker to optimize procedure calls, not by * reducing the number of instructions, but by substituting either faster instructions (e.g., * NOP in place of LDQ) or by eliminating stalls caused by one instruction needing to wait for * the previous instruction to finish. */ void emit_lp_rel( int reltype, /* TIR store conditional command for linkage */ int lpx, /* linkage index of global symbol */ int psect1, /* psect (program section) in which to place replacement instruction */ int off1, /* byte offset in psect1 at which to place replacement instruction */ int repl_ins, /* replacement instruction */ int psect2, /* psect containing base address from which displacement is to be calculated */ int off2, /* byte offset in psect2 from which displacement is to be calculated */ int namelen, /* length of global symbol name */ char *name) /* global symbol name */ { int len; register char *fast; char buf[MAX_REC_SIZE]; fast = buf; *((short *) fast)++ = reltype; *((short *) fast)++ = 0; /* record length */ *((int4 *) fast)++ = lpx; *((int4 *) fast)++ = psect1; *((int4 *) fast)++ = off1; *((int4 *) fast)++ = 0; *((int4 *) fast)++ = repl_ins; *((int4 *) fast)++ = psect2; *((int4 *) fast)++ = off2; *((int4 *) fast)++ = 0; *fast++ = namelen; memcpy(fast, name, namelen); fast += namelen; len = ROUND_UP(fast - buf, 8); /* round up to next quadword boundary */ *((short *) (buf + 2)) = len; buff_emit(buf, len); /* No increment of psect_use_tab, because these commands must refer to previously written image locations. */ emit_last_immed = NO_IMMED; } /* * emit_pidr * * Args: offset from a psect base, that psect index * * Description: Issues TIR records to create an image activation-time adjusted reference. * That is, at activation time, the value in the current image location will be * incremented by the runtime image base address. Assumes the value is the offset * from the base of the given psect of something to which one wants to refer. * * (Originally named after the VAX linker object language command TIR$C_STO_PIDR, for * Position Independent Data Reference; the Alpha implements this with two TIR commands.) */ void emit_pidr(int4 offset, unsigned char psect) { emit_sta_pq(psect, offset); emit_sto_lw(); } /* * emit_psc * * Args: buffer to contain program section (PSECT) definition global symbol directory subrecord, * virtual address boundary at which to align program section, * bit flags indicating attributes of PSECT, * number of bytes in PSECT, * length in bytes of the name of this PSECT, and * the name of this PSECT. * * Description: Puts global symbol directory PSECT definition subrecord into buffer. * Returns pointer to next available byte in buffer. */ char *emit_psc( char *buf, int align, int flags, int alloc, int length, char *name) { char *fast; fast = buf; *((short *) fast)++ = EGSD$C_PSC; *((short *) fast)++ = 0; *((short *) fast)++ = align; *((short *) fast)++ = flags; *((int4 *) fast)++ = alloc; *((char *) fast)++ = length; memcpy(fast, name, length); fast += length; length = ROUND_UP(fast - buf, 8); fast = buf + length; ((short *) buf)[1] = length; return fast; } /* * emit_sta_pq Stack Psect Base Plus Byte Offset * * Args: psect index, byte offset * * Description: Issues TIR command to add program section base and byte offset then push result onto stack. */ void emit_sta_pq ( int psect, /* psect (program section) index */ int offset) /* byte offset into psect */ { char buf[MAX_REC_SIZE]; register char *fast; fast = buf; *((short *) fast)++ = ETIR$C_STA_PQ; *((short *) fast)++ = 2 * SIZEOF(short) + SIZEOF(int4) + 2 * SIZEOF(int4); *((int4 *) fast)++ = psect; *((int4 *) fast)++ = offset; *((int4 *) fast)++ = 0; /* upper half of offset qw */ linker_stack_depth++; buff_emit(buf, fast - buf); emit_last_immed = NO_IMMED; } /* * emit_stc_lp_psb Store Conditional Linkage Pair plus Signature * * Args: linkage index, length of procedure name, procedure name * * Description: Issues TIR command to declare conditional linkage and signature information for the named procedure. * N.B. this TIR command reserves two indices, lpx and (lpx+1). */ void emit_stc_lp_psb( int lpx, /* linkage pair index */ int len, /* length of name */ char *name) /* procedure name */ { register char *fast; char buf[MAX_REC_SIZE]; fast = buf; *((short *) fast)++ = ETIR$C_STC_LP_PSB; *((short *) fast)++ = 0; /* record length */ *((int4 *) fast)++ = lpx; *fast++ = len; memcpy(fast, name, len); fast += len; *((char *) fast)++ = 1; /* signature length */ *((char *) fast)++ = 0; /* signature information */ len = ROUND_UP(fast - buf, 8); /* round up to next quadword boundary */ *((short *) (buf + 2)) = len; buff_emit(buf, len); psect_use_tab[current_psect] += 4 * SIZEOF(int4); /* two quadwords */ emit_last_immed = NO_IMMED; } /* * emit_sto_gbl Store Global * * Args: length of global symbol name, global symbol name * * Description: Issues TIR command to store a global symbol reference. */ void emit_sto_gbl( int len, /* length of global symbol name */ char *name) /* global symbol name */ { register char *fast; char buf[MAX_REC_SIZE]; fast = buf; *((short *) fast)++ = ETIR$C_STO_GBL; *((short *) fast)++ = 0; /* record length */ *fast++ = len; memcpy(fast, name, len); fast += len; len = ROUND_UP(fast - buf, 8); /* round up to next quadword boundary */ *((short *) (buf + 2)) = len; buff_emit(buf, len); psect_use_tab[current_psect] += 2 * SIZEOF(int4); emit_last_immed = NO_IMMED; } /* * emit_sto_lw Store Longword * * Args: (none) * * Description: Issues TIR command to pop quadword from stack and write low longword to image; value is always treated * as an address and relocated if image is relocatable or fixed up if psect contributed by shareable image. */ void emit_sto_lw(void) { char buf[MAX_REC_SIZE]; register char *fast; fast = buf; *((short *) fast)++ = ETIR$C_STO_LW; *((short *) fast)++ = 2 * SIZEOF(short); linker_stack_depth--; buff_emit(buf, fast - buf); psect_use_tab[current_psect] += SIZEOF(int4); emit_last_immed = NO_IMMED; } /* * emit_sto_off Store Offset to Psect * * Args: (none) * * Description: Issues TIR command to pop quadword from stack and write to image; value is always treated as an address * and relocated if image is relocatable or fixed up if psect contributed by shareable image. */ void emit_sto_off(void) { char buf[MAX_REC_SIZE]; register char *fast; fast = buf; *((short *) fast)++ = ETIR$C_STO_OFF; *((short *) fast)++ = 2 * SIZEOF(short); linker_stack_depth--; buff_emit(buf, fast - buf); psect_use_tab[current_psect] += 2 * SIZEOF(int4); emit_last_immed = NO_IMMED; } /* * output_symbol * * Description: Generate and write global symbol directory (GSD) symbol records for every * global symbol defined or referenced in this module. */ #define GSD_DATA_TYPE 0 #define GSD_PROC_TYPE 0 void output_symbol(void) { int stat, len, reclen; register char *fast; struct sym_table *sym; sym = symbols; while (sym) { len = sym->name_len; /* Compute length of record exclusive of symbol name field. */ reclen = 2 * SIZEOF(short) + 2 * SIZEOF(char); /* common record header definition information */ switch (sym->psect) { case GTM_ANOTHER_MODULE: /* reference to psect from some other module */ reclen += SIZEOF(short); break; case GTM_CODE: /* symbol definition */ case GTM_LINKAGE: /* symbol definition */ reclen += SIZEOF(short) + 6 * SIZEOF(int4); break; default: /* presumably a reference to symbol defined in this module */ reclen += SIZEOF(short); } reclen += 1; /* space for length of name following */ /* Determine whether buffer has enough room; if not, flush it first. */ if (OBJ_SYM_BUF_SIZE < ROUND_UP(sym_buff_used + reclen + len,8)) { ((short *) sym_buff)[0] = EOBJ$C_EGSD; ((short *) sym_buff)[1] = sym_buff_used; obj_rab.rab$l_rbf = sym_buff; obj_rab.rab$w_rsz = sym_buff_used; stat = sys$put(&obj_rab); if (stat != RMS$_NORMAL) rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv); sym_buff_used = 8; emit_last_immed = NO_IMMED; } /* Add next symbol to buffer. */ fast = sym_buff + sym_buff_used; *((short *) fast)++ = EGSD$C_SYM; *((short *) fast)++ = 0; /* EGSY$W_SIZE (record length, after padding) */ /* Global symbol data type -- currently ignored by linker. WARNING: these values need to be defined properly when the linker starts processing them. [lidral] */ if (sym->psect == GTM_ANOTHER_MODULE) /* code for "not defined in this module" */ *((char *) fast)++ = GSD_PROC_TYPE; else *((char *) fast)++ = GSD_DATA_TYPE; *((char *) fast)++ = '\0'; /* alignment byte (must be zero) */ switch (sym->psect) { case GTM_ANOTHER_MODULE: /* psect from some other module */ *((short *) fast)++ = 0; /* ESRF$W_FLAGS = not defined here, not a weak reference */ break; /* no more fields in a reference */ case GTM_CODE: *((short *) fast)++ = EGSY$M_DEF | EGSY$M_REL; /* ESDF$W_FLAGS */ *((int4 *) fast)++ = sym->value; /* ESDF$L_VALUE */ *((int4 *) fast)++ = 0; *((int4 *) fast)++ = 0; /* ESDF$L_CODE_ADDRESS */ *((int4 *) fast)++ = 0; *((int4 *) fast)++ = 0; /* ESDF$L_CA_PSINDX */ *((int4 *) fast)++ = sym->psect; /* ESDF$L_PSINDX */ break; case GTM_LINKAGE: *((short *) fast)++ = EGSY$M_DEF | EGSY$M_REL | EGSY$M_NORM; /* ESDF$W_FLAGS */ *((int4 *) fast)++ = sym->value; /* ESDF$L_VALUE */ *((int4 *) fast)++ = 0; *((int4 *) fast)++ = 0; /* ESDF$L_CODE_ADDRESS = offset in GTM_CODE */ *((int4 *) fast)++ = 0; *((int4 *) fast)++ = GTM_CODE; /* ESDF$L_CA_PSINDX = psect containing code address */ *((int4 *) fast)++ = sym->psect; /* ESDF$L_PSINDX = psect containing procedure descriptor */ break; default: /* presumably a reference to a symbol defined in this module */ *((short *) fast)++ = EGSY$M_REL; /* ESRF$W_FLAGS */ break; /* no more fields in a reference */ } *((char *) fast)++ = len; /* ESDF$B_NAMLNG/ESRF$B_NAMLNG */ memcpy(fast, &sym->name[0], len); fast += len; len = fast - (sym_buff + sym_buff_used); len = ROUND_UP(len, 8); /* round up to quadword boundary */ *((short *) (sym_buff + sym_buff_used + 2)) = len; /* fill in EGSD$C_SYM record length (EGSY$W_SIZE) field */ sym_buff_used += len; sym = sym->next; } /* flush symbol buffer */ if (sym_buff_used > 8) { ((short *) sym_buff)[0] = EOBJ$C_EGSD; ((short *) sym_buff)[1] = sym_buff_used; obj_rab.rab$l_rbf = sym_buff; obj_rab.rab$w_rsz = sym_buff_used; stat = sys$put(&obj_rab); if (stat != RMS$_NORMAL) rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv); sym_buff_used = 8; emit_last_immed = NO_IMMED; } } /* * set_psect * * Args: psect index, byte offset * * Description: Issues TIR commands to set image location to the specified psect's base plus the given byte offset. * Resets current_psect. */ void set_psect( int psect, /* psect (program section) index */ int offset) /* byte offset into psect */ { register char *fast; char set_psect_rec[MAX_REC_SIZE]; /* TIR records to set the psect */ assert (offset >= psect_use_tab[psect]); /* not really necessary, but our code works this way */ if (current_psect != psect || psect_use_tab[current_psect] != offset) { emit_sta_pq(psect, offset); fast = set_psect_rec; *((short *) fast)++ = ETIR$C_CTL_SETRB; /* pop stack to set relocation base */ *((short *) fast)++ = 2 * SIZEOF(short); linker_stack_depth--; buff_emit(set_psect_rec, fast - set_psect_rec); current_psect = psect; psect_use_tab[psect] = offset; emit_last_immed = NO_IMMED; } } fis-gtm-V6.0-003/sr_avms/obj_filesp.h0000644000032200000250000000220712201176167016305 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2004 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef OBJ_FILESP_INCLUDED #define OBJ_FILESP_INCLUDED void emit_pidr(int4 offset, unsigned char psect); void emit_reference(uint4 refaddr, mstr *name, uint4 *result); struct sym_table *define_symbol(int4 psect, mstr *name, int4 value); /* Prefix of the psect name generated for every routine table entry (used in obj_file.c */ #define RNAMB_PREF "GTM$R" #define RNAMB_PREF_LEN STR_LIT_LEN(RNAMB_PREF) /* First significant characters of the routine name on which the table is already sorted by the VMS linker */ #define RNAME_SORTED_LEN (EGPS$S_NAME - RNAMB_PREF_LEN) /* EGPS$S_NAME defined in objlangdefs.h */ #define RNAME_ALL_Z "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" #endif /* OBJ_FILESP_INCLUDED */ fis-gtm-V6.0-003/sr_avms/op_bkpt.m640000644000032200000250000001767412201176167016024 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001, 2010 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .title OP_BKPT G_MSF $linkage_section a_opp_ret: .linkage_pair opp_ret a_op_retarg: .linkage_pair op_retarg a_frame_pointer: .address frame_pointer a_zstep_level: .address zstep_level $code_section ;*1********************************************************************* $routine OPP_ZSTEPRET, entry=OPP_ZSTEPRET_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls ldl r28, msf$typ_off(r12) blbc r28, 10$ ldq r28, a_zstep_level ldl r28, (r28) subq r28, r12, r28 bgt r28, 10$ $call op_zstepret, set_arg_info=false, nonstandard=true 10$: ldq r26, a_opp_ret ldq r27, a_opp_ret+8 ldq r3, (sp) lda sp, 8(sp) jmp r26 $end_routine .page ;*2********************************************************************* $routine OPP_ZSTEPRETARG, entry=OPP_ZSTEPRETARG_CA, kind=null lda sp, -24(sp) stq r3, (sp) stq r0, 8(sp) stq r1, 16(sp) mov r27, r3 .base r3, $ls ldl r28, msf$typ_off(r12) blbc r28, 10$ ldq r28, a_zstep_level ldl r28, (r28) subq r28, r12, r28 bgt r28, 10$ $call op_zstepret, set_arg_info=false, nonstandard=true 10$: ldq r26, a_op_retarg ldq r27, a_op_retarg+8 ldq r3, (sp) ldq r0, 8(sp) ldq r1, 16(sp) lda sp, 24(sp) jmp r26 $end_routine ;*3********************************************************************* $routine OP_ZBFETCH, entry=OP_ZBFETCH_CA, kind=null stack_offset = 16 lda sp, -stack_offset(sp) stq r3, (sp) stq r2, 8(sp) mov r27, r3 .base r3, $ls stl r26, msf$mpc_off(r12) fetch_args r2, stack_offset $call op_zbreak, args=, set_arg_info=false, nonstandard=true getframe bne r0, 10$ imb 10$: ldq r3, (sp) ldq r2, 8(sp) lda sp, stack_offset(sp) ret r26 $end_routine .page ;*4********************************************************************* $routine OP_ZBSTART, entry=OP_ZBSTART_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls stl r26, msf$mpc_off(r12) $call op_zbreak, args=, set_arg_info=false, nonstandard=true getframe bne r0, 10$ imb 10$: ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine ;*5********************************************************************* $routine OP_ZSTEPFETCH, entry=OP_ZSTEPFETCH_CA, kind=null stack_offset = 16 lda sp, -stack_offset(sp) stq r3, (sp) stq r2, 8(sp) mov r27, r3 .base r3, $ls stl r26, msf$mpc_off(r12) fetch_args r2, stack_offset $call op_zst_break, set_arg_info=false, nonstandard=true getframe imb ldq r3, (sp) ldq r2, 8(sp) lda sp, stack_offset(sp) ret r26 $end_routine .page ;*6********************************************************************* $routine OP_ZSTEPSTART, entry=OP_ZSTEPSTART_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls stl r26, msf$mpc_off(r12) $call op_zst_break, set_arg_info=false, nonstandard=true getframe imb ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine ;*7********************************************************************* $routine OP_ZSTZBFETCH, entry=OP_ZSTZBFETCH_CA, kind=null stack_offset = 16 lda sp, -stack_offset(sp) stq r3, (sp) stq r2, 8(sp) mov r27, r3 .base r3, $ls stl r26, msf$mpc_off(r12) fetch_args r2, stack_offset $call op_zbreak, args=, set_arg_info=false, nonstandard=true $call op_zst_break, set_arg_info=false, nonstandard=true getframe imb ldq r3, (sp) ldq r2, 8(sp) lda sp, stack_offset(sp) ret r26 $end_routine .page ;*8********************************************************************* $routine OP_ZSTZBSTART, entry=OP_ZSTZBSTART_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls stl r26, msf$mpc_off(r12) $call op_zbreak, args=, set_arg_info=false, nonstandard=true $call op_zst_break, set_arg_info=false, nonstandard=true getframe imb ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .page ;*9********************************************************************* $routine OP_ZSTZB_FET_OVER, entry=OP_ZSTZB_FET_OVER_CA, kind=null stack_offset = 16 lda sp, -stack_offset(sp) stq r3, (sp) stq r2, 8(sp) mov r27, r3 .base r3, $ls stl r26, msf$mpc_off(r12) fetch_args r2, stack_offset $call op_zbreak, args=, set_arg_info=false, nonstandard=true ldq r28, a_zstep_level ldl r28, (r28) subq r28, r12, r28 ble r28, 10$ beq r0, 20$ $call op_zst_over, set_arg_info=false, nonstandard=true ldl r26, msf$mpc_off(r12) br lbl30a 10$: $call op_zst_break, set_arg_info=false, nonstandard=true 20$: getframe imb lbl30a: ldq r3, (sp) ldq r2, 8(sp) lda sp, stack_offset(sp) ret r26 $end_routine .page ;*10******************************************************************** $routine OP_ZSTZB_ST_OVER, entry=OP_ZSTZB_ST_OVER_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls stl r26, msf$mpc_off(r12) $call op_zbreak, args=, set_arg_info=false, nonstandard=true ldq r28, a_zstep_level ldl r28, (r28) subq r28, r12, r28 ble r28, 10$ beq r0, 20$ $call op_zst_over, set_arg_info=false, nonstandard=true ldl r26, msf$mpc_off(r12) br lbl30b 10$: $call op_zst_break, set_arg_info=false, nonstandard=true 20$: getframe imb lbl30b: ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .page ;*11******************************************************************** $routine OP_ZST_FET_OVER, entry=OP_ZST_FET_OVER_CA, kind=null stack_offset = 16 lda sp, -stack_offset(sp) stq r3, (sp) stq r2, 8(sp) mov r27, r3 .base r3, $ls stl r26, msf$mpc_off(r12) fetch_args r2, stack_offset ldq r28, a_zstep_level ldl r28, (r28) subq r28, r12, r28 bgt r28, lbl10a $call op_zst_break, set_arg_info=false, nonstandard=true getframe imb br lbl20a lbl10a: $call op_zst_over, set_arg_info=false, nonstandard=true ldl r26, msf$mpc_off(r12) lbl20a: ldq r3, (sp) ldq r2, 8(sp) lda sp, stack_offset(sp) ret r26 $end_routine .page ;*12******************************************************************** $routine OP_ZST_ST_OVER, entry=OP_ZST_ST_OVER_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls stl r26, msf$mpc_off(r12) ldq r28, a_zstep_level ldl r28, (r28) subq r28, r12, r28 bgt r28, lbl10b $call op_zst_break, set_arg_info=false, nonstandard=true getframe imb br lbl20b lbl10b: $call op_zst_over, set_arg_info=false, nonstandard=true ldl r26, msf$mpc_off(r12) lbl20b: ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .page ;*13******************************************************************** $routine OPP_ZST_OVER_RET, entry=OPP_ZST_OVER_RET_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls ldl r28, msf$typ_off(r12) blbc r28, 10$ ldq r28, a_zstep_level ldl r28, (r28) ldl r24, msf$old_frame_off(r12) subq r28, r24, r28 bgt r28, 10$ $call op_zstepret, set_arg_info=false, nonstandard=true 10$: ldq r26, a_opp_ret ldq r27, a_opp_ret+8 ldq r3, (sp) lda sp, 8(sp) jmp r26 $end_routine ;*14******************************************************************** $routine OPP_ZST_OVER_RETARG, entry=OPP_ZST_OVER_RETARG_CA, kind=null lda sp, -24(sp) stq r3, (sp) stq r0, 8(sp) stq r1, 16(sp) mov r27, r3 .base r3, $ls ldl r28, msf$typ_off(r12) blbc r28, 10$ ldq r28, a_zstep_level ldl r28, (r28) ldl r24, msf$old_frame_off(r12) subq r28, r24, r28 bgt r28, 10$ $call op_zstepret, set_arg_info=false, nonstandard=true 10$: ldq r26, a_op_retarg ldq r27, a_op_retarg+8 ldq r3, (sp) ldq r0, 8(sp) ldq r1, 16(sp) lda sp, 24(sp) jmp r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_call.m640000644000032200000250000000216612201176167015765 0ustar librarygtc .title OP_CALL ; ############################################################### ; # # ; # Copyright 2001, 2003 Sanchez Computer Associates, Inc. # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ############################################################### G_MSF $linkage_section a_frame_pointer: .address frame_pointer $code_section $routine OP_CALLB, entry=OP_CALL_CA, aliases=, kind=null lda sp, -16(sp) stq r3, 8(sp) stq r26, (sp) mov r27, r3 .base r3, $ls ldq r1, a_frame_pointer ldl r1, (r1) ; Bump the return PC past the branch instruction following the jsr that got us here: addl r26, r16, r26 ; length of branch sequence stl r26, msf$mpc_off(r1) ; and store it in the Mumps stack frame $call COPY_STACK_FRAME, set_arg_info=false, nonstandard=true ldq r12, a_frame_pointer ldl r12, (r12) ldq r28, (sp) ldq r3, 8(sp) lda sp, 16(sp) ret r28 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_callsp.m640000644000032200000250000000240212201176167016321 0ustar librarygtc .title OP_CALLSP ; ############################################################### ; # # ; # Copyright 2001, 2007 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ############################################################### G_MSF $linkage_section a_frame_pointer: .address frame_pointer $code_section $routine OP_CALLSPB, entry=OP_CALLSP_CA, aliases=, kind=null lda sp, -16(sp) stq r3, 8(sp) stq r26, (sp) mov r27, r3 .base r3, $ls ldq r1, a_frame_pointer ldl r1, (r1) ; Bump the return PC past the branch instruction following the jsr that got us here: addl r26, r16, r26 ; length of branch sequence stl r26, msf$mpc_off(r1) ; and store it in the Mumps stack frame $call EXFUN_FRAME, set_arg_info=false, nonstandard=true ldl r16, 0(r10) ; Value of $TEST $call PUSH_TVAL, args=, set_arg_info=false, nonstandard=true ldq r12, a_frame_pointer ldl r12, (r12) ldl r9, msf$temps_ptr_off(r12) ldq r28, (sp) ldq r3, 8(sp) lda sp, 16(sp) ret r28 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_contain.m640000644000032200000250000001573512201176167016513 0ustar librarygtc;################################################################# ;# # ;# Copyright 2006, 2008 Fidelity Information Services, Inc # ;# # ;# This source code contains the intellectual property # ;# of its copyright holder(s), and is made available # ;# under a license. If you do not know the terms of # ;# the license, please stop and do not read further. # ;# # ;################################################################# .title op_contain "'[' ('contains') operator" ; OP_CONTAIN implements the MUMPS string relational operator "[" ("contains"): ; ; lhs [ rhs ; ; lhs ("left-hand-side") and rhs ("right-hand-side") are expressions interpreted ; as strings. If rhs is contained exactly somewhere in lhs, the resulting ; relation is true, otherwise, false. ; ; On entry to this routine: ; r0 -> mval for lhs ; r1 -> mval for rhs ; ; This version of OP_CONTAIN is not a simple, straightforward translation of the ; VAX version. The VAX has a rich set of instructions that can be used for string ; manipulation, and the VAX version of this routine takes advantage of that, using ; locc and cmpb instructions, as well as auto-increment addressing mode. None of ; these features exist in the Alpha architecture. Alpha does have a set of byte ; manipulation instructions, however, but they work only on data in registers. ; Thus, it makes sense to load as much of the strings in question into registers ; as is feasible, rather than working with just one byte at a time. mval$def $routine OP_CONTAIN, entry=OP_CONTAIN_CA, kind=null ; Routine prologue: lda sp, -48(sp) stq r26, (sp) stq r13, 8(sp) stq r2, 16(sp) stq r3, 24(sp) stq r4, 32(sp) stq r5, 40(sp) mov r27, r13 ; Set up a base register .base r13, $ls ; for the linkage section ; End of prologue .page ; ************************************************************************************** ; Validate the input parameters and handle the trivial cases. ; Make sure that both lhs and rhs are strings: mov r0, r2 ; r2 -> lhs mval mov r1, r3 ; r3 -> rhs mval mv_force_defined r2 mv_force_str (r2) mv_force_defined r3 mv_force_str (r3) ; If rhs is a null string, we have a match (by definition): ldl r1, mval$l_strlen(r3) ; r1 = length of rhs string beq r1, match ; If lhs is a null string, we don't have a match: ldl r0, mval$l_strlen(r2) ; r0 = length of lhs string beq r0, nomatch ; If lhs is shorter than rhs, there can't possibly be a match: cmplt r0, r1, r24 blbs r24, nomatch ; ************************************************************************************** ; OK, neither string is null, and their lengths check out; load as much ; of rhs as possible into r5 (i.e. min (8, length of rhs) characters), ; then load the same number of characters from lhs into r4. ; Load the first 8 characters of rhs into r5: ldl r3, mval$a_straddr(r3) ; r3 -> rhs string ldq_u r5, (r3) ldq_u r28, 7(r3) extql r5, r3, r5 extqh r28, r3, r28 or r28, r5, r5 ; Load the first 8 characters of lhs into r4: ldl r2, mval$a_straddr(r2) ; r2 -> lhs string ldq_u r4, (r2) ldq_u r28, 7(r2) extql r4, r2, r4 extqh r28, r2, r28 or r28, r4, r4 ; Compute the number of characters to retain in r5 and r4: mov 8, r22 cmplt r1, r22, r24 cmovlbs r24, r1, r22 ; r22 = min (8, r1) ; Clear any excess characters that may have been loaded above: mov ^xff, r28 sll r28, r22, r28 zap r5, r28, r5 zap r4, r28, r4 ; Update the string counters and pointers: subq r1, r22, r1 subq r0, r22, r0 addq r3, r22, r3 addq r2, r22, r2 ; Compute a shift count for later use in loading new characters from lhs into r4: subq r22, 1, r22 sll r22, 3, r22 ; ************************************************************************************** ; At this point, ; r5 contains either all of rhs, or the first 8 characters of rhs ; r4 contains the corresponding number of characters from lhs ; r22 = a shift count to use for loading new characters from lhs into r4 ; r1 = the number of characters remaining in rhs (exclusive of what's in r5) ; r0 = the number of characters remaining in lhs (exclusive of what's in r4) ; r3 -> the remainder of rhs (meaningful only if r1 > 0) ; r2 -> the remainder of lhs main_loop: cmpeq r4, r5, r24 ; If there's a match here, go check the remainder of rhs: blbs r24, check_remainder ; There's no match this iteration; if nothing's left in lhs, return false: beq r0, nomatch ; Return here from check_remainder if no match was found there, either: restart: ; Load the next character from lhs into r4: srl r4, 8, r4 ; shift everything down by a byte, losing the low order character ldq_u r28, (r2) ; load the quadword containing the next character in lhs extbl r28, r2, r28 ; extract the character sll r28, r22, r28 ; shift it up into the correct position or r28, r4, r4 ; and stick it into r4 ; Update the lhs context: subq r0, 1, r0 lda r2, 1(r2) ; And try again: br main_loop .page ; ************************************************************************************** ; The main loop found a match somewhere in lhs with the first portion of rhs. We now ; have to check to see if the remainder of rhs (if any) matches the same number of characters ; in the remainder of lhs. check_remainder: ; If there's nothing left in rhs, we have a match: beq r1, match ; If there are fewer characters remaining in lhs than there are in rhs, ; then there can't possibly be a match: cmplt r0, r1, r28 blbs r28, nomatch ; Save context: mov r1, r17 ; r17 = remaining length of rhs mov r3, r19 ; r19 -> remainder of rhs mov r2, r18 ; r18 -> remainder of lhs ; Now loop, comparing the remainders of the two strings. remainder_loop: ; Load the first 8 characters of the remainder of rhs into r21: ldq_u r21, (r19) ldq_u r28, 7(r19) extql r21, r19, r21 extqh r28, r19, r28 or r28, r21, r21 ; Load the first 8 characters of the remainder of lhs into r20: ldq_u r20, (r18) ldq_u r28, 7(r18) extql r20, r18, r20 extqh r28, r18, r28 or r28, r20, r20 ; Should we compare all 8 characters? cmplt r17, 8, r24 blbc r24, compare ; yes; skip ; We need to compare fewer than 8 characters, so ; clear the excess characters that were loaded above: mov ^xff, r28 sll r28, r17, r28 zap r21, r28, r21 zap r20, r28, r20 compare: cmpeq r20, r21, r24 ; If no match, go back to the main loop and try again: blbc r24, restart ; Update for the next iteration: subq r17, 8, r17 ble r17, match lda r19, 8(r19) lda r18, 8(r18) br remainder_loop ; ************************************************************************************** nomatch: clr r0 br return match: mov 1, r0 return: mov r0, r24 ; set condition code (emulator) according to function result ; Routine epilogue: ldq r28, (sp) ldq r13, 8(sp) ldq r2, 16(sp) ldq r3, 24(sp) ldq r4, 32(sp) ldq r5, 40(sp) lda sp, 48(sp) ret r28 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_currtn.m640000644000032200000250000000210512201176167016360 0ustar librarygtc;################################################################# ;# # ;# Copyright 2006, 2008 Fidelity Information Services, Inc # ;# # ;# This source code contains the intellectual property # ;# of its copyright holder(s), and is made available # ;# under a license. If you do not know the terms of # ;# the license, please stop and do not read further. # ;# # ;################################################################# .title OP_CURRTN g_msf mval$def $routine OP_CURRTN, entry=OP_CURRTN_CA, kind=null lda sp, -16(sp) stq r26, (sp) .base r27, $ls ; Set r1->mval$b_mvtype to mval$m_str (r1->mvtype = MV_STR): ldl r28, mval$w_mvtype(r1) mskwl r28, mval$w_mvtype, r28 or r28, mval$m_str, r28 stl r28, mval$w_mvtype(r1) ldl r0, msf$rvector_off(r12) ldl r16, mrt$rtn_len(r0) stl r16, mval$l_strlen(r1) ; r1->str.len = frame_pointer->rvector->routine_name.len ldl r16, mrt$rtn_addr(r0) stl r16, mval$a_straddr(r1) ; r1->str.addr = frame_pointer->rvector->routine_name.addr ldq r26, (sp) lda sp, 16(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_equ.m640000644000032200000250000000147612201176167015647 0ustar librarygtc .title op_equ determine whether two mvals are equal ; op_equ ; ; op_equ calls is_equ to compare two mval operands to determine ; whether they are equal. The actual comparison is performed by ; the C-callable routine is_equ; op_equ is needed as an interlude ; between generated GT.M code that passes the arguments in r0 ; and r0 instead of in the argument registers. ; ; entry ; r0, r1 contain addresses of mval's to be compared ; ; return ; r0 1, if the two mval's are equal ; 0, if they're not equal $routine name=op_equ,entry=op_equ_ca,kind=stack, - base_reg_is_fp=true,rsa_offset=24,saved_regs= .base r27, $ls mov r0, r16 mov r1, r17 $call is_equ, args=, set_arg_info=false mov r0, r24 ; copy is_equ's return value to GT.M's condition code register $return $end_routine name=op_equ .end fis-gtm-V6.0-003/sr_avms/op_exfun.m640000644000032200000250000000510312201176167016171 0ustar librarygtc .title op_exfun - invoke (internal) extrinsic function ; ############################################################### ; # # ; # Copyright 2001, 2012 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ############################################################### G_MSF ; op_exfun - invoke (internal) extrinsic function ; ; arguments: ; ret_value address for function to place return value ; offset to this frame's continue (return) point past branch to subroutine ; mask ; actualcnt actual argument count ; actual1 address of actual first argument ; actual2 address of actual second argument ; . . . $routine name=op_exfun, entry=op_exfun_ca, kind=stack, saved_regs=, - data_section_pointer=true, - data_section=<$DATA$, QUAD, NOPIC, CON, REL, LCL, NOSHR, MIX, NOEXE, RD, WRT> $linkage_section A_frame_pointer: .address frame_pointer $code_section mov r27, r13 .base r13, $ls ldq r1, A_frame_pointer ldl r1, (r1) addl r26, r17, r28 ; add size of jump sequence to get return addr for frame. stl r28, msf$mpc_off(r1) $call exfun_frame, set_arg_info=false ldl r16, 0(r10) ; $TRUTH aka $TEST value bic r16, #^Xfe, r16 ; clear all but low order bit ldq r17, $RSA_OFFSET+24(fp) ; old r16 (ret_value) ldq r18, $RSA_OFFSET+40(fp) ; old r18 (mask) ldq r19, $RSA_OFFSET+48(fp) ; old r19 (actualcnt) ldq r20, $RSA_OFFSET+56(fp) ; old r20 (actual1) ldq r21, $RSA_OFFSET+64(fp) ; old r21 (actual2) lda r25, 4(r19) ; If more than 2 actual arguments, push rest onto stack. subq r19, 2, r28 ; number of arguments originally passed on stack (actual3 . . . actualn) ble r28, zero_in_stack ; all original arguments in registers lda r0, $SIZE(fp) subq r28, 1, r28 ; offset = number - 1 s8addq r28, r0, r0 ; address of actualn loop: ldq r1, (r0) lda sp, -8(sp) lda r0, -8(r0) stq r1, (sp) subq r28, 1, r28 bge r28, loop zero_in_stack: $call push_parm, set_arg_info=false ; push_parm ($T, ret_value, mask, actualcnt [, actual1[, actual2 . . .]]) done: ldq r28, A_frame_pointer ldl r2, (r28) mov r2, r12 ldl r9, msf$temps_ptr_off(r12) $begin_epilogue mov fp, sp ldq r26, $RSA_OFFSET(sp) ldq r2, $RSA_OFFSET+8(sp) ldq r13, $RSA_OFFSET+16(sp) ldq fp, $RSA_OFFSET+72(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue $end_routine name=op_exfun .end fis-gtm-V6.0-003/sr_avms/op_extcall.m640000644000032200000250000000601412201176167016502 0ustar librarygtc .title op_extcall - call external (MUMPS) routine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2005, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; G_MSF PROCDESC ; op_extcall calls and external GT.M MUMPS routine. If the routine has not yet ; been linked into the current image, op_extcall will first link it by invoking ; the auto-ZLINK function. ; ; Args: ; procdsc - address of procedure descriptor of routine to call ; labaddr - address of offset into routine to which to transfer control $routine name=op_extcall, entry=op_extcall_ca, kind=stack, saved_regs=, - data_section_pointer=true $linkage_section A_frame_pointer: .address frame_pointer L_ERR_GTMCHECK: .long ERR_GTMCHECK L_ERR_LABELUNKNOWN: .long ERR_LABELUNKNOWN $data_section PDSC_FLAGS: .long GTM_PD_FLAGS $code_section .base r27, $ls ldq r22, $dp .base r22, $ds putframe r12 mov r27, r13 .base r13, $ls beq r16, L20 ; if procdsc == 0, this routine has not yet been linked into current image beq r17, L40 ; if labaddr == 0 (and procdsc != 0), there is some interal error ; Check whether first argument is procedure descriptor or routine header. ldl r28, PDSC_FLAGS ldl r0, (r16) xor r28, r0, r28 bne r28, L10 ; if not procedure descriptor, it must be a routine header ldq r16, 8(r16) ; rhdaddr = procdsc->entry_point ; entry point address is address of routine header L10: ldl r17, (r17) ; *lab_ln_ptr beq r17, L40 ldl r28, mrt$curr_ptr(r16) addl r17, r28, r17 addl r17, r16, r17 ; rhdaddr + *lab_ln_ptr ldl r17, (r17) ; *labaddr ldl r28, mrt$curr_ptr(r16) ; rhdaddr->current_rhead_ptr addl r16, r28, r18 ; rhdaddr + rhdaddr->current_rhead_ptr addl r17, r18, r18 ; rhdaddr + rhdaddr->current_rhead_ptr + *labaddr $call new_stack_frame, args=, set_arg_info=false $begin_epilogue getframe mov fp, sp ldq fp, $RSA_OFFSET+8(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue L20: bne r17, L40 ; if labaddr != 0 (and procdsc == 0), there is some internal error lda sp, -8(sp) ; auto_zlink will put value here stq r31, (sp) $call auto_zlink, args=, set_arg_info=false beq r0, L30 mov r0, r16 ; rhdaddr of newly-ZLINK'ed routine ldq r17, (sp) ; new labaddr lda sp, 8(sp) beq r17, L30 br L10 ; auto_zlink returns pointer to a routine header, not a procedure descriptor L30: $call lib$signal, args= $begin_epilogue getframe mov fp, sp ldq fp, $RSA_OFFSET+8(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue L40: $call lib$signal, args= $begin_epilogue getframe mov fp, sp ldq fp, $RSA_OFFSET+8(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue $end_routine name=op_extcall .end fis-gtm-V6.0-003/sr_avms/op_extexfun.m640000644000032200000250000001111712201176167016714 0ustar librarygtc .title op_extexfun - invoke external extrinsic function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2005, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; G_MSF PROCDESC ; op_extexfun - invoke external extrinsic function ; ; arguments: ; routine address of procedure descriptor of procedure containing extrinsic function ; label address of offset into routine to which to transfer control ; ret_value address for function to place return value ; mask ; actualcnt actual argument count ; actual1 address of actual first argument ; actual2 address of actual second argument ; . . . $routine name=op_extexfun, entry=op_extexfun_ca, kind=stack, saved_regs=, - data_section_pointer=true, - data_section=<$DATA$, QUAD, NOPIC, CON, REL, LCL, NOSHR, MIX, NOEXE, RD, WRT> $linkage_section A_frame_pointer: .address frame_pointer L_ERR_FMLLSTMISSING: .long ERR_FMLLSTMISSING L_ERR_GTMCHECK: .long ERR_GTMCHECK L_ERR_LABELUNKNOWN: .long ERR_LABELUNKNOWN $data_section PDSC_FLAGS: .long GTM_PD_FLAGS $code_section .base r27, $ls ldq r2, $dp .base r2, $ds putframe mov r27, r13 .base r13, $ls L9: beq r16, L20 ; if procdsc == 0, this routine has not yet been linked into current image beq r17, L40 ; if labaddr == 0 (and procdsc != 0), it's an unknown label ; Check whether first argument is procedure descriptor or routine header. ldl r28, PDSC_FLAGS ldl r0, (r16) xor r28, r0, r28 bne r28, L10 ; if not procedure descriptor, it must be a routine header ldq r16, 8(r16) ; rhdaddr = procdsc->entry_point ; entry point address is address of routine header L10: mov r17, r22 ; temporarily save labaddr, so it is not overriden ldl r17, (r17) ; *lab_ln_ptr beq r17, L40 ldl r28, mrt$curr_ptr(r16) addl r17, r28, r17 addl r17, r16, r17 ; rhdaddr + *lab_ln_ptr ldl r17, (r17) ; *labaddr ldl r28, mrt$curr_ptr(r16) ; rhdaddr->current_rhead_ptr addl r16, r28, r18 ; rhdaddr + rhdaddr->current_rhead_ptr addl r17, r18, r18 ; rhdaddr + rhdaddr->current_rhead_ptr + *labaddr mov r22, r17 ; restore the original labaddr addq r17, 4, r17 ; labaddr += 4, to point to has_parms ldl r17, (r17) ; *has_parms beq r17, L50 ; if has_parms == 0, then issue an error L12: $call new_stack_frame, args=, set_arg_info=false ldl r16, 0(r10) ; push $TRUTH aka $TEST bic r16, #^Xfe, r16 ; clear all but low order bit L15: ldq r17, $RSA_OFFSET+24(fp) ; old r18 (ret_value) ldq r18, $RSA_OFFSET+32(fp) ; old r19 (mask) ldq r19, $RSA_OFFSET+40(fp) ; old r20 (actualcnt) ldq r20, $RSA_OFFSET+48(fp) ; old r21 (actual1) ldq r21, $SIZE(fp) ; actual2, if any lda r25, 4(r19) ; If more than 1 argument, push rest onto stack. subq r19, 2, r28 ; number of arguments to put onto stack (actual3 . . . actualn) ble r28, zero_in_stack ; all original arguments in registers lda r0, $SIZE(fp) s8addq r28, r0, r0 ; address of actualn loop: ldq r1, (r0) lda sp, -8(sp) lda r0, -8(r0) stq r1, (sp) subq r28, 1, r28 bgt r28, loop zero_in_stack: $call push_parm, set_arg_info=false ; push_parm ($T, ret_value, mask, argc[, actual1[, actual2 . . .]]) L16: getframe $begin_epilogue mov fp, sp ldq r2, $RSA_OFFSET+8(sp) ldq fp, $RSA_OFFSET+56(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue L20: bne r17, L30 ; procdsc == 0, but label != 0 => internal error lda sp, -8(sp) ; auto_zlink will put value here stq r31, (sp) $call auto_zlink, args=, set_arg_info=false beq r0, L30 mov r0, r16 ; rhdaddr of newly-ZLINK'ed routine ldq r17, (sp) ; new labaddr lda sp, 8(sp) beq r17, L40 ; found routine, but labaddr still 0 => unknown label br L10 L30: $call lib$signal, args= $begin_epilogue getframe mov fp, sp ldq r2, $RSA_OFFSET+8(sp) ldq fp, $RSA_OFFSET+56(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue L40: $call lib$signal, args= $begin_epilogue getframe mov fp, sp ldq r2, $RSA_OFFSET+8(sp) ldq fp, $RSA_OFFSET+56(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue L50: $call lib$signal, args= $begin_epilogue getframe mov fp, sp ldq r2, $RSA_OFFSET+8(sp) ldq fp, $RSA_OFFSET+56(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue $end_routine name=op_extexfun .end fis-gtm-V6.0-003/sr_avms/op_extjmp.m640000644000032200000250000000611312201176167016355 0ustar librarygtc .title op_extjmp - jump to a label in an external (MUMPS) routine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2005, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; G_MSF PROCDESC ; op_extjmp transfers control to a label in an external MUMPS module. If the routine ; has not yet been linked into the current image, op_extjmp will first link it by ; invoking the auto-ZLINK function. ; ; Args: ; procdsc - address of procedure descriptor of routine containing the label ; labaddr - address of offset into routine to which to transfer control $routine name=op_extjmp, entry=op_extjmp_ca, kind=stack, saved_regs=, - data_section_pointer=true $linkage_section A_frame_pointer: .address frame_pointer L_ERR_GTMCHECK: .long ERR_GTMCHECK L_ERR_LABELUNKNOWN: .long ERR_LABELUNKNOWN $data_section PDSC_FLAGS: .long GTM_PD_FLAGS $code_section .base r27, $ls ldq r22, $dp .base r22, $ds putframe r12 mov r27, r13 .base r13, $ls beq r16, L20 ; if procdsc == 0, this routine has not yet been linked into current image beq r17, L40 ; if labaddr == 0 (and procdsc != 0), there is some interal error ; Check whether first argument is a procedure descriptor or routine header. ldl r28, PDSC_FLAGS ldl r0, (r16) xor r28, r0, r28 bne r28, L10 ; if not procedure descriptor, it must be a routine header ldq r16, 8(r16) ; rhdaddr = procdsc->entry_point ; entry point address is address of routine header L10: ldl r17, (r17) ; *lab_ln_ptr beq r17, L40 ldl r28, mrt$curr_ptr(r16) addl r17, r28, r17 addl r17, r16, r17 ; rhdaddr + *lab_ln_ptr ldl r17, (r17) ; *labaddr ldl r28, mrt$curr_ptr(r16) ; rhdaddr->current_rhead_ptr addl r16, r28, r18 ; rhdaddr + rhdaddr->current_rhead_ptr addl r17, r18, r18 ; rhdaddr + rhdaddr->current_rhead_ptr + *labaddr $call flush_jmp, args=, set_arg_info=false $begin_epilogue getframe imb mov fp, sp ldq fp, $RSA_OFFSET+16(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue L20: bne r17, L40 ; if labaddr != 0 (and procdsc == 0), there is some internal error lda sp, -8(sp) ; auto_zlink will put value here stq r31, (sp) $call auto_zlink, args=, set_arg_info=false beq r0, L30 mov r0, r16 ; rhdaddr of newly-ZLINK'ed routine ldq r17, (sp) ; new labaddr lda sp, 8(sp) beq r17, L40 br L10 ; auto_zlink returns pointer to a routine header, not a procedure descriptor L30: $call lib$signal, args= $begin_epilogue getframe imb mov fp, sp ldq fp, $RSA_OFFSET+16(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue L40: $call lib$signal, args= $begin_epilogue getframe imb mov fp, sp ldq fp, $RSA_OFFSET+16(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue $end_routine name=op_extjmp .end fis-gtm-V6.0-003/sr_avms/op_fetchintrrpt.m640000644000032200000250000000171512201176167017565 0ustar librarygtc .title OP_FETCHINTRRPT G_MSF $linkage_section a_neterr_pending: .address neterr_pending a_iott_write_error: .address iott_write_error $code_section $routine OP_FETCHINTRRPT, entry=OP_FETCHINTRRPT_CA, kind=null stack_offset = 16 lda sp, -stack_offset(sp) stq r13, (sp) stq r2, 8(sp) mov r27, r13 .base r13, $ls stl r26, msf$mpc_off(r12) fetch_args r2, stack_offset ldq r0, a_neterr_pending ldq_u r24, (r0) extbl r24, r0, r24 beq r24, 10$ $call outofband_clear, set_arg_info=false, nonstandard=true $call gvcmz_neterr, args=<0/a>, set_arg_info=false, nonstandard=true 10$: ldq r0, a_iott_write_error ldl r24, (r0) beq r24, 15$ $call outofband_clear, set_arg_info=false, nonstandard=true $call iott_wrterr, set_arg_info=false, nonstandard=true 15$: $call async_action, args=<1/a>, set_arg_info=false, nonstandard=true 20$: ldl r28, msf$mpc_off(r12) ldq r13, (sp) ldq r2, 8(sp) lda sp, stack_offset(sp) ret r28 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_fnget.m640000644000032200000250000000276012201176167016155 0ustar librarygtc;################################################################# ;# # ;# Copyright 2006, 2009 Fidelity Information Services, Inc # ;# # ;# This source code contains the intellectual property # ;# of its copyright holder(s), and is made available # ;# under a license. If you do not know the terms of # ;# the license, please stop and do not read further. # ;# # ;################################################################# .title op_fnget "$Get() function" ; OP_FNGET implements the $Get() function. ; Upon entry, r1 -> source mval, r0 -> target mval. ; If the source mval is defined, it is copied to the target, ; otherwise, the target mval is set to be a null string. mval$def $routine OP_FNGET, entry=OP_FNGET_CA, kind=null beq r1, undefined ; a nonexistent source is undefined mv_if_notdefined (r1), undefined ; Copy the source mval to the target: mov mval$m_aliascont, r24 ldl r22, mval$w_mvtype(r1) ; includes mval$b_exp and the unreferenced fnpcid ldl r23, mval$l_strlen(r1) bic r22, r24, r22 ; don't allow propagation of alias container flag ldl r24, mval$a_straddr(r1) stl r22, mval$w_mvtype(r0) stl r23, mval$l_strlen(r0) stl r24, mval$a_straddr(r0) ldl r22, mval$l_m0(r1) ldl r23, mval$l_m1(r1) stl r22, mval$l_m0(r0) stl r23, mval$l_m1(r0) ret r26 undefined: ; Set the target mval to a null string: mov mval$m_str, r22 clr r23 stl r22, mval$w_mvtype(r0) ; also clears mval$b_exp stl r23, mval$l_strlen(r0) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_fnzextract.m640000644000032200000250000000335712201176167017245 0ustar librarygtc;################################################################# ;# # ;# Copyright 2006, 2008 Fidelity Information Services, Inc # ;# # ;# This source code contains the intellectual property # ;# of its copyright holder(s), and is made available # ;# under a license. If you do not know the terms of # ;# the license, please stop and do not read further. # ;# # ;################################################################# .title OP_FNZEXTRACT mval$def $routine OP_FNZEXTRACT, entry=OP_FNZEXTRACT_CA, kind=null lda sp, -48(sp) stq r26, (sp) stq r2, 8(sp) stq r3, 16(sp) stq r4, 24(sp) stq r5, 32(sp) stq r13, 40(sp) mov r27, r13 .base r13, $ls mov r16, r5 ; r5 = second index mov r17, r4 ; r4 = first index mov r18, r2 ; r2 -> source mval mov r19, r3 ; r3 -> result mval mv_force_defined r2 mv_force_str (r2) cmovle r4, 1, r4 ; r4 = start = max(1, first index) ldl r1, mval$l_strlen(r2) ; r1 = length of source string subq r4, r1, r24 ; if start > source length, bgt r24, 20$ ; then result is a null string subq r5, r1, r24 cmovgt r24, r1, r5 ; r5 = end = min(source length, second index) subq r5, r4, r0 addq r0, 1, r0 ; r0 = result length = end - start + 1 beq r0, 10$ blt r0, 20$ ldl r28, mval$a_straddr(r2) ; r28 = address of source string addq r4, r28, r4 subq r4, 1, r4 ; r4 = result address = source address + start - 1 stl r4, mval$a_straddr(r3) 10$: mov mval$m_str, r28 stl r0, mval$l_strlen(r3) ; set result length stl r28, mval$w_mvtype(r3) ; set result type (always a string) ldq r28, (sp) ldq r2, 8(sp) ldq r3, 16(sp) ldq r4, 24(sp) ldq r5, 32(sp) ldq r13, 40(sp) lda sp, 48(sp) ret r28 ; Result is a null string: 20$: clr r0 br 10$ $end_routine .end fis-gtm-V6.0-003/sr_avms/op_follow.m640000644000032200000250000000451712201176167016356 0ustar librarygtc;################################################################# ;# # ;# Copyright 2006, 2008 Fidelity Information Services, Inc # ;# # ;# This source code contains the intellectual property # ;# of its copyright holder(s), and is made available # ;# under a license. If you do not know the terms of # ;# the license, please stop and do not read further. # ;# # ;################################################################# .title op_follow ; op_follow implements the MUMPS string relational operator "]" ("follows"): ; ; lhs ] rhs ; ; lhs ("left-hand-side") and rhs ("right-hand-side") are expressions interpreted ; as strings. If lhs follows rhs in the ASCII collaring sequence, the resulting ; relation is true, otherwise, false (actually, this function differs slightly -- ; see description of exit conditions below). ; ; According to the ANSI standard, ANSI/MDC X11.1-1990, the relation is true iff ; any of the following is true: ; ; a. rhs is empty and lhs is not. ; b. neither lhs nor rhs is empty and the leftmost character of lhs ; follows (has numeric code greater than) the leftmost character of rhs. ; c. There exists a positive integer n such that lhs and rhs have ; identical heads of length n (i.e., $E(lhs,1,n)=$E(rhs,1,n)) and the ; remainder of lhs follows the remainder of rhs. ; ; Entry: ; r0 -> lhs mval ; r1 -> rhs mval ; ; Exit: ; r0 = >0, if lhs follows rhs ; 0, if lhs equals rhs ; <0, if rhs follows lhs (allows reversal of operands and subsequent test) MVAL$DEF $routine name=op_follow, entry=op_follow_ca, kind=stack, saved_regs= mov r27, r13 .base r13, $ls ; Make sure both lhs and rhs are strings. mov r0, r2 ; r2 <- address of lhs mval mov r1, r3 ; r3 <- address of rhs mval mv_force_defined r2 mv_force_str (r2) mv_force_defined r3 mv_force_str (r3) ; Obtain string lengths. ldl r17, mval$l_strlen(r2) ldl r19, mval$l_strlen(r3) $call memvcmp, args=, set_arg_info=false mov r0, r24 ; set condition code (emulator) according to function result $return $end_routine .end fis-gtm-V6.0-003/sr_avms/op_forcenum.m640000644000032200000250000000364312201176167016671 0ustar librarygtc;################################################################# ;# # ;# Copyright 2006, 2008 Fidelity Information Services, Inc # ;# # ;# This source code contains the intellectual property # ;# of its copyright holder(s), and is made available # ;# under a license. If you do not know the terms of # ;# the license, please stop and do not read further. # ;# # ;################################################################# .title OP_FORCENUM mval$def $routine OP_FORCENUM, entry=OP_FORCENUM_CA, kind=null lda sp, -32(sp) stq r26, (sp) stq r13, 8(sp) mov r27, r13 .base r13, $ls stq r0, 16(sp) mv_force_defined r1 stq r1, 24(sp) mv_force_num (r1) ldq r0, 16(sp) ldq r1, 24(sp) mv_if_notstring (r1), 10$ ldl r28, (r1) and r28, mval$m_num_approx, r28 beq r28, 30$ 10$: mv_if_notint (r1), 20$ ; Set mvtype to int: ldl r28, mval$w_mvtype(r0) mskwl r28, mval$w_mvtype, r28 or r28, mval$m_int, r28 stl r28, mval$w_mvtype(r0) ; Copy r1->m1 to r0->m1 ldl r24, mval$l_m1(r1) stl r24, mval$l_m1(r0) ; Return: ldq r26, (sp) ldq r13, 8(sp) lda sp, 32(sp) ret r26 ; Copy r1->exp to r0->exp, and set r0->mvtype = nm: 20$: ldl r28, mval$w_mvtype(r1) ; r28 = longword containing r1->exp zapnot r28, ^X1@mval$b_exp, r28 ; clear all but the exp field or r28, mval$m_nm, r28 ; set the mvtype field to nm stl r28, mval$w_mvtype(r0) ; Copy r1->(m0,m1) to r0->(m0,m1) ldl r24, mval$l_m0(r1) ldl r28, mval$l_m1(r1) stl r24, mval$l_m0(r0) stl r28, mval$l_m1(r0) ; Return: ldq r26, (sp) ldq r13, 8(sp) lda sp, 32(sp) ret r26 ; Copy r1->mval to r0->mval ; (mval's are longword-aligned, and are 5 longwords long [mval$size = 20]): 30$: ldl r16, (r1) ldl r17, 4(r1) ldl r18, 8(r1) ldl r19, 12(r1) ldl r20, 16(r1) stl r16, (r0) stl r17, 4(r0) stl r18, 8(r0) stl r19, 12(r0) stl r20, 16(r0) ; Return: ldq r26, (sp) ldq r13, 8(sp) lda sp, 32(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_forchk1.m640000644000032200000250000000213612201176167016404 0ustar librarygtc; ################################################################ ; # # ; # Copyright 2008 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ################################################################ .title op_forchk1 ; op_forchk1 - dummy routine called at start of FOR-statement ; ; During normal execution, this routine would be called at the beginning of a For-statement. ; However, when it is desired to set a break at that location, the entry in the xfer table ; pointing to op_forchk1 would be altered to point to the desired alternative routine. $routine name=op_forchk1,entry=op_forchk1_ca,kind=null ret r26 $end_routine name=op_forchk1 fis-gtm-V6.0-003/sr_avms/op_forinit.m640000644000032200000250000000306612201176167016524 0ustar librarygtc;################################################################# ;# # ;# Copyright 2006, 2008 Fidelity Information Services, Inc # ;# # ;# This source code contains the intellectual property # ;# of its copyright holder(s), and is made available # ;# under a license. If you do not know the terms of # ;# the license, please stop and do not read further. # ;# # ;################################################################# .title OP_FORINIT G_MSF mval$def $routine OP_FORINIT, entry=OP_FORINIT_CA, kind=null stack_offset = 32 lda sp, -stack_offset(sp) stq r13, (sp) stq r2, 8(sp) stq r3, 16(sp) stq r4, 24(sp) mov r27, r13 .base r13, $ls stl r26, msf$mpc_off(r12) mov r16, r2 mov r17, r3 mov r18, r4 mv_force_defined r2 mv_force_num (r2) mv_force_defined r3 mv_force_num (r3) mv_force_defined r4 mv_force_num (r4) ldl r28, mval$l_m1(r3) blt r28, 40$ mv_if_int (r3), 30$ ; The following sequence emulates the Vax instruction: ; tstb mval$b_exp(r3) ldq_u r28, mval$b_exp(r3) lda r0, mval$b_exp+1(r3) extqh r28, r0, r28 blt r28, 40$ 30$: mov r2, r0 mov r4, r1 br 50$ 40$: mov r4, r0 mov r2, r1 50$: $call OP_NUMCMP, set_arg_info=false, nonstandard=true ldl r28, msf$mpc_off(r12) ldq r13, (sp) ldq r2, 8(sp) ldq r3, 16(sp) ldq r4, 24(sp) lda sp, stack_offset(sp) ret r28 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_forintrrpt.m640000644000032200000250000000161712201176167017263 0ustar librarygtc .title OP_FORINTRRPT G_MSF call_inst_size = 12 $linkage_section a_neterr_pending: .address neterr_pending a_iott_write_error: .address iott_write_error $code_section $routine OP_FORINTRRPT, entry=OP_FORINTRRPT_CA, kind=null stack_offset = 16 lda sp, -stack_offset(sp) stq r26, (sp) stq r13, 8(sp) mov r27, r13 .base r13, $ls ldq r0, a_neterr_pending ldq_u r24, (r0) extbl r24, r0, r24 beq r24, 10$ $call outofband_clear, set_arg_info=false, nonstandard=true $call gvcmz_neterr, args=<0/a>, set_arg_info=false, nonstandard=true 10$: ldq r0, a_iott_write_error ldl r24, (r0) beq r24, 15$ $call outofband_clear, set_arg_info=false, nonstandard=true $call iott_wrterr, set_arg_info=false, nonstandard=true 15$: $call async_action, args=<0/a>, set_arg_info=false, nonstandard=true 20$: ldq r26, (sp) ldq r13, 8(sp) lda sp, stack_offset(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_forlcldo.m640000644000032200000250000000224312201176167016652 0ustar librarygtc .title OP_FORLCLDO ; ############################################################### ; # # ; # Copyright 2001, 2003 Sanchez Computer Associates, Inc. # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ############################################################### G_MSF $linkage_section a_frame_pointer: .address frame_pointer $code_section $routine OP_FORLCLDOB, entry=OP_FORLCLDO_CA, aliases=, kind=null lda sp, -16(sp) stq r3, 8(sp) stq r26, (sp) mov r27, r3 .base r3, $ls ldq r1, a_frame_pointer ldl r1, (r1) ; Bump the return PC past the branch instruction following the jsr that got us here: addl r26, r16, r26 ; length of branch sequence stl r26, msf$mpc_off(r1) ; and store it in the Mumps stack frame $call EXFUN_FRAME, set_arg_info=false, nonstandard=true ldq r12, a_frame_pointer ldl r12, (r12) ldl r9, msf$temps_ptr_off(r12) ldq r28, (sp) ldq r3, 8(sp) lda sp, 16(sp) ret r28 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_forloop.m640000644000032200000250000001652112201176167016532 0ustar librarygtc;################################################################# ;# # ;# Copyright 2006, 2012 Fidelity Information Services, Inc # ;# # ;# This source code contains the intellectual property # ;# of its copyright holder(s), and is made available # ;# under a license. If you do not know the terms of # ;# the license, please stop and do not read further. # ;# # ;################################################################# .title OP_FORLOOP "FOR loop iteration logic" ; On entry: ; ; r16 -> index variable ; r17 -> step mval (guaranteed to be temp or lit and therefore defined as numeric) ; r18 -> terminator mval ; r19 -> return address to continue looping ; ; The usual return address in R26 is for loop termination. G_MSF mval$def $linkage_section ; These are read-only constants; it's convenient to stash them in the linkage section: mant_lo_val: .quad MANT_LO mant_hi_val: .quad MANT_HI $code_section $routine OP_FORLOOP, entry=OP_FORLOOP_CA, kind=null lda sp, -40(sp) stq r2, (sp) stq r3, 8(sp) stq r4, 16(sp) stq r13, 24(sp) mov r27, r13 .base r13, $ls ; Save the first three arguments in non-volatile registers: mov r16, r2 ; r2 -> index variable mval mov r17, r3 ; r3 -> step mval mov r18, r4 ; r4 -> terminator mval ; Save the loop termination return address in the Mumps stack frame: stl r26, msf$mpc_off(r12) ; Save the loop continuation return address on the stack: stq r19, 32(sp) mv_force_defined_strict r2 ; disregard NOUNDEF mv_force_num (r2) ; make sure the index variable is numeric mv_if_notint (r2), add_non_int ; branch if index is not int mv_if_notint (r3), add_non_int ; branch if step is not int ; Index and step are both int; that makes it easy to compute the new index value: ldl r22, mval$l_m1(r2) ; r22 = index value ldl r23, mval$l_m1(r3) ; r23 = step value addq r22, r23, r22 ; r22 = new index value [= old index + step] mv_if_notint (r4), add ; branch if terminator is not int ; At this point, index, step, and terminator are all int; that makes it easy to ; do the appropriate comparison between the new index value and the terminator: ldl r24, mval$l_m1(r4) ; r24 = terminator value cmple r31, r23, r26 ; r26 = (step >= 0) cmple r22, r24, r27 ; r27 = (index <= terminator) and r26, r27, r28 ; r28 = (step >= 0 and index <= terminator) xor r26, 1, r26 ; r26 = (step < 0) cmple r24, r22, r27 ; r27 = (index >= terminator) and r26, r27, r26 ; r26 = (step < 0 and index >= terminator) or r28, r26, r26 ; r26 = ((step >= 0 and index <= terminator) or (step < 0 and index >= terminator)) beq r26, terminate_loop ; branch if false; loop has terminated stl r22, mval$l_m1(r2) ; store new index value [= old index + step] ; Since index's value has changed, set its mvtype to int only ; (i.e. clear all bits except mval$m_int): ldl r26, mval$w_mvtype(r2) mskwl r26, mval$w_mvtype, r26 or r26, mval$m_int, r26 stl r26, mval$w_mvtype(r2) br continue_loop ; One or both of index and step are not int; add step to index: add_non_int: $call ADD_MVALS, args=, set_arg_info=false, nonstandard=true br compare ; At this point, index and step are int, but terminator is not; ; check the new index value (it's in r22): add: $call CHECK_INDEX, set_arg_info=false, nonstandard=true, local=true ; Do the appropriate comparison between the updated index value and the terminator: compare: mov r2, r0 ; r0 -> index mov r4, r1 ; r1 -> terminator mv_if_notint (r3), 15$ ; branch if step is not int ldl r28, mval$l_m1(r3) blt r28, 20$ ; branch if step's value is negative ; Branch if either index or terminator is not int: 5$: mv_if_notint (r0), compare_non_int mv_if_notint (r1), compare_non_int ; Index and terminator are both int; that makes the comparison easy: 10$: ldl r0, mval$l_m1(r0) ldl r1, mval$l_m1(r1) cmple r0, r1, r0 blbs r0, continue_loop br undo ; loop has terminated ; Step is not int; check the sign of its exp field: 15$: ldq_u r28, mval$b_exp(r3) lda r27, mval$b_exp+1(r3) extqh r28, r27, r28 bge r28, 5$ ; branch if step's exp is positive ; Either step's value or its exp field is negative; swap r0 with r1: 20$: mov r4, r0 ; r0 -> terminator mov r2, r1 ; r1 -> index mv_if_notint (r0), compare_non_int mv_if_int (r1), 10$ ; Neither index nor terminator is int; use OP_NUMCMP to do the comparison: compare_non_int: $call OP_NUMCMP, set_arg_info=false, nonstandard=true ; args are r0 and r1 ble r0, continue_loop ; The FOR loop has terminated; before returning we must subtract step from index: undo: mv_if_notint (r2), sub_non_int ; branch if index is not int mv_if_notint (r3), sub_non_int ; branch if step is not int ldl r22, mval$l_m1(r2) ; r22 = new index value ldl r23, mval$l_m1(r3) ; r23 = step value subq r22, r23, r22 ; r22 = old index value [= new index - step] ; Check the new (old) index value: $call CHECK_INDEX, set_arg_info=false, nonstandard=true, local=true br terminate_loop ; One or both of index and step are not int; subtract step from index: sub_non_int: $call ADD_MVALS, args=, set_arg_info=false, nonstandard=true ; The FOR loop has terminated; return via the address saved in the Mumps stack frame: terminate_loop: ldl r26, msf$mpc_off(r12) br epilogue ; The FOR loop has not yet terminated; return via the address saved on the stack: continue_loop: ldq r26, 32(sp) epilogue: ldq r2, (sp) ldq r3, 8(sp) ldq r4, 16(sp) ldq r13, 24(sp) lda sp, 40(sp) ret r26 $end_routine ; This is a local routine to check and update the value of the index variable. ; ; On entry, R22 contains the value to check, and r2 -> the mval for the index variable. $routine CHECK_INDEX, entry=CHECK_INDEX_CA, local=true, kind=null .base r27, $ls ldq r25, mant_hi_val cmplt r22, r25, r28 beq r28, 20$ ; branch if index >= MANT_HI negq r25, r25 cmple r22, r25, r28 bne r28, 10$ ; branch if index <= -MANT_HI ; Abs(index value) < MANT_HI; simply store it: stl r22, mval$l_m1(r2) ; Since the value has changed, set mvtype to int (i.e. clear all bits except mval$m_int): ldl r24, mval$w_mvtype(r2) mskwl r24, mval$w_mvtype, r24 or r24, mval$m_int, r24 stl r24, mval$w_mvtype(r2) ret r26 ; index <= -MANT_HI: 10$: negq r22, r22 ; make the value positive mov ^x80, r28 ; set the sign bit for exp ; index >= MANT_HI: 20$: or r28, ^x45, r28 ; exp will be ^x45 (decimal 69) ; Set mvtype (to mval$m_nm) and exp: mov mval$m_nm, r24 ; set mvtype field insbl r28, mval$b_exp, r28 ; move the exp value into position in r28 or r24, r28, r24 ; set the new field values into r24 stl r24, mval$w_mvtype(r2) ; and store them ; Divide the index value (r22) by 10: ldah r24, -13107 negq r22, r25 lda r24, -13107(r24) cmovge r22, r22, r25 sll r24, 32, r24 umulh r25, r24, r25 srl r25, 3, r25 negq r25, r28 cmovge r22, r25, r28 ; r28 = index / 10 mulq r28, 10, r24 ; r24 = (index / 10) * 10 ldq r25, mant_lo_val subq r22, r24, r22 ; r22 = index - ((index / 10) * 10) mulq r22, r25, r22 ; r22 = (index - ((index / 10) * 10)) * MANT_LO stl r22, mval$l_m0(r2) ; (index - ((index / 10) * 10)) * MANT_LO stl r28, mval$l_m1(r2) ; index / 10 ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_gettruth.m640000644000032200000250000000112512201176167016712 0ustar librarygtc .title OP_GETTRUTH mval$def $linkage_section a_literal_zero: .address literal_zero a_literal_one: .address literal_one $code_section $routine OP_GETTRUTH, entry=OP_GETTRUTH_CA, kind=null .base r27, $ls ldl r20, 0(r10) ; $TEST value ldq r24, a_literal_one ldq r28, a_literal_zero cmovne r20, r24, r28 ; mval's are longword-aligned, and are 5 longwords long [mval$size = 20]: ldl r16, (r28) ldl r17, 4(r28) ldl r18, 8(r28) ldl r19, 12(r28) ldl r20, 16(r28) stl r16, (r1) stl r17, 4(r1) stl r18, 8(r1) stl r19, 12(r1) stl r20, 16(r1) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_iretmvad.m640000644000032200000250000000065612201176167016667 0ustar librarygtc .title OP_IRETMVAD g_msf $linkage_section a_frame_pointer: .address frame_pointer $routine OP_IRETMVAD, entry=OP_IRETMVAD_CA, kind=null lda sp, -16(sp) stq r3, (sp) stq r1, 8(sp) ; save r1, restore into r0 later mov r27, r3 .base r3, $ls putframe $call OP_UNWIND, set_arg_info=false, nonstandard=true getframe ldq r0, 8(sp) ; set r0 from saved r1 ldq r3, (sp) lda sp, 16(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_linefetch.m640000644000032200000250000000110712201176167017005 0ustar librarygtc .title op_linefetch G_MSF ; entry: ; r16 argument count ; r17 . . . arguments to pass to fetch $routine name=op_linefetch, entry=op_linefetch_ca, kind=stack, saved_regs= stl r26, msf$mpc_off(r12) stl r13, msf$ctxt_off(r12) mov r27, r13 .base r13, $ls fetch_args r2, $SIZE $begin_epilogue mov fp, sp ldl r26, msf$mpc_off(r12) ; use the return address from the MUMPS stack frame ldq r2, $RSA_OFFSET+8(sp) ldq r13, $RSA_OFFSET+16(sp) ldq fp, $RSA_OFFSET+24(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue $end_routine name=op_linefetch .end fis-gtm-V6.0-003/sr_avms/op_mprofcall.m640000644000032200000250000000222212201176167017022 0ustar librarygtc .title OP_MPROFCALL ; ############################################################### ; # # ; # Copyright 2001, 2003 Sanchez Computer Associates, Inc. # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ############################################################### G_MSF $linkage_section a_frame_pointer: .address frame_pointer $code_section $routine OP_MPROFCALLB, entry=OP_MPROFCALL_CA, aliases=, kind=null lda sp, -16(sp) stq r3, 8(sp) stq r26, (sp) mov r27, r3 .base r3, $ls ldq r1, a_frame_pointer ldl r1, (r1) ; Bump the return PC past the branch instruction following the jsr that got us here: addl r26, r16, r26 ; length of branch sequence stl r26, msf$mpc_off(r1) ; and store it in the Mumps stack frame $call COPY_STACK_FRAME_SP, set_arg_info=false, nonstandard=true ldq r12, a_frame_pointer ldl r12, (r12) ldq r28, (sp) ldq r3, 8(sp) lda sp, 16(sp) ret r28 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_mprofcallsp.m640000644000032200000250000000245712201176167017377 0ustar librarygtc .title OP_MPROFCALLSP ; ############################################################### ; # # ; # Copyright 2001, 2007 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ############################################################### G_MSF $linkage_section a_frame_pointer: .address frame_pointer $code_section $routine OP_MPROFCALLSPB, entry=OP_MPROFCALLSP_CA, aliases=, kind=null lda sp, -16(sp) stq r3, 8(sp) stq r26, (sp) mov r27, r3 .base r3, $ls ldq r1, a_frame_pointer ldl r1, (r1) ; Bump the return PC past the branch instruction following the jsr that got us here: addl r26, r16, r26 ; length of branch sequence stl r26, msf$mpc_off(r1) ; and store it in the Mumps stack frame $call EXFUN_FRAME_PUSH_DUMMY_FRAME, set_arg_info=false, nonstandard=true ldl r16, 0(r10) ; Fetch $TEST value $call PUSH_TVAL, args=, set_arg_info=false, nonstandard=true ldq r12, a_frame_pointer ldl r12, (r12) ldl r9, msf$temps_ptr_off(r12) ldq r28, (sp) ldq r3, 8(sp) lda sp, 16(sp) ret r28 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_mprofexfun.m640000644000032200000250000000525712201176167017247 0ustar librarygtc .title op_mprofexfun - invoke (internal) extrinsic function mprofiling flavor ; ############################################################### ; # # ; # Copyright 2001, 2012 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ############################################################### G_MSF ; op_mprofexfun - invoke (internal) extrinsic function m-profiling flavor ; ; arguments: ; ret_value address for function to place return value ; offset to this frame's continue (return) point past branch to subroutine ; mask ; actualcnt actual argument count ; actual1 address of actual first argument ; actual2 address of actual second argument ; . . . $routine name=op_mprofexfun, entry=op_mprofexfun_ca, kind=stack, saved_regs=, - ; BYPASSOK data_section_pointer=true, - data_section=<$DATA$, QUAD, NOPIC, CON, REL, LCL, NOSHR, MIX, NOEXE, RD, WRT> $linkage_section A_frame_pointer: .address frame_pointer $code_section mov r27, r13 .base r13, $ls ldq r1, A_frame_pointer ldl r1, (r1) addl r26, r17, r28 ; add size of jump sequence to get return addr for frame. stl r28, msf$mpc_off(r1) $call exfun_frame_sp, set_arg_info=false ldl r16, 0(r10) ; $TRUTH aka $TEST value bic r16, #^Xfe, r16 ; clear all but low order bit ldq r17, $RSA_OFFSET+24(fp) ; old r16 (ret_value) ldq r18, $RSA_OFFSET+40(fp) ; old r18 (mask) ldq r19, $RSA_OFFSET+48(fp) ; old r19 (actualcnt) ldq r20, $RSA_OFFSET+56(fp) ; old r20 (actual1) ldq r21, $RSA_OFFSET+64(fp) ; old r21 (actual2) lda r25, 4(r19) ; If more than 2 actual arguments, push rest onto stack. subq r19, 2, r28 ; number of arguments originally passed on stack (actual3 . . . actualn) ble r28, zero_in_stack ; all original arguments in registers lda r0, $SIZE(fp) subq r28, 1, r28 ; offset = number - 1 s8addq r28, r0, r0 ; address of actualn loop: ldq r1, (r0) lda sp, -8(sp) lda r0, -8(r0) stq r1, (sp) subq r28, 1, r28 bge r28, loop zero_in_stack: $call push_parm, set_arg_info=false ; push_parm ($T, ret_value, mask, actualcnt [, actual1[, actual2 . . .]]) done: ldq r28, A_frame_pointer ldl r2, (r28) ; saved value of frame_pointer mov r2, r12 ldl r9, msf$temps_ptr_off(r12) $begin_epilogue mov fp, sp ldq r26, $RSA_OFFSET(sp) ldq r2, $RSA_OFFSET+8(sp) ldq r13, $RSA_OFFSET+16(sp) ldq fp, $RSA_OFFSET+72(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue $end_routine name=op_mprofexfun .end fis-gtm-V6.0-003/sr_avms/op_mprofextcall.m640000644000032200000250000000605512201176167017553 0ustar librarygtc .title op_mprofextcall - call external (MUMPS) routine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2005, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; G_MSF PROCDESC ; op_mprofextcall calls and external GT.M MUMPS routine. If the routine has not yet ; been linked into the current image, op_mprofextcall will first link it by invoking ; the auto-ZLINK function. ; ; Args: ; procdsc - address of procedure descriptor of routine to call ; labaddr - address of offset into routine to which to transfer control $routine name=op_mprofextcall, entry=op_mprofextcall_ca, kind=stack, saved_regs=, - data_section_pointer=true $linkage_section A_frame_pointer: .address frame_pointer L_ERR_GTMCHECK: .long ERR_GTMCHECK L_ERR_LABELUNKNOWN: .long ERR_LABELUNKNOWN $data_section PDSC_FLAGS: .long GTM_PD_FLAGS $code_section .base r27, $ls ldq r22, $dp .base r22, $ds putframe r12 mov r27, r13 .base r13, $ls beq r16, L20 ; if procdsc == 0, this routine has not yet been linked into current image beq r17, L40 ; if labaddr == 0 (and procdsc != 0), there is some interal error ; Check whether first argument is procedure descriptor or routine header. ldl r28, PDSC_FLAGS ldl r0, (r16) xor r28, r0, r28 bne r28, L10 ; if not procedure descriptor, it must be a routine header ldq r16, 8(r16) ; rhdaddr = procdsc->entry_point ; entry point address is address of routine header L10: ldl r17, (r17) ; *lab_ln_ptr beq r17, L40 ldl r28, mrt$curr_ptr(r16) addl r17, r28, r17 addl r17, r16, r17 ; rhdaddr + *lab_ln_ptr ldl r17, (r17) ; *labaddr ldl r28, mrt$curr_ptr(r16) ; rhdaddr->current_rhead_ptr addl r16, r28, r18 ; rhdaddr + rhdaddr->current_rhead_ptr addl r17, r18, r18 ; rhdaddr + rhdaddr->current_rhead_ptr + *labaddr $call new_stack_frame_sp, args=, set_arg_info=false $begin_epilogue getframe mov fp, sp ldq fp, $RSA_OFFSET+8(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue L20: bne r17, L40 ; if labaddr != 0 (and procdsc == 0), there is some internal error lda sp, -8(sp) ; auto_zlink will put value here stq r31, (sp) $call auto_zlink, args=, set_arg_info=false beq r0, L30 mov r0, r16 ; rhdaddr of newly-ZLINK'ed routine ldq r17, (sp) ; new labaddr lda sp, 8(sp) beq r17, L30 br L10 ; auto_zlink returns pointer to a routine header, not a procedure descriptor L30: $call lib$signal, args= $begin_epilogue getframe mov fp, sp ldq fp, $RSA_OFFSET+8(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue L40: $call lib$signal, args= $begin_epilogue getframe mov fp, sp ldq fp, $RSA_OFFSET+8(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue $end_routine name=op_mprofextcall .end fis-gtm-V6.0-003/sr_avms/op_mprofextexfun.m640000644000032200000250000001103312201176167017755 0ustar librarygtc .title op_mprofextexfun - invoke external extrinsic function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2005, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; G_MSF PROCDESC ; op_mprofextexfun - invoke external extrinsic function ; ; arguments: ; routine address of procedure descriptor of procedure containing extrinsic function ; label address of offset into routine to which to transfer control ; ret_value address for function to place return value ; mask ; actualcnt actual argument count ; actual1 address of actual first argument ; actual2 address of actual second argument ; . . . $routine name=op_mprofextexfun, entry=op_mprofextexfun_ca, kind=stack, saved_regs=, - ; BYPASSOK data_section_pointer=true, - data_section=<$DATA$, QUAD, NOPIC, CON, REL, LCL, NOSHR, MIX, NOEXE, RD, WRT> $linkage_section A_frame_pointer: .address frame_pointer L_ERR_FMLLSTMISSING: .long ERR_FMLLSTMISSING L_ERR_GTMCHECK: .long ERR_GTMCHECK L_ERR_LABELUNKNOWN: .long ERR_LABELUNKNOWN $data_section PDSC_FLAGS: .long GTM_PD_FLAGS $code_section .base r27, $ls ldq r2, $dp .base r2, $ds putframe mov r27, r13 .base r13, $ls L9: beq r16, L20 ; if procdsc == 0, this routine has not yet been linked into current image beq r17, L40 ; if labaddr == 0 (and procdsc != 0), it's an unknown label ; Check whether first argument is procedure descriptor or routine header. ldl r28, PDSC_FLAGS ldl r0, (r16) xor r28, r0, r28 bne r28, L10 ; if not procedure descriptor, it must be a routine header ldq r16, 8(r16) ; rhdaddr = procdsc->entry_point ; entry point address is address of routine header L10: mov r17, r22 ; temporarily save labaddr, so it is not overriden ldl r17, (r17) ; *lab_ln_ptr beq r17, L40 ldl r28, mrt$curr_ptr(r16) addl r17, r28, r17 addl r17, r16, r17 ; rhdaddr + *lab_ln_ptr ldl r17, (r17) ; *labaddr ldl r28, mrt$curr_ptr(r16) ; rhdaddr->current_rhead_ptr addl r16, r28, r18 addl r17, r18, r18 mov r22, r17 ; restore the original labaddr addq r17, 4, r17 ; labaddr += 4, to point to has_parms ldl r17, (r17) ; *has_parms beq r17, L50 ; if has_parms == 0, then issue an error L12: $call new_stack_frame_sp, args=, set_arg_info=false ldl r16, 0(r10) ; push $TRUTH aka $TEST bic r16, #^Xfe, r16 ; clear all but low order bit L15: ldq r17, $RSA_OFFSET+24(fp) ; old r18 (ret_value) ldq r18, $RSA_OFFSET+32(fp) ; old r19 (mask) ldq r19, $RSA_OFFSET+40(fp) ; old r20 (actualcnt) ldq r20, $RSA_OFFSET+48(fp) ; old r21 (actual1) ldq r21, $SIZE(fp) ; actual2, if any lda r25, 4(r19) ; If more than 1 argument, push rest onto stack. subq r19, 2, r28 ; number of arguments to put onto stack (actual3 . . . actualn) ble r28, zero_in_stack ; all original arguments in registers lda r0, $SIZE(fp) s8addq r28, r0, r0 ; address of actualn loop: ldq r1, (r0) lda sp, -8(sp) lda r0, -8(r0) stq r1, (sp) subq r28, 1, r28 bgt r28, loop zero_in_stack: $call push_parm, set_arg_info=false ; push_parm ($T, ret_value, mask, argc[, actual1[, actual2 . . .]]) L16: getframe $begin_epilogue mov fp, sp ldq r2, $RSA_OFFSET+8(sp) ldq fp, $RSA_OFFSET+56(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue L20: bne r17, L30 ; procdsc == 0, but label != 0 => internal error lda sp, -8(sp) ; auto_zlink will put value here stq r31, (sp) $call auto_zlink, args=, set_arg_info=false beq r0, L30 mov r0, r16 ; rhdaddr of newly-ZLINK'ed routine ldq r17, (sp) ; new labaddr lda sp, 8(sp) beq r17, L40 ; found routine, but labaddr still 0 => unknown label br L10 L30: $call lib$signal, args= $begin_epilogue getframe mov fp, sp ldq r2, $RSA_OFFSET+8(sp) ldq fp, $RSA_OFFSET+56(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue L40: $call lib$signal, args= $begin_epilogue getframe mov fp, sp ldq r2, $RSA_OFFSET+8(sp) ldq fp, $RSA_OFFSET+56(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue L50: $call lib$signal, args= $begin_epilogue getframe mov fp, sp ldq r2, $RSA_OFFSET+8(sp) ldq fp, $RSA_OFFSET+56(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue $end_routine name=op_mprofextexfun .end fis-gtm-V6.0-003/sr_avms/op_mprofforchk1.m640000644000032200000250000000205412201176167017447 0ustar librarygtc;################################################################# ;# # ;# Copyright 2011 Fidelity Information Services, Inc # ;# # ;# This source code contains the intellectual property # ;# of its copyright holder(s), and is made available # ;# under a license. If you do not know the terms of # ;# the license, please stop and do not read further. # ;# # ;################################################################# .title op_mprofforloop "FOR loop iteration logic" $routine OP_MPROFFORCHK1, entry=OP_MPROFFORCHK1_CA, kind=null subq sp, 16, sp stq r26, 0(sp) stq r13, 8(sp) mov r27, r13 .base r13, $ls mov r26, r16 ; send the return address to forchkhandler $call forchkhandler, args=, set_arg_info=false, nonstandard=true ldq r26, (sp) ldq r13, 8(sp) addq sp, 16, sp ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_mprofforlcldo.m640000644000032200000250000000230012201176167017710 0ustar librarygtc .title OP_MPROFFORLCLDO ; ############################################################### ; # # ; # Copyright 2001, 2012 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ############################################################### G_MSF $linkage_section a_frame_pointer: .address frame_pointer $code_section $routine OP_MPROFFORLCLDOB, entry=OP_MPROFFORLCLDO_CA, aliases=, kind=null lda sp, -16(sp) stq r3, 8(sp) stq r26, (sp) mov r27, r3 .base r3, $ls ldq r1, a_frame_pointer ldl r1, (r1) ; Bump the return PC past the branch instruction following the jsr that got us here: addl r26, r16, r26 ; length of branch sequence stl r26, msf$mpc_off(r1) ; and store it in the Mumps stack frame $call EXFUN_FRAME_SP, set_arg_info=false, nonstandard=true ldq r12, a_frame_pointer ldl r12, (r12) ldl r9, msf$temps_ptr_off(r12) ldq r28, (sp) ldq r3, 8(sp) lda sp, 16(sp) ret r28 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_mproflinefetch.m640000644000032200000250000000134112201176167020051 0ustar librarygtc .title op_mproflinefetch G_MSF ; entry: ; r16 argument count ; r17 . . . arguments to pass to fetch $routine name=op_mproflinefetch, entry=op_mproflinefetch_ca, kind=stack, saved_regs= stl r26, msf$mpc_off(r12) stl r13, msf$ctxt_off(r12) mov r27, r13 .base r13, $ls fetch_args r2, $SIZE $call PCURRPOS, args=<>, set_arg_info=false, nonstandard=true $call STACK_LEAK_CHECK, args=<>, set_arg_info=false, nonstandard=true $begin_epilogue mov fp, sp ldl r26, msf$mpc_off(r12) ; use the return address from the MUMPS stack frame ldq r2, $RSA_OFFSET+8(sp) ldq r13, $RSA_OFFSET+16(sp) ldq fp, $RSA_OFFSET+24(sp) lda sp, $SIZE(sp) ret r26 $end_epilogue $end_routine name=op_mproflinefetch .end fis-gtm-V6.0-003/sr_avms/op_mproflinestart.m640000644000032200000250000000116212201176167020116 0ustar librarygtc .title op_mproflinestart G_MSF ; op_mproflinestart - establish start of line in GT.M MUMPS stack frame $routine name=op_mproflinestart, entry=op_mproflinestart_ca, kind=stack, saved_regs= stl r26, msf$mpc_off(r12) stl r13, msf$ctxt_off(r12) mov r27, r13 .base r13, $ls $call PCURRPOS, args=<>, set_arg_info=false, nonstandard=true $begin_epilogue mov fp, sp ldl r26, msf$mpc_off(r12) ; use the return address from the MUMPS stack frame ldq r2, $RSA_OFFSET+8(sp) ldq r13, $RSA_OFFSET+16(sp) ldq fp, $RSA_OFFSET+24(sp) lda sp, $SIZE(sp) ret r26 $end_routine name=op_mproflinestart fis-gtm-V6.0-003/sr_avms/op_neg.m640000644000032200000250000000445612201176167015627 0ustar librarygtc;################################################################# ;# # ;# Copyright 2006, 2008 Fidelity Information Services, Inc # ;# # ;# This source code contains the intellectual property # ;# of its copyright holder(s), and is made available # ;# under a license. If you do not know the terms of # ;# the license, please stop and do not read further. # ;# # ;################################################################# .title OP_NEG mval$def $routine OP_NEG, entry=OP_NEG_CA, kind=null lda sp, -32(sp) stq r26, (sp) stq r2, 8(sp) stq r3, 16(sp) stq r13, 24(sp) mov r27, r13 .base r13, $ls mov r0, r2 ; r2 -> output mval mov r1, r3 ; r3 -> input mval mv_force_defined r3 mv_force_num (r3) ; Move the mvtype from the input mval to the output mval, ; except for the str bit: ldq_u r23, mval$w_mvtype(r3) ldq_u r22, mval$w_mvtype(r2) extwl r23, r3, r23 mskwl r22, r2, r22 and r23, #mval$m_int, r23 ; clear everything except mval$v_nm and mval$v_int inswl r23, r2, r23 or r22, r23, r22 stq_u r22, mval$w_mvtype(r2) ; Is the input zero? ldl r24, mval$l_m1(r3) beq r24, 10$ ; No; is it int? mv_if_notint (r3), 15$ ; Yes; output m1 = - input m1 ldl r24, mval$l_m1(r3) negl r24, r24 stl r24, mval$l_m1(r2) ; Return: 5$: ldq r28, (sp) ldq r2, 8(sp) ldq r3, 16(sp) ldq r13, 24(sp) lda sp, 32(sp) ret r28 ; Input mval is zero; clear output exp, sign, m0, and m1: 10$: ldq_u r22, mval$b_exp(r2) lda r23, mval$b_exp(r2) mskbl r22, r23, r22 stq_u r22, mval$b_exp(r2) stl r31, mval$l_m0(r2) stl r31, mval$l_m1(r2) br 5$ ; Input is not int; move input m0 and m1 to output 15$: ldl r22, mval$l_m0(r3) ldl r23, mval$l_m1(r3) stl r22, mval$l_m0(r2) stl r23, mval$l_m1(r2) ; Move exp from input to output, but flip the sign: ldq_u r22, mval$b_exp(r2) ldq_u r23, mval$b_exp(r3) lda r24, mval$b_exp(r2) lda r25, mval$b_exp(r3) mskbl r22, r24, r22 extbl r23, r25, r23 ; low order byte of r23 = input exp and sign xor r23, ^x80, r23 ; flip the sign bit insbl r23, r24, r23 or r22, r23, r22 stq_u r22, mval$b_exp(r2) br 5$ $end_routine .end fis-gtm-V6.0-003/sr_avms/op_numcmp.m640000644000032200000250000000064012201176167016344 0ustar librarygtc .title OP_NUMCMP "Compare mval's, set condition code" ; On entry, r0 and r1 point to mval's. ; On exit, r24 contains the appropriate condition. $routine OP_NUMCMP, entry=OP_NUMCMP_CA, kind=null lda sp, -8(sp) stq r26, (sp) .base r27, $ls mov r0, r16 mov r1, r17 $call NUMCMP, args=, set_arg_info=false, nonstandard=true mov r0, r24 ldq r26, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_restartpc.m640000644000032200000250000000064212201176167017056 0ustar librarygtc .title OP_RESTARTPC "Save PC" G_MSF call_inst_size = 12 $linkage_section A_restart_ctxt: .address restart_ctxt A_restart_pc: .address restart_pc $code_section $routine OP_RESTARTPC, entry=OP_RESTARTPC_CA, kind=null .base r27, $ls ldq r25, A_restart_pc subq r26, call_inst_size, r28 stl r28, (r25) ldq r25, A_restart_ctxt ldl r28, msf$ctxt_off(r12) stl r28, (r25) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_retarg.m640000644000032200000250000000147712201176170016334 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2009, 2010 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .title OP_RETARG G_MSF $linkage_section a_frame_pointer: .address frame_pointer $code_section $routine OP_RETARG, entry=OP_RETARG_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls mov r0, r16 mov r1, r17 $call UNW_RETARG, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) addq sp, 8, sp jmp r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_startintrrpt.m640000644000032200000250000000155612201176170017626 0ustar librarygtc .title OP_STARTINTRRPT G_MSF $linkage_section a_neterr_pending: .address neterr_pending a_iott_write_error: .address iott_write_error a_frame_pointer: .address frame_pointer $code_section $routine OP_STARTINTRRPT, entry=OP_STARTINTRRPT_CA, kind=null lda sp, -8(sp) stq r2, (sp) mov r27, r2 .base r2, $ls putframe ldq r0, a_neterr_pending ldq_u r24, (r0) extbl r24, r0, r24 beq r24, 10$ $call outofband_clear, set_arg_info=false, nonstandard=true $call gvcmz_neterr, args=<0/a>, set_arg_info=false, nonstandard=true 10$: ldq r0, a_iott_write_error ldl r24, (r0) beq r24, 15$ $call outofband_clear, set_arg_info=false, nonstandard=true $call iott_wrterr, set_arg_info=false, nonstandard=true 15$: $call async_action, args=<1/a>, set_arg_info=false, nonstandard=true 20$: getframe ldq r2, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/op_sto.m640000644000032200000250000000271712201176170015653 0ustar librarygtc;################################################################# ;# # ;# Copyright 2006, 2012 Fidelity Information Services, Inc # ;# # ;# This source code contains the intellectual property # ;# of its copyright holder(s), and is made available # ;# under a license. If you do not know the terms of # ;# the license, please stop and do not read further. # ;# # ;################################################################# .title OP_STO mval$def $linkage_section a_literal_null: .address literal_null a_undef_inhibit: .address undef_inhibit l_underr: .linkage_pair underr $code_section $routine OP_STO, entry=OP_STO_CA, kind=null .base r27, $ls mv_if_notdefined (r1), 10$ ; Copy the mval pointed to by r1 to the mval pointed to by r0 ; (mval's are longword-aligned, and are 5 longwords long [mval$size = 20]): 5$: mov mval$m_aliascont, r24 ldl r16, (r1) ldl r17, 4(r1) bic r16, r24, r16 ; don't allow propagation of alias container flag ldl r18, 8(r1) ldl r19, 12(r1) ldl r20, 16(r1) stl r16, (r0) stl r17, 4(r0) stl r18, 8(r0) stl r19, 12(r0) stl r20, 16(r0) ret r26 10$: ldq r28, a_undef_inhibit ldq_u r24, (r28) extbl r24, r28, r24 beq r24, 20$ ldq r1, a_literal_null br 5$ ; "Call" UNDERR; it will return to our caller, since we haven't changed r26: 20$: mov r1, r16 mov ^x1, r25 ; UNDEF here is never subscripted - use arg cnt 1 ldq r28, l_underr ldq r27, l_underr+8 jmp r28 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_break.m640000644000032200000250000000051712201176170016306 0ustar librarygtc .title OPP_BREAK g_msf $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_BREAK, entry=OPP_BREAK_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_BREAK, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_commarg.m640000644000032200000250000000055012201176170016644 0ustar librarygtc .title OPP_COMMARG G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_COMMARG, entry=OPP_COMMARG_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_COMMARG, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_dmode.m640000644000032200000250000000047312201176170016313 0ustar librarygtc .title OPP_DMODE g_msf $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_DMODE, entry=OPP_DMODE_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_DMODE, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_hardret.m640000644000032200000250000000052612201176170016653 0ustar librarygtc .title OPP_HARDRET g_msf $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_HARDRET, entry=OPP_HARDRET_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_HARDRET, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_inddevparms.m640000644000032200000250000000057512201176170017542 0ustar librarygtc .title OPP_INDDEVPARMS G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_INDDEVPARMS, entry=OPP_INDDEVPARMS_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_INDDEVPARMS, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_indfnname.m640000644000032200000250000000056512201176170017164 0ustar librarygtc .title OPP_INDFNNAME G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_INDFNNAME, entry=OPP_INDFNNAME_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_INDFNNAME, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_indfun.m640000644000032200000250000000055112201176170016503 0ustar librarygtc .title OPP_INDFUN G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_INDFUN, entry=OPP_INDFUN_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_INDFUN, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_indglvn.m640000644000032200000250000000055012201176170016660 0ustar librarygtc .title OPP_INDGLVN G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_INDGLVN, entry=OPP_INDGLVN_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_INDGLVN, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_indincr.m640000644000032200000250000000200112201176170016636 0ustar librarygtc .title OPP_INDINCR ; ############################################################### ; # # ; # Copyright 2004 Sanchez Computer Associates, Inc. # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ############################################################### G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_INDINCR, entry=OPP_INDINCR_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_INDINCR, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_indlvadr.m640000644000032200000250000000054712201176170017030 0ustar librarygtc .title OPP_INDLVADR G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_INDLVADR, entry=OPP_INDLVADR_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_INDLVADR, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_indlvarg.m640000644000032200000250000000055412201176170017031 0ustar librarygtc .title OPP_INDLVARG G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_INDLVARG, entry=OPP_INDLVARG_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_INDLVARG, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_indlvnamadr.m640000644000032200000250000000056312201176170017522 0ustar librarygtc .title OPP_INDLVNAMADR G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_INDLVNAMADR, entry=OPP_INDLVNAMADR_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_INDLVNAMADR, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_indmerge.m640000644000032200000250000000055412201176170017015 0ustar librarygtc .title OPP_INDMERGE G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_INDMERGE, entry=OPP_INDMERGE_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_INDMERGE, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_indpat.m640000644000032200000250000000054412201176170016501 0ustar librarygtc .title OPP_INDPAT G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_INDPAT, entry=OPP_INDPAT_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_INDPAT, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_indrzshow.m640000644000032200000250000000056012201176170017247 0ustar librarygtc .title OPP_INDRZSHOW G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_INDRZSHOW, entry=OPP_INDRZSHOW_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_INDRZSHOW, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_indsavglvn.m640000644000032200000250000000147112201176170017375 0ustar librarygtc .title OPP_INDSAVGLVN ; ############################################################### ; # # ; # Copyright 2012 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ############################################################### G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_INDSAVGLVN, entry=OPP_INDSAVGLVN_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_INDSAVGLVN, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_indsavlvn.m640000644000032200000250000000146512201176170017231 0ustar librarygtc .title OPP_INDSAVLVN ; ############################################################### ; # # ; # Copyright 2012 Fidelity Information Services, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ############################################################### G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_INDSAVLVN, entry=OPP_INDSAVLVN_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_INDSAVLVN, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_indset.m640000644000032200000250000000054412201176170016510 0ustar librarygtc .title OPP_INDSET G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_INDSET, entry=OPP_INDSET_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_INDSET, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_indtext.m640000644000032200000250000000056212201176170016701 0ustar librarygtc .title OPP_INDTEXT G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_INDTEXT, entry=OPP_INDTEXT_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_INDTEXT, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_iretmval.m640000644000032200000250000000055312201176170017045 0ustar librarygtc .title OPP_IRETMVAL g_msf $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_IRETMVAL, entry=OPP_IRETMVAL_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_IRETMVAL, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_newintrinsic.m640000644000032200000250000000056712201176170017743 0ustar librarygtc .title OPP_NEWINTRINSIC G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_NEWINTRINSIC, entry=OPP_NEWINTRINSIC_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_NEWINTRINSIC, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_newvar.m640000644000032200000250000000053712201176170016526 0ustar librarygtc .title OPP_NEWVAR G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_NEWVAR, entry=OPP_NEWVAR_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_NEWVAR, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_ret.m640000644000032200000250000000454212201176170016016 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001, 2008 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .title OPP_RET G_MSF $linkage_section a_frame_pointer: .address frame_pointer a_skip_error_ret: .address skip_error_ret a_error_frame: .address error_frame a_is_tracing_on: .address is_tracing_on a_msp: .address msp a_mv_chain: .address mv_chain a_tp_pointer: .address tp_pointer L_ERR_STACKUNDERFLO: .long ERR_STACKUNDERFLO $code_section $routine OPP_RET, entry=OPP_RET_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls ; Since most QUITs will be simple, check to see if there's anything to unwind: ldq r28, a_mv_chain ldl r28, (r28) cmpule r12, r28, r24 blbc r24, lbl20 ; branch if frame_pointer > mv_chain ldq r28, a_tp_pointer ldl r26, (r28) bne r26, lbl20 ; if there's a transaction on, go do unwind ldq r28, a_skip_error_ret ldl r26, (r28) bne r26, lbl20 ; if skip_error_ret is TRUE, go do unwind (at least to reset it to FALSE) ldq r28, a_error_frame ldl r26, (r28) bne r26, lbl20 ; if error_frame is non-NULL, go do unwind ; Check the frame pointer type if it requires special handling by op_unwind ldl r28, msf$typ_off(r12) ; contains msf$flags srl r28, 16, r28 ; shift flags byte to low order and r28, sff_indce, r28 ; isolate indirect bit bne r28, lbl20 ; go do the long version ldq r28, a_is_tracing_on ldl r26, (r28) bne r26, lbl20 ; if m-profiling is on, go do unwind ; The frame_pointer is <= the mv_chain, so there's nothing to do but set up ; the new frame pointer and stack pointer: addl r12, msf$frame_size, r26 ldq r28, a_msp stl r26, (r28) ldl r12, msf$old_frame_off(r12) beq r12, lbl90 ldq r28, a_frame_pointer stl r12, (r28) getframe mov r13, r27 ldq r3, (sp) lda sp, 8(sp) jmp r26 lbl20: $call OP_UNWIND, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 ; Note that LIB$SIGNAL does not return: lbl90: $call LIB$SIGNAL, args=, nonstandard=true $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_rterror.m640000644000032200000250000000055012201176170016716 0ustar librarygtc .title OPP_RTERROR g_msf $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_RTERROR, entry=OPP_RTERROR_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_RTERROR, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_svput.m640000644000032200000250000000053712201176170016405 0ustar librarygtc .title OPP_SVPUT G_MSF $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_SVPUT, entry=OPP_SVPUT_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_SVPUT, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_tcommit.m640000644000032200000250000000063512201176170016677 0ustar librarygtc .title OPP_TCOMMIT "Commit a transaction - may result in restart (transfer of control)" g_msf $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_TCOMMIT, entry=OPP_TCOMMIT_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_TCOMMIT, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_trestart.m640000644000032200000250000000061112201176170017065 0ustar librarygtc .title OPP_TRESTART "Restart a specified transaction" g_msf $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_TRESTART, entry=OPP_TRESTART_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_TRESTART, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_trollback.m640000644000032200000250000000061412201176170017175 0ustar librarygtc .title OPP_TROLLBACK "Rollback a specified transaction" g_msf $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_TROLLBACK, entry=OPP_TROLLBACK_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_TROLLBACK, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_tstart.m640000644000032200000250000000510412201176170016540 0ustar librarygtc .title OPP_TSTART "Initiate a transaction processing frame" G_MSF $linkage_section a_frame_pointer: .address frame_pointer $code_section $routine OPP_TSTART, entry=OPP_TSTART_CA, kind=null stack_offset = 16 lda sp, -stack_offset(sp) stq r2, (sp) stq r3, 8(sp) ; Note: we use r3 as a base for the linkage section instead of the usual r13, ; since r13 is saved by putframe and restored by getframe: mov r27, r3 .base r3, $ls putframe ; On entry to this routine, the value in arg3 (i.e. r18) has the following meaning: ; = -2 : preserve all variables ; = -1 : not restartable ; >= 0 : = the number of variables to preserve ; ; IFF (arg3 >= 0), the total number of arguments to this routine is (arg3 + 3); ; otherwise, there are just 3 arguments. (Note that r25 DOES NOT contain any ; argument information; calls to this routine emulate the VAX JSB instruction, ; and do not set up such information.) ; ; On the other hand, OP_TSTART, called below, expects $Test as its first argument, ; followed by all of the arguments passed to this routine. ; ; Therefore, we have to create a new argument list with all of our arguments moved ; UP one slot in the list in order to make room for $Test. The fact that the first ; six arguments are passed in registers, while any arguments in excess of six are ; passed on the stack, complicates this task. So... ; ; First, move any arguments passed on the stack from their current positions ; just above our register save area to new positions just below it: mov sp, r2 ; save the current stack pointer subq r18, 4, r28 ; r28 = the number of arguments on the stack, less 1 blt r28, 10$ ; skip if there weren't any on the stack sll r28, 3, r0 addq r0, stack_offset, r0 ; account for the saved registers addq r0, sp, r0 ; r0 -> the last argument loop: ldq r1, (r0) lda sp, -8(sp) lda r0, -8(r0) subq r28, 1, r28 stq r1, (sp) bgt r28, loop ; Next, put the original arg6 onto the stack: 10$: lda sp, -8(sp) stq r21, (sp) ; Now, shift the first five arguments up into the next higher registers: mov r20, r21 mov r19, r20 mov r18, r19 mov r17, r18 mov r16, r17 ; Finally, put "tstart-is-implicit" flag into the first argument register, and call OP_TSTART: lda r16, 0 ; Note that what was in r18 is now in r19: clr r25 cmovgt r19, r19, r25 ; iff r19 > 0, number of arguments is r19, ... addq r25, 4, r25 ; ... plus the original 3 arguments, plus $Test $call OP_TSTART, set_arg_info=false, nonstandard=true getframe mov r2, sp ; restore the stack ldq r2, (sp) ldq r3, 8(sp) lda sp, stack_offset(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_xnew.m640000644000032200000250000000276512201176170016212 0ustar librarygtc .title OPP_XNEW G_MSF $linkage_section A_frame_pointer: .address frame_pointer $routine OPP_XNEW, entry=OPP_XNEW_CA, kind=null stack_offset = 16 lda sp, -stack_offset(sp) stq r2, (sp) stq r3, 8(sp) mov sp, r2 ; save the current stack pointer ; Note: we use r3 as a base for the linkage section instead of the usual r13, ; since r13 is saved by putframe and restored by getframe: mov r27, r3 .base r3, $ls putframe ; The variable length argument list that was passed to us must be passed on to OP_XNEW. ; However, since our first argument is actually the argument count, it has to be moved ; into the Argument Information register (r25), and the remaining arguments must all be ; moved down one slot in the list: mov r16, r25 ; argument count mov r17, r16 ; arg1 mov r18, r17 ; arg2 mov r19, r18 ; arg3 mov r20, r19 ; arg4 mov r21, r20 ; arg5 ldq r21, stack_offset(sp) ; arg6 was on the stack ; Any additional arguments that were on the stack must be re-stacked below our register save area: subq r25, 6, r28 ; r28 = the number of arguments left on the stack ble r28, 5$ ; skip if none sll r28, 3, r0 addq r0, stack_offset, r0 ; account for the saved registers addq r0, sp, r0 ; r0 -> argN loop: ldq r1, (r0) lda sp, -8(sp) lda r0, -8(r0) subq r28, 1, r28 stq r1, (sp) bgt r28, loop 5$: $call OP_XNEW, set_arg_info=false, nonstandard=true mov r2, sp ; restore the stack getframe ldq r2, (sp) ldq r3, 8(sp) lda sp, stack_offset(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_zcont.m640000644000032200000250000000051612201176170016356 0ustar librarygtc .title OPP_ZCONT g_msf $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_ZCONT, entry=OPP_ZCONT_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_ZCONT, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_zg1.m640000644000032200000250000000147312201176170015725 0ustar librarygtc .title OPP_ZG1 "Wrapper for ZGOTO level no entryref" ; ############################################################### ; # # ; # Copyright 2011 Fidelity Information Service, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ############################################################### g_msf $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_ZG1, entry=OPP_ZG1_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_ZG1, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/opp_zgoto.m640000644000032200000250000000150512201176170016362 0ustar librarygtc .title OPP_ZGOTO "Wrapper for ZGOTO level with entryref" ; ############################################################### ; # # ; # Copyright 2011 Fidelity Information Service, Inc # ; # # ; # This source code contains the intellectual property # ; # of its copyright holder(s), and is made available # ; # under a license. If you do not know the terms of # ; # the license, please stop and do not read further. # ; # # ; ############################################################### g_msf $linkage_section a_frame_pointer: .address frame_pointer $routine OPP_ZGOTO, entry=OPP_ZGOTO_CA, kind=null lda sp, -8(sp) stq r3, (sp) mov r27, r3 .base r3, $ls putframe $call OP_ZGOTO, args=, set_arg_info=false, nonstandard=true getframe ldq r3, (sp) lda sp, 8(sp) ret r26 $end_routine .end fis-gtm-V6.0-003/sr_avms/pdscdef.h0000644000032200000250000000576312201176170015605 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* Alpha OpenVMS procedure descriptor values. */ /* FLAGS field. */ #define PDSC$K_KIND_BOUND 0 #define PDSC$K_KIND_NULL 8 #define PDSC$K_KIND_FP_STACK 9 #define PDSC$K_KIND_FP_REGISTER 10 #define PDSC$M_HANDLER_VALID 0x10 #define PDSC$M_HANDLER_REINVOKABLE 0x20 #define PDSC$M_HANDLER_DATA_VALID 0x40 #define PDSC$M_BASE_REG_IS_FP 0x80 #define PDSC$M_REI_RETURN 0x100 #define PDSC$M_STACK_RETURN_VALUE 0x200 #define PDSC$M_BASE_FRAME 0x400 #define PDSC$M_NATIVE 0x1000 #define PDSC$M_NO_JACKET 0x2000 #define PDSC$M_TIE_FRAME 0x4000 #define PDSC$M_FUNC_RETURN 0xF #define PDSC$K_NULL_SIZE 16 #define PDSC$K_BOUND_SIZE 24 #define PDSC$K_MIN_BOUND_SIZE 24 #define PDSC$K_MIN_LENGTH_SF 32 #define PDSC$K_MIN_STACK_SIZE 32 #define PDSC$K_MAX_STACK_SIZE 48 #define PDSC$K_MIN_LENGTH_RF 24 #define PDSC$K_MIN_REGISTER_SIZE 24 #define PDSC$K_MAX_REGISTER_SIZE 40 #define PDSC$K_BOUND_ENVIRONMENT_SIZE 32 #define PDSC$W_FLAGS 0 #define PDSC$S_KIND 4 /* FLAGS field. */ #define PDSC$V_KIND 0 #define PDSC$V_HANDLER_VALID 4 #define PDSC$V_HANDLER_REINVOKABLE 5 #define PDSC$V_HANDLER_DATA_VALID 6 #define PDSC$V_BASE_REG_IS_FP 7 #define PDSC$V_REI_RETURN 8 #define PDSC$V_STACK_RETURN_VALUE 9 #define PDSC$V_BASE_FRAME 10 #define PDSC$V_NATIVE 12 #define PDSC$V_NO_JACKET 13 #define PDSC$V_TIE_FRAME 14 #define PDSC$W_RSA_OFFSET 2 #define PDSC$B_SAVE_FP 2 #define PDSC$B_SAVE_RA 3 #define PDSC$B_ENTRY_RA 4 #define PDSC$S_FUNC_RETURN 4 #define PDSC$V_FUNC_RETURN 0 #define PDSC$W_SIGNATURE_OFFSET 6 #define PDSC$S_ENTRY 8 #define PDSC$Q_ENTRY 8 #define PDSC$L_ENTRY 8 #define PDSC$L_SIZE 16 #define PDSC$S_PROC_VALUE 8 #define PDSC$Q_PROC_VALUE 16 #define PDSC$L_PROC_VALUE 16 #define PDSC$S_KIND_SPECIFIC 24 #define PDSC$R_KIND_SPECIFIC 24 #define PDSC$L_IREG_MASK 24 #define PDSC$L_FREG_MASK 28 #define PDSC$S_STACK_HANDLER 8 #define PDSC$Q_STACK_HANDLER 32 #define PDSC$S_STACK_HANDLER_DATA 8 #define PDSC$Q_STACK_HANDLER_DATA 40 #define PDSC$S_REG_HANDLER 8 #define PDSC$Q_REG_HANDLER 24 #define PDSC$S_REG_HANDLER_DATA 8 #define PDSC$Q_REG_HANDLER_DATA 32 #define PDSC$L_ENVIRONMENT 24 #define PDSC$S_ENVIRONMENT 8 #define PDSC$Q_ENVIRONMENT 24 #define PDSC$K_LKP_LENGTH 16 #define PDSC$S_LKP_ENTRY 8 #define PDSC$Q_LKP_ENTRY 0 #define PDSC$PS_LKP_ENTRY 0 #define PDSC$S_LKP_PROC_VALUE 8 #define PDSC$Q_LKP_PROC_VALUE 8 #define PDSC$PS_LKP_PROC_VALUE 8 #define LKP$K_SIZE 16 #define LKP$S_ENTRY 8 #define LKP$Q_ENTRY 0 #define LKP$PS_ENTRY 0 #define LKP$S_PROC_VALUE 8 #define LKP$Q_PROC_VALUE 8 #define LKP$PS_PROC_VALUE 8 fis-gtm-V6.0-003/sr_avms/prober.mar0000644000032200000250000000032512201176170016003 0ustar librarygtc .title prober ; returns 1 if address is accessible VAX = 1 code_psect .entry prober,^m<> ; movq 4(ap),r0 movl 4(ap),r0 movl 8(ap),r1 prober #0,r0,(r1) beql 10$ movl #1,r0 ret 10$: clrl r0 ret .end fis-gtm-V6.0-003/sr_avms/probew.mar0000644000032200000250000000033012201176170016004 0ustar librarygtc .title probew ; returns 1 if address is accessible VAX = 1 code_psect .entry probew,^m<> ; movq 4(ap),r0 movl 4(ap),r0 movl 8(ap),r1 probew #0,r0,(r1) beql 10$ movl #1,r0 ret 10$: clrl r0 ret .end fis-gtm-V6.0-003/sr_avms/proc_desc.h0000644000032200000250000000161112201176170016122 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* proc_desc - Alpha OpenVMS procedure descriptor information. */ typedef struct { short flags; short rsa_offset; short reserved_1; short signature_offset; int4 *code_address; int4 must_be_zero_1; /* actually, rest of code_address, but DEC C only implements 32-bit pointers */ int4 size; } proc_desc; #define PDSC_FLAGS ((PDSC$K_KIND_FP_STACK << PDSC$V_KIND) \ | PDSC$M_BASE_REG_IS_FP | PDSC$M_NATIVE | PDSC$M_NO_JACKET | PDSC$M_HANDLER_VALID) fis-gtm-V6.0-003/sr_avms/procdesc.max0000644000032200000250000000030512201176170016320 0ustar librarygtc .macro PROCDESC GTM_PD_FLAGS = ^X00183099 ; these bits are set in create_object_file (in obj_file.c) in the beginning ; of the procedure descriptor for all GT.M MUMPS object modules .endm fis-gtm-V6.0-003/sr_avms/putframe.max0000644000032200000250000000072112201176170016343 0ustar librarygtc; Save registers into current GT.M MUMPS stack frame ; Note: this macro requires a scratch register; you may specify one or it will default to r0. .macro putframe reg=r0 ; A_frame_pointer must be address of quadword containing the address of frame_pointer ldq reg, A_frame_pointer ldl reg, (reg) stl r8, msf$l_symtab_off(reg) stl r9, msf$temps_ptr_off(reg) stl r13, msf$ctxt_off(reg) stl r14, msf$literal_ptr_off(reg) stl r26, msf$mpc_off(reg) .endm fis-gtm-V6.0-003/sr_avms/release_name.h0000644000032200000250000000104712201176170016604 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #define GTM_RELEASE_NAME "GT.M V6.0-003 VMS AXP" #define GTM_PRODUCT "GT.M" #define GTM_VERSION "V6.0" fis-gtm-V6.0-003/sr_avms/rundown_dispatch.m640000644000032200000250000000020612201176170017712 0ustar librarygtc .title RUNDOWN_DISPATCH $routine RUNDOWN_DISPATCH, kind=stack .base r27, $ls $call USER_RUNDOWN $return $end_routine .end fis-gtm-V6.0-003/sr_avms/secshrlink.axp0000644000032200000250000000220512201176170016667 0ustar librarygtc!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! ! Copyright 2001, 2010 Fidelity Information Services, Inc ! ! ! ! This source code contains the intellectual property ! ! of its copyright holder(s), and is made available ! ! under a license. If you do not know the terms of ! ! the license, please stop and do not read further. ! ! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! protect=yes obd/inc=(gtmsecplv,crit_wake,del_sec,init_sec,gtm_enq,gtm_enqw,gtm_deq,gtm_blkast) obd/inc=(get_proc_info,init_secshr_addrs,gtm_getlkiw,secshr_db_clnup) obd/inc=(adawi,bci,gtm_memmove,mutex_stoprel,probe,prober,probew,relqueop,rundown_dispatch) obd/inc=(sec_shr_blk_build,sec_shr_map_build,aswp_secshr,compswap_secshr,is_proc_alive) urd gsmatch=lequal,13,0 symbol_vector=( - crit_wake = PROCEDURE, - del_sec = PROCEDURE, - init_sec = PROCEDURE, - gtm_enq = PROCEDURE, - gtm_enqw = PROCEDURE, - gtm_deq = PROCEDURE, - gtm_blkast = PROCEDURE, - get_proc_info = PROCEDURE, - init_secshr_addrs = PROCEDURE, - gtm_getlkiw = PROCEDURE, - secshr_db_clnup = PROCEDURE, - probe = PROCEDURE - ) fis-gtm-V6.0-003/sr_avms/zc_call.m640000644000032200000250000001727012201176170015757 0ustar librarygtc; **************************************************************** ; * * ; * Copyright 2001, 2012 Fidelity Information Services, Inc * ; * This source code contains the intellectual property * ; * of its copyright holder(s), and is made available * ; * under a license. If you do not know the terms of * ; * the license, please stop and do not read further. * ; * * ; **************************************************************** .title ZC_CALL ; Call interface: ; ; int zc_call (zcrtn, zcret, lcllist, lcllistend, save_ret); ; zctabrtn *zcrtn; ; zctabret *zcret; ; lclarg *lcllist, *lcllistend; ; int *save_ret; ; ; On entry, lcllist points to a list of local arguments, and lcllistend ; points to the byte just after the last argument in the list. ZC_CALL ; passes these arguments to the routine pointed to by zcrtn, and processes ; the return value as specified by zcret and save_ret. ; The following definitions must reflect the structure layouts in ZCALL.H: ; ZCALL Table routine offsets (correspond to type zctabrtn): rtn_entrypoint = 4 ; ZCALL Table return offsets (correspond to type zctabret): ret_class = 0 ret_type = 1 ; ZCALL Table argument offsets (correspond to types zctabinput and zctaboutput): arg_mechanism = 0 arg_type = 1 arg_qualifier = 3 ; Local argument offsets; these definitions reflect the structure layout of ; type lclarg, which is defined in DO_ZCALL.C: lcl_skip = 0 lcl_zctab = 4 lcl_dsc = 8 lcl_size = 48 zcdef macro64$callstd_defs $linkage_section a_zcch: .address ZCCH L_ERR_ZCSTATUS: .long ERR_ZCSTATUS L_ERR_GTMCHECK: .long ERR_GTMCHECK $code_section $routine ZC_CALL, entry=ZC_CALL_CA, kind=stack, saved_regs=, - handler=GTM$DYN_CH, rsa_offset=16 stq r31, 8(fp) mov r27, r13 .base r13, $ls ; Process the local arguments in reverse order; ; r18 = lcllist ; r19 = lcllistend clr r0 ; r0 will count the arguments clr r25 ; r25 will accumulate argument information loop: subq r19, lcl_size, r19 cmple r18, r19, r24 blbc r24, setup_call ldl r1, lcl_zctab(r19) ; lclarg.zctab, ZCALL Table argument ; Skip this argument? ldl r26, lcl_skip(r19) ; lclarg.skip blbc r26, 10$ ; Yes; is this argument optional? ldq_u r24, arg_qualifier(r1) lda r23, arg_qualifier(r1) extbl r24, r23, r24 cmpeq r24, zc$iqual_optional, r24 blbs r24, loop ; yes; skip it 10$: addq r0, 1, r0 ; bump the argument count lda sp, -8(sp) ; allocate space for the argument ; Shift any previous argument information up one slot: sll r25, macro64$ai_reg_info1_length, r25 ldq_u r24, arg_mechanism(r1) lda r23, arg_mechanism(r1) extbl r24, r23, r24 lda r22, lcl_dsc(r19) ; lclarg.dsc cmpeq r24, zc$mech_descriptor, r23 blbs r23, by_descriptor cmpeq r24, zc$mech_descriptor64, r23 blbs r23, by_descriptor ldl r22, dsc$a_pointer(r22) cmpeq r24, zc$mech_reference, r23 blbs r23, by_reference cmpeq r24, zc$mech_value, r23 blbc r23, assertfail ; Argument is to be passed by value: ldq_u r24, arg_type(r1) lda r23, arg_type(r1) extbl r24, r23, r24 ; r24 = data type cmpeq r24, zc$dtype_long, r23 blbs r23, long cmpeq r24, zc$dtype_word, r23 blbs r23, word cmpeq r24, zc$dtype_byte, r23 blbs r23, byte cmpeq r24, zc$dtype_longu, r23 blbs r23, longu cmpeq r24, zc$dtype_wordu, r23 blbs r23, wordu cmpeq r24, zc$dtype_byteu, r23 blbs r23, byteu cmpeq r24, zc$dtype_quad, r23 blbs r23, quad cmpeq r24, zc$dtype_floating, r23 blbs r23, float cmpeq r24, zc$dtype_double, r23 blbs r23, double cmpeq r24, zc$dtype_g_floating, r23 blbc r23, assertfail double: mov macro64$ar_fg, r28 ldg f0, (r22) ; D_ or G_floating - fall into float_common float_common: stg f0, (sp) sll r28, macro64$ai_reg_info1_start, r28 or r25, r28, r25 br loop float: ldf f0, (r22) mov macro64$ar_ff, r28 br float_common byte: ldq_u r28, (r22) lda r23, 1(r22) extqh r28, r23, r28 sra r28, 56, r28 stq r28, (sp) br loop byteu: ldq_u r28, (r22) extbl r28, r22, r28 stq r28, (sp) br loop word: ldq_u r28, (r22) ldq_u r27, 1(r22) extwl r28, r22, r28 extwh r27, r22, r27 or r27, r28, r28 sll r28, 48, r28 sra r28, 48, r28 stq r28, (sp) br loop wordu: ldq_u r28, (r22) ldq_u r27, 1(r22) extwl r28, r22, r28 extwh r27, r22, r27 or r27, r28, r28 stq r28, (sp) br loop long: ldq_u r28, (r22) ldq_u r27, 3(r22) extll r28, r22, r28 extlh r27, r22, r27 or r27, r28, r28 sll r28, 32, r28 sra r28, 32, r28 stq r28, (sp) br loop longu: ldq_u r28, (r22) ldq_u r27, 3(r22) extll r28, r22, r28 extlh r27, r22, r27 or r27, r28, r28 stq r28, (sp) br loop quad: ldq_u r28, (r22) ldq_u r27, 7(r22) extql r28, r22, r28 extqh r27, r22, r27 or r27, r28, r28 stq r28, (sp) br loop ; Argument is to be passed by descriptor or by reference: by_descriptor: cmovlbs r26, 0, r22 ; if this arg is to be skipped, zero out r22 by_reference: stq r22, (sp) ; stack address of argument br loop ; All of the arguments have been processed; set up the ZCALL: setup_call: addq r19, lcl_size, r19 ; assert (r19 + lcl_size == lcllist); cmpeq r19, r18, r24 blbc r24, assertfail mov r17, r2 ; save zcret mov r20, r3 ; save save_ret ldl r27, rtn_entrypoint(r16); r27 = zcrtn->entrypoint = address of procedure descriptor ldq r26, 8(r27) ; r26 = address of entry point ; Set up the Argument Information register, r25; ; bits <63:26> must be zero, and the argument count goes in the low order byte: sll r25, 38, r25 srl r25, 38, r25 or r25, r0, r25 ; At this point, all of the arguments are on the stack. Even though there ; may be fewer than six of them, it's a lot faster and easier to load all six ; integer argument registers and all six floating point argument registers ; than it would be to figure out how many to load, and into which registers. ; If there are actually fewer than six arguments, then the values loaded into ; some of these registers will be irrelevant. This is not a big deal. ldq r16, (sp) ldq r17, 8(sp) ldq r18, 16(sp) ldq r19, 24(sp) ldq r20, 32(sp) ldq r21, 40(sp) ldg f16, (sp) ldg f17, 8(sp) ldg f18, 16(sp) ldg f19, 24(sp) ldg f20, 32(sp) ldg f21, 40(sp) ; The stack pointer must also be adjusted to reflect that these arguments have ; been "popped" off the stack. Only the actual number of arguments (up to six) ; will be popped. This leaves the seventh and successive arguments on the stack ; (if any). mov 6, r22 cmplt r0, r22, r24 cmovlbs r24, r0, r22 ; r22 = min(6,r0) = number of arguments popped s8addq r22, sp, sp ldq r28, a_zcch stq r28, 8(fp) ; establish ZCALL condition handler jsr r26, r26 ; ZCALL stq r31, 8(fp) ; remove ZCALL condition handler ; Check the return class: ldq_u r28, ret_class(r2) lda r27, ret_class(r2) extbl r28, r27, r28 ; r28 = zcret->class cmpeq r28, zc$retc_status, r23 blbs r23, check_status cmpeq r28, zc$retc_value, r23 blbc r23, return ; Return class = value; check the data type: ldq_u r24, ret_type(r2) lda r27, ret_type(r2) extbl r24, r27, r24 ; r24 = zcret->type cmpeq r24, zc$dtype_long, r23 blbs r23, quad_ret cmpeq r24, zc$dtype_longu, r23 blbs r23, quad_ret cmpeq r24, zc$dtype_quad, r23 blbs r23, quad_ret cmpeq r24, zc$dtype_floating, r23 blbs r23, float_ret cmpeq r24, zc$dtype_double, r23 blbs r23, double_ret cmpeq r24, zc$dtype_g_floating, r23 blbc r23, assertfail double_ret: stg f0, (r3) br return float_ret: stf f0, (r3) br return quad_ret: stq r0, (r3) return: $return check_status: stl r0, (r3) blbs r0, return mov r0, r18 $call LIB$SIGNAL, args=, nonstandard=true br return assertfail: $call LIB$SIGNAL, args=L_ERR_GTMCHECK/L, nonstandard=true br return $end_routine .end fis-gtm-V6.0-003/sr_avms/zc_makespace.m640000644000032200000250000000333612201176170016773 0ustar librarygtc; **************************************************************** ; * * ; * Copyright 2001, 2004 Sanchez Computer Associates, Inc. * ; * This source code contains the intellectual property * ; * of its copyright holder(s), and is made available * ; * under a license. If you do not know the terms of * ; * the license, please stop and do not read further. * ; * * ; **************************************************************** .title ZC_MAKESPACE ; ; Call interface: ; ; void zc_makespace (dst, mask, mvallist, mvallistend, zcrtn, n_tabargs) ; mval *dst, **mvallist, **mvallistend; ; long mask; ; zctabrtn *zcrtn; ; unsigned n_tabargs; ; ; ZC_MAKESPACE calls DO_ZCALL as follows: ; ; do_zcall (dst, mask, mvallist, mvallistend, zcrtn, lcllist, lcllistend); ; ; where: ; ; dst ... zcrtn are simply passed on unchanged; ; lcllist is the address of the first element of an array of ; struct lclarg_type [see DO_ZCALL.C for definition]; and ; lcllistend is the address of the next byte after the last element ; in the array pointed to by lcllist. ; ; Since lcllistend is the seventh argument, it must be passed on the stack. ; The array is also allocated on the stack; the number of elements is specified ; by the input parameter n_tabargs, and the size of each element is 48 bytes. ; See DO_ZCALL.C for details. ; $routine ZC_MAKESPACE, entry=ZC_MAKESPACE_CA, kind=stack .base r27, $ls ; On entry, r21 = n_tabargs mulq r21, 48, r21 ; r21 = n_tabargs * 48 subq sp, r21, sp mov sp, r21 ; r21 = lcllist ; lcllistend = fp [= original sp] $call DO_ZCALL, args= $return $end_routine .end fis-gtm-V6.0-003/sr_cmi/0000755000032200000250000000000012201176175013620 5ustar librarygtcfis-gtm-V6.0-003/sr_cmi/cmi_close.c0000644000032200000250000000443612201176175015730 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include #include #include "cmihdr.h" #include "cmidef.h" #include "efn.h" #define TIMER_FLAGS 0 GBLREF struct NTD *ntd_root; uint4 cmi_close(struct CLB *lnk) { uint4 efn_mask, status; static readonly int4 delta_1_sec[2] = { -10000000, -1 }; struct CLB *previous; qio_iosb iosb; lnk->sta = CM_CLB_DISCONNECT; previous = RELQUE2PTR(lnk->cqe.fl); remqti(previous); efn_mask = (0x1 << efn_cmi_immed_wait | 0x1 << efn_2timer); /* DECnet OSI does not currently time out if the channel is gone, so protect it with our own timer */ status = sys$setimr(efn_2timer, &delta_1_sec, 0, lnk, TIMER_FLAGS); if (status & 1) { /* If we can't get the timer (which we believe should be exceedingly rare), just blow it away to prevent a hang */ /* First, request a disconnect (also transmits all pending messages before disconnecting). */ status = SYS$QIO(efn_cmi_immed_wait, lnk->dch, IO$_DEACCESS | IO$M_SYNCH, &iosb, 0, 0, 0, 0, 0, 0, 0, 0); /* Ignore previous status return because we're going to deassign the link regardless. */ status = sys$wflor(efn_2timer, efn_mask); /* Unless in test, ignore previous status return because we're going to deassign the link regardless. */ assert(status & 1); }else assert(0); /* In testing trap the timer failure */ sys$cantim(lnk, 0); /* in case still running */ /* abort the link in case the timer went off */ status = SYS$QIOW(EFN$C_ENF, lnk->dch, IO$_DEACCESS | IO$M_ABORT, &iosb, 0, 0, 0, 0, 0, 0, 0, 0); /* Ignore previous status return because we're going to deassign the link regardless. */ status = SYS$CANCEL(lnk->dch); /* Ignore previous status for same reason. */ status = SYS$DASSGN(lnk->dch); if ((status & 1) == 0) return status; lib$free_vm(&SIZEOF(*lnk), &lnk, 0); return status; } fis-gtm-V6.0-003/sr_cmi/cmi_init.c0000644000032200000250000000344112201176175015561 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include #include #include #ifdef __Alpha_AXP #include nfbdef #else #include #endif #include "cmihdr.h" #include "cmidef.h" GBLREF struct NTD *ntd_root; uint4 cmi_init(cmi_descriptor *tnd, unsigned char tnr, void (*err)(), void (*crq)(), bool (*acc)()) { uint4 status; #ifdef __Alpha_AXP # pragma member_alignment save # pragma nomember_alignment #endif struct { unsigned char operation; int4 object_number; } nfb; #ifdef __Alpha_AXP # pragma member_alignment restore #endif struct dsc$descriptor_s nfb_desc; qio_iosb iosb; error_def(CMI_CMICHECK); status = cmj_netinit(); if ((status & 1) == 0) return status; nfb_desc.dsc$w_length = SIZEOF(nfb); nfb_desc.dsc$b_dtype = DSC$K_DTYPE_T; nfb_desc.dsc$b_class = DSC$K_CLASS_S; nfb_desc.dsc$a_pointer = &nfb; if (tnr != 0) { nfb.operation = NFB$C_DECLOBJ; nfb.object_number = tnr; if (0 != tnd) return CMI_CMICHECK; } else { if (0 == tnd) return CMI_CMICHECK; nfb.operation = NFB$C_DECLNAME; nfb.object_number = 0; } status = sys$qiow(EFN$C_ENF, ntd_root->dch, IO$_ACPCONTROL, &iosb, 0, 0, &nfb_desc, tnd, 0, 0, 0, 0); if (status & 1) status = iosb.status; if ((status & 1) == 0) return status; ntd_root->err = err; ntd_root->crq = crq; ntd_root->acc = acc; status = cmj_mbx_read_start(ntd_root); return status; } fis-gtm-V6.0-003/sr_cmi/cmi_open.c0000644000032200000250000000351712201176175015563 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include #include #include #include "cmihdr.h" #include "cmidef.h" GBLREF struct NTD *ntd_root; GBLREF struct dsc$descriptor_s cm_netname; #define TASK_PREFIX "::\"0=" #define TASK_SUFFIX "\"" #define MAX_NCB_LENGTH 128 uint4 cmi_open(struct CLB *lnk) { uint4 status; struct dsc$descriptor_s ncb; qio_iosb iosb; unsigned char *cp; unsigned char ncb_buffer[MAX_NCB_LENGTH]; if (ntd_root == 0) { status = cmj_netinit(); if ((status & 1) == 0) return status; } ncb.dsc$w_length = lnk->nod.dsc$w_length + lnk->tnd.dsc$w_length + SIZEOF(TASK_PREFIX) - 1 + SIZEOF(TASK_SUFFIX) - 1; ncb.dsc$b_dtype = DSC$K_DTYPE_T; ncb.dsc$b_class = DSC$K_CLASS_S; ncb.dsc$a_pointer = cp = ncb_buffer; assert(ncb.dsc$w_length < SIZEOF(ncb_buffer)); memcpy(cp, lnk->nod.dsc$a_pointer, lnk->nod.dsc$w_length); cp += lnk->nod.dsc$w_length; memcpy(cp, TASK_PREFIX, SIZEOF(TASK_PREFIX) - 1); cp += SIZEOF(TASK_PREFIX) - 1; memcpy(cp, lnk->tnd.dsc$a_pointer, lnk->tnd.dsc$w_length); cp += lnk->tnd.dsc$w_length; memcpy(cp, TASK_SUFFIX, SIZEOF(TASK_SUFFIX) - 1); status = sys$assign(&cm_netname, &lnk->dch, 0, 0); if (status & 1) { status = sys$qiow(EFN$C_ENF, lnk->dch, IO$_ACCESS, &iosb, 0, 0, 0, &ncb, 0, 0, 0, 0); if (status & 1) status = iosb.status; if (status & 1) { insqhi(lnk, ntd_root); }else { sys$dassgn(lnk->dch); } } return status; } fis-gtm-V6.0-003/sr_cmi/cmi_read.c0000644000032200000250000000115512201176175015531 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include #include "cmihdr.h" #include "cmidef.h" uint4 cmi_read(lnk) struct CLB *lnk; { lnk->cbl = lnk->mbl; return cmj_iostart(lnk,IO$_READVBLK, CM_CLB_READ); } fis-gtm-V6.0-003/sr_cmi/cmi_write.c0000644000032200000250000000113312201176175015744 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include #include "cmihdr.h" #include "cmidef.h" uint4 cmi_write(lnk) struct CLB *lnk; { return cmj_iostart(lnk, IO$_WRITEVBLK, CM_CLB_WRITE); } fis-gtm-V6.0-003/sr_cmi/cmi_write_int.c0000644000032200000250000000157712201176175016632 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include #include #include "cmihdr.h" #include "cmidef.h" uint4 cmi_write_int(struct CLB *lnk) { int4 status; qio_iosb iosb; /* Note: there is an outstanding read so use unique efn and iosb */ status = sys$qiow(EFN$C_ENF, lnk->dch, IO$_WRITEVBLK | IO$M_INTERRUPT, &iosb, 0, 0, lnk->mbf, lnk->cbl, 0, 0, 0, 0); if (status & 1) status = iosb.status; return status; } fis-gtm-V6.0-003/sr_cmi/cmierrors.msg0000644000032200000250000000156512201176175016344 0ustar librarygtc!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! ! Copyright 2001, 2009 Fidelity Information Services, Inc ! ! ! ! This source code contains the intellectual property ! ! of its copyright holder(s), and is made available ! ! under a license. If you do not know the terms of ! ! the license, please stop and do not read further. ! ! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .FACILITY CMI,250/PREFIX=CMI_ .TITLE CMIERRORS Error Messages for CMI..GT.CM DCNINPROG /fatal/fao=0 LNKNOTIDLE /fatal/fao=0 ASSERT /error/fao=3 CMICHECK /fatal/fao=0 NETFAIL /error/fao=0 .end fis-gtm-V6.0-003/sr_cmi/cmihdr.h0000644000032200000250000000161712201176175015244 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "gtm_sizeof.h" #define rts_error lib$signal #define error_def(x) globalvalue x #ifdef DEBUG error_def(CMI_ASSERT); #define assert(x) ((x) ? 1 : rts_error(CMI_ASSERT, 3, SIZEOF(__FILE__) - 1, __FILE__, __LINE__)) #else #define assert(x) #endif #define GBLDEF globaldef #define GBLREF globalref #define LITDEF readonly globaldef #define LITREF readonly globalref typedef char bool; #define ALIGN_QUAD _align(quadword) #define TRUE 1 #define FALSE 0 fis-gtm-V6.0-003/sr_cmi/cmivector.mar0000644000032200000250000000065112201176175016316 0ustar librarygtc .title cmivector - transfer vectors for shared images .psect cmivector,page,con,exe,pic,nowrt,shr,gbl cmivector_size = 16 ;total of 16 transfer vectors .macro xfer a .transfer a .mask a jmp l^a+2 .endm cmivector:: xfer cmi_close xfer cmi_init xfer cmi_open xfer cmi_read xfer cmi_write xfer cmi_write_int xfer cmu_makclb xfer cmu_getclb xfer cmu_ntdroot .blkq cmivector_size - <<. - cmivector> / 8> .end fis-gtm-V6.0-003/sr_cmi/cmj_ast.c0000644000032200000250000000122612201176175015405 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "cmihdr.h" #include "cmidef.h" void cmj_ast(lnk) struct CLB *lnk; { uint4 status; error_def(CMI_DCNINPROG); error_def(CMI_LNKNOTIDLE); cmj_fini(lnk); if (lnk->ast != 0) (*lnk->ast)(lnk); return; } fis-gtm-V6.0-003/sr_cmi/cmj_disconn2.c0000644000032200000250000000144412201176175016337 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "cmihdr.h" #include "cmidef.h" void cmj_disconn2(lnk) struct CLB *lnk; { int status; error_def(CMI_NETFAIL); /* Ignore iosb of previous qio because we're going to deassign the link regardless. */ status = SYS$DASSGN(lnk->dch); lib$free_vm(&SIZEOF(*lnk), &lnk, 0); if ((status & 1) == 0) rts_error(CMI_NETFAIL,0,status); return; } fis-gtm-V6.0-003/sr_cmi/cmj_fini.c0000644000032200000250000000136512201176175015547 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "cmihdr.h" #include "cmidef.h" void cmj_fini(lnk) struct CLB *lnk; { switch (lnk->sta) { case CM_CLB_READ: lnk->cbl = lnk->ios.xfer_count; break; case CM_CLB_WRITE: break; case CM_CLB_IDLE: assert(FALSE); break; case CM_CLB_DISCONNECT: return; } lnk->sta = CM_CLB_IDLE; return; } fis-gtm-V6.0-003/sr_cmi/cmj_iostart.c0000644000032200000250000000241412201176175016303 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include #include #include "cmihdr.h" #include "cmidef.h" #include "efn.h" uint4 cmj_iostart(struct CLB *lnk, uint4 operation, unsigned int state) { uint4 status; error_def(CMI_DCNINPROG); error_def(CMI_LNKNOTIDLE); void cmj_ast(); if (lnk->sta != CM_CLB_IDLE) return (lnk->sta == CM_CLB_DISCONNECT) ? CMI_DCNINPROG : CMI_LNKNOTIDLE; lnk->sta = (unsigned char)state; if (lnk->ast) { status = sys$qio(EFN$C_ENF, lnk->dch, operation, &lnk->ios, cmj_ast, lnk, lnk->mbf, lnk->cbl, 0, 0, 0, 0); } else { status = sys$qio(EFN$C_ENF, lnk->dch, operation, &lnk->ios, 0, 0, lnk->mbf, lnk->cbl, 0, 0, 0, 0); if (1 & status) { status = sys$synch(EFN$C_ENF, &lnk->ios); cmj_fini(lnk); if (1 & status) status = lnk->ios.status; } } return status; } fis-gtm-V6.0-003/sr_cmi/cmj_mbx_ast.c0000644000032200000250000001201712201176175016253 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include #include #include #include #include #include "cmihdr.h" #include "cmidef.h" #include "efn.h" GBLREF struct dsc$descriptor_s cm_netname; error_def(CMI_NETFAIL); static void cmj_accept_ast(), cmj_reject_ast(), cmj_mbx_err(); void cmj_mbx_ast(struct NTD *tsk) { struct CLB *cmu_makclb(); struct dsc$descriptor_s ncb_desc; uint4 status, unit; cm_mbx *mp; struct CLB *lnk; bool newclb; void cmj_ast(); status = 0; mp = tsk->mbx.dsc$a_pointer; assert(mp->netnum == 3 && mp->netnam[0] == 'N' && mp->netnam[1] == 'E' && mp->netnam[2] == 'T'); switch(mp->msg) { case MSG$_CONNECT: lnk = cmj_unit2clb(tsk, mp->unit); if (lnk == 0) { newclb = TRUE; lnk = cmu_makclb(); lnk->dch = tsk->dch; lnk->ntd = tsk; }else { newclb = FALSE; assert(lnk->sta == CM_CLB_IDLE); } ncb_desc.dsc$w_length = mp->len; ncb_desc.dsc$b_dtype = DSC$K_DTYPE_T; ncb_desc.dsc$b_class = DSC$K_CLASS_S; ncb_desc.dsc$a_pointer = mp->text; lnk->mbf = 0; /* the statement below and the 3 qio's emulate cmj_iostart which could be used if lnk->clb were a int4 */ lnk->sta = CM_CLB_WRITE; if (tsk->crq == 0) { lnk->ast = cmj_reject_ast; status = sys$qio(efn_ignore, lnk->dch, IO$_ACCESS | IO$M_ABORT, &lnk->ios, cmj_ast, lnk, lnk->mbf, &ncb_desc, 0, 0, 0, 0); } else { if (tsk->acc && !(*tsk->acc)(lnk)) { lnk->ast = cmj_reject_ast; status = sys$qio(efn_ignore, lnk->dch, IO$_ACCESS | IO$M_ABORT, &lnk->ios, cmj_ast, lnk, lnk->mbf, &ncb_desc, 0, 0, 0, 0); }else { status = sys$assign(&cm_netname, &lnk->dch, 0, &tsk->mnm); if (status & 1) { status = lib$getdvi(&DVI$_UNIT, &lnk->dch, 0, &unit, 0, 0); if (status & 1) { lnk->mun = (unsigned short)unit; lnk->ast = cmj_accept_ast; status = sys$qio(efn_ignore, lnk->dch, IO$_ACCESS, &lnk->ios, cmj_ast, lnk, lnk->mbf, &ncb_desc, 0, 0, 0, 0); } } } } if ((status & 1) == 0) { if (newclb) { lib$free_vm(&SIZEOF(*lnk), &lnk, 0); lnk = 0; } cmj_mbx_err(status, tsk, lnk); break; } return; case MSG$_INTMSG: if (tsk->mbx_ast != 0) { (*tsk->mbx_ast)(tsk); break; } /* CAUTION: FALLTHROUGH */ case MSG$_DISCON: case MSG$_ABORT: case MSG$_EXIT: case MSG$_PATHLOST: case MSG$_PROTOCOL: case MSG$_THIRDPARTY: case MSG$_TIMEOUT: case MSG$_NETSHUT: case MSG$_REJECT: case MSG$_CONFIRM: if (tsk->err) { lnk = cmj_unit2clb(tsk, mp->unit); (*tsk->err)(tsk, lnk, mp->msg); }else rts_error(CMI_NETFAIL,0,status); /* condition handler would need to close the connection */ /* CAUTION: FALLTHROUGH */ default: break; } status = cmj_mbx_read_start(tsk); if ((status & 1) == 0) { lnk = cmj_unit2clb(tsk, mp->unit); cmj_mbx_err(status, tsk, lnk); } } static void cmj_reject_ast(struct CLB *lnk) { struct NTD *tsk; uint4 status; tsk = lnk->ntd; status = lnk->ios.status; if ((status & 1) == 0) { if (cmj_unit2clb(tsk, lnk->mun) == 0) { lib$free_vm(&SIZEOF(*lnk), &lnk, 0); lnk = 0; } cmj_mbx_err(status, tsk, lnk); } status = cmj_mbx_read_start(tsk); if ((status & 1) == 0) cmj_mbx_err(status, tsk, lnk); } static void cmj_accept_ast(struct CLB *lnk) { struct NTD *tsk; uint4 status; tsk = lnk->ntd; status = lnk->ios.status; if ((status & 1) == 0) { if (cmj_unit2clb(tsk, lnk->mun) == 0) { lib$free_vm(&SIZEOF(*lnk), &lnk, 0); lnk = 0; } cmj_mbx_err(status, tsk, lnk); }else { insqhi(lnk, tsk); (*tsk->crq)(lnk); } status = cmj_mbx_read_start(tsk); if ((status & 1) == 0) cmj_mbx_err(status, tsk, lnk); } static void cmj_mbx_err(uint4 status, struct NTD *tsk, struct CLB *lnk) { unsigned int msg; if (tsk->err) { switch (status) { case SS$_LINKABORT: msg = MSG$_ABORT; break; case SS$_LINKDISCON: msg = MSG$_DISCON; break; case SS$_LINKEXIT: msg = MSG$_EXIT; break; case SS$_PATHLOST: msg = MSG$_PATHLOST; break; case SS$_PROTOCOL: msg = MSG$_PROTOCOL; break; case SS$_THIRDPARTY: msg = MSG$_THIRDPARTY; break; case SS$_CONNECFAIL: case SS$_TIMEOUT: msg= MSG$_TIMEOUT; break; case SS$_REJECT: msg = MSG$_REJECT; break; default: case SS$_DEVALLOC: case SS$_IVDEVNAM: assert(FALSE); /* CAUTION: FALLTHROUGH */ case SS$_NOSUCHNODE: case SS$_UNREACHABLE: msg = MSG$_NODEINACC; break; } (*tsk->err)(tsk, lnk, msg); }else rts_error(CMI_NETFAIL,0,status); /* condition handler would need to close the connection */ } fis-gtm-V6.0-003/sr_cmi/cmj_mbx_read_start.c0000644000032200000250000000141412201176175017613 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include #include "cmihdr.h" #include "cmidef.h" #include "efn.h" int cmj_mbx_read_start(struct NTD *tsk) { void cmj_mbx_ast(); int status; status = sys$qio(efn_ignore, tsk->mch, IO$_READVBLK, &(tsk->mst), &cmj_mbx_ast, tsk, tsk->mbx.dsc$a_pointer, tsk->mbx.dsc$w_length, 0, 0, 0, 0); return status; } fis-gtm-V6.0-003/sr_cmi/cmj_netinit.c0000644000032200000250000000367412201176175016301 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include #include #include "cmihdr.h" #include "cmidef.h" GBLDEF $DESCRIPTOR(cm_netname,"_NET:"); GBLDEF struct NTD *ntd_root; /* CLEAN-UP: 1. replace CMI_CMICHECK with new message 2. find correct size and location of MBX_SIZE */ #define MBX_SIZE 256 uint4 cmj_netinit() { error_def(CMI_CMICHECK); uint4 status; int4 maxmsg,bufquo; /* lib$asn_wth_mbx uses longwords by reference for these items */ struct NTD *tsk; unsigned char mailbox_name_buffer[128]; short unsigned mbx_name_length; uint4 long_mnl; if (ntd_root) return CMI_CMICHECK; lib$get_vm(&SIZEOF(*ntd_root), &ntd_root, 0); tsk = ntd_root; memset(tsk, 0, SIZEOF(*tsk)); tsk->mbx.dsc$w_length = MBX_SIZE; tsk->mbx.dsc$b_dtype = DSC$K_DTYPE_T; tsk->mbx.dsc$b_class = DSC$K_CLASS_S; lib$get_vm(&MBX_SIZE, &tsk->mbx.dsc$a_pointer, 0); maxmsg = tsk->mbx.dsc$w_length; bufquo = maxmsg; status = lib$asn_wth_mbx(&cm_netname, &maxmsg, &bufquo, &(tsk->dch), &(tsk->mch)); if ((status & 1) == 0) return status; tsk->mnm.dsc$w_length = SIZEOF(mailbox_name_buffer); tsk->mnm.dsc$b_dtype = DSC$K_DTYPE_T; tsk->mnm.dsc$b_class = DSC$K_CLASS_S; tsk->mnm.dsc$a_pointer = mailbox_name_buffer; status = lib$getdvi(&DVI$_FULLDEVNAM, &tsk->mch,0,0,&tsk->mnm,&mbx_name_length); if ((status & 1) == 0) return status; long_mnl = mbx_name_length; lib$get_vm(&long_mnl, &tsk->mnm.dsc$a_pointer, 0); tsk->mnm.dsc$w_length = mbx_name_length; memcpy(tsk->mnm.dsc$a_pointer, mailbox_name_buffer, mbx_name_length); return status; } fis-gtm-V6.0-003/sr_cmi/cmj_unit2clb.c0000644000032200000250000000130312201176175016334 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "cmihdr.h" #include "cmidef.h" struct CLB *cmj_unit2clb(tsk,unit) struct NTD *tsk; unsigned short unit; { struct CLB *p; for (p = RELQUE2PTR(tsk->cqh.fl) ; p != tsk ; p = RELQUE2PTR(p->cqe.fl)) { if (p->mun == unit) return p; } return 0; } fis-gtm-V6.0-003/sr_cmi/cmj_util.mar0000644000032200000250000000215212201176175016127 0ustar librarygtc .title cmj_util utility routines ; remqti - remove self-relative queue entry from tail interlocked ; ; calling sequence: ; ; typedef struct ; { ; long flink,blink; ; } self_rel_que; ; ; self_rel_que *remqti(queheader) ; self_rel_que *queheader; ; ; return: ; if successful, then a pointer to the queue entry which was removed ; if zero, then the queue was empty ; if -1, then the secondary interlock failed, the instruction may ; be retried, but should declare a GTMCHECK if the secondary ; interlock fails repeatedly ; QI_STARVATION = 6 .entry insqhi,^m<> clrl r0 movl #QI_STARVATION,r1 5$: insqhi @4(ap),@8(ap) bcs 20$ bneq 10$ incl r0 10$: ret 20$: sobgtr r1,5$ decl r0 ret .entry insqti,^m<> clrl r0 movl #QI_STARVATION,r1 5$: insqti @4(ap),@8(ap) bcs 20$ bneq 10$ incl r0 10$: ret 20$: sobgtr r1,5$ decl r0 ret .entry remqhi,^m<> movl #QI_STARVATION,r1 5$: remqhi @4(ap),r0 bcs 20$ bvc 10$ clrl r0 10$: ret 20$: sobgtr r1,5$ mnegl #1,r0 ret .entry remqti,^m<> movl #QI_STARVATION,r1 5$: remqti @4(ap),r0 bcs 20$ bvc 10$ clrl r0 10$: ret 20$: sobgtr r1,5$ mnegl #1,r0 ret .end fis-gtm-V6.0-003/sr_cmi/cmu_getclb.c0000644000032200000250000000177312201176175016100 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "cmihdr.h" #include "cmidef.h" GBLREF struct NTD *ntd_root; struct CLB *cmu_getclb(node, task) cmi_descriptor *node, *task; { struct CLB *p; if (ntd_root) { for (p = RELQUE2PTR(ntd_root->cqh.fl) ; p != ntd_root ; p = RELQUE2PTR(p->cqe.fl)) { if (p->nod.dsc$w_length == node->dsc$w_length && memcmp(p->nod.dsc$a_pointer, node->dsc$a_pointer, p->nod.dsc$w_length) == 0) { if (p->tnd.dsc$w_length == task->dsc$w_length && memcmp(p->tnd.dsc$a_pointer, task->dsc$a_pointer, p->tnd.dsc$w_length) == 0) return p; } } } return 0; } fis-gtm-V6.0-003/sr_cmi/cmu_makclb.c0000644000032200000250000000115712201176175016065 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "cmihdr.h" #include "cmidef.h" struct CLB *cmu_makclb() { struct CLB *lnk; lib$get_vm(&SIZEOF(*lnk), &lnk, 0); memset(lnk, 0, SIZEOF(*lnk)); return lnk; } fis-gtm-V6.0-003/sr_cmi/cmu_ntdroot.c0000644000032200000250000000106512201176175016323 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "cmihdr.h" #include "cmidef.h" GBLREF struct NTD *ntd_root; struct NTD *cmu_ntdroot() { return ntd_root; } fis-gtm-V6.0-003/sr_i386/0000755000032200000250000000000012201176214013533 5ustar librarygtcfis-gtm-V6.0-003/sr_i386/aswp.s0000644000032200000250000000133112201176146014673 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title aswp.s .sbttl aswp .include "linkage.si" # .386 # .MODEL FLAT, C .text ENTRY aswp movl 4(%esp),%edx # A(latch longword) movl 8(%esp),%eax # replacement value # LOCK xchg (%edx),%eax # return original value lock xchgl (%edx),%eax # return original value ret fis-gtm-V6.0-003/sr_i386/auto_zlink.c0000644000032200000250000000557712201176175016102 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "i386.h" #include "urx.h" #include #include "op.h" #include #define PEA_SZ 5 #define XFER_BYTE_SZ 3 #define XFER_LONG_SZ 6 #define INST_SZ 1 error_def(ERR_LABELUNKNOWN); error_def(ERR_ROUTINEUNKNOWN); rhdtyp *auto_zlink (unsigned char *pc, int4 **line) { char *adj_pc; /* address of PEA rtnref offset */ mstr rname; mident_fixed rname_local; urx_rtnref *rtnurx; mval rtn; rhdtyp *rhead; union { ModR_M modrm; unsigned char byte; } modrm_byte_byte, modrm_byte_long; /* ASSUMPTION -- The instruction previous to the current mpc is a transfer table jump. * This is either a byte or a int4 displacement off of ebx, instruction * size either 3 or 6 (prefix byte, ModR/M byte, 8- or 32-bit offset). */ modrm_byte_byte.modrm.reg_opcode = I386_INS_CALL_Ev; modrm_byte_byte.modrm.mod = I386_MOD32_BASE_DISP_8; modrm_byte_byte.modrm.r_m = I386_REG_EBX; modrm_byte_long.modrm.reg_opcode = I386_INS_CALL_Ev; modrm_byte_long.modrm.mod = I386_MOD32_BASE_DISP_32; modrm_byte_long.modrm.r_m = I386_REG_EBX; if ((*(pc - XFER_BYTE_SZ) == I386_INS_Grp5_Prefix) && (*(pc - XFER_BYTE_SZ + 1) == modrm_byte_byte.byte)) { assert(*(pc - XFER_BYTE_SZ - PEA_SZ) == I386_INS_PUSH_Iv); adj_pc = (char *)pc - XFER_BYTE_SZ - PEA_SZ; } else if ((*(pc - XFER_LONG_SZ) == I386_INS_Grp5_Prefix) && (*(pc - XFER_LONG_SZ + 1) == modrm_byte_long.byte)) { assert(*(pc - XFER_LONG_SZ - PEA_SZ) == I386_INS_PUSH_Iv); adj_pc = (char *)pc - XFER_LONG_SZ - PEA_SZ; } else GTMASSERT; if (azl_geturxrtn(adj_pc + INST_SZ, &rname, &rtnurx)) { assert((0 <= rname.len) && (MAX_MIDENT_LEN >= rname.len)); assert(rname.addr); /* Copy rname into local storage because azl_geturxrtn sets rname.addr to an address that is * freed during op_zlink and before the call to find_rtn_hdr. */ memcpy(rname_local.c, rname.addr, rname.len); rname.addr = rname_local.c; assert(rtnurx); assert(*(adj_pc - PEA_SZ) == I386_INS_PUSH_Iv); assert(azl_geturxlab(adj_pc - PEA_SZ + INST_SZ, rtnurx)); assert(!find_rtn_hdr(&rname)); rtn.mvtype = MV_STR; rtn.str.len = rname.len; rtn.str.addr = rname.addr; op_zlink (&rtn, 0); if (0 != (rhead = find_rtn_hdr(&rname))) /* note the assignment */ { *line = *(int4 **)(adj_pc - PEA_SZ + INST_SZ); if (!(*line)) rts_error(VARLSTCNT(1) ERR_LABELUNKNOWN); return rhead; } } rts_error(VARLSTCNT(1) ERR_ROUTINEUNKNOWN); return NULL; } fis-gtm-V6.0-003/sr_i386/auto_zlink.h0000644000032200000250000000106512201176146016071 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __AUTO_ZLINK_H__ #define __AUTO_ZLINK_H__ rhdtyp *auto_zlink (unsigned char *pc, int4 **line); #endif fis-gtm-V6.0-003/sr_i386/call_dm.s0000644000032200000250000000130212201176146015312 0ustar librarygtc################################################################# # # # Copyright 2001, 2007 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title call_dm.s .sbttl call_dm .include "linkage.si" # .386 # .MODEL FLAT, C .DATA .text .extern op_oldvar .extern opp_dmode # PUBLIC call_dm # call_dm PROC ENTRY call_dm l1: call opp_dmode call op_oldvar jmp l1 ret # call_dm ENDP # END fis-gtm-V6.0-003/sr_i386/caller_id.s0000644000032200000250000000123012201176146015635 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title caller_id.s .sbttl caller_id # .386 # .MODEL FLAT, C .include "linkage.si" .text # PUBLIC caller_id ENTRY caller_id movl 4(%ebp),%eax # address of caller's return address ret # caller_id ENDP # END fis-gtm-V6.0-003/sr_i386/callg.s0000644000032200000250000000273212201176146015011 0ustar librarygtc################################################################# # # # Copyright 2001, 2006 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title callg.s .sbttl callg .include "linkage.si" # .386 # .MODEL FLAT, C # Assembler routine to immitate the VAX CALLG instruction, which can redirect # a routine calls argument list to a prepared list in memory. # This implementation has the caveat that the argument list must be integers, # and that it follows our version of the VMS calling conventions - i.e. that # a count of the arguments following is actually the first thing on the stack. routarg = 8 argsarg = 12 cntsav = -4 .text ENTRY callg enter $4,$0 pushl %edi pushl %esi pushl %ebx movl routarg(%ebp),%edx # routine to call movl argsarg(%ebp),%esi # argument list movl (%esi),%ecx movl %ecx,cntsav(%ebp) # save following argument count addl $4,%esi # skip argument count movl %ecx, %eax negl %eax leal (%esp,%eax,4),%esp movl %esp,%edi pushl %ecx rep movsl call *%edx popl %edx # discard possibly modified count movl cntsav(%ebp),%edx # edx to preserve return value in eax leal (%esp,%edx,4),%esp popl %ebx popl %esi popl %edi leave ret fis-gtm-V6.0-003/sr_i386/ci_restart.s0000644000032200000250000000252512201176146016066 0ustar librarygtc################################################################# # # # Copyright 2001, 2003 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title ci_restart.s .sbttl ci_restart # .386 # .MODEL FLAT, C .include "linkage.si" .DATA .extern param_list .text ENTRY ci_restart pushl %ebp # save C frame pointer movl %esp,%ebp # set frame marker for this procedure movl param_list,%eax movl 4(%eax),%eax # argcnt cmpl $0,%eax # if (argcnt > 0) { jle L0 imull $4,%eax,%edx # param_list->args[argcnt] leal 20(%edx),%edx pushl %eax movl param_list,%eax addl %eax,%edx popl %eax L1: pushl 0(%edx) # pushing arguments backwards subl $4,%edx subl $1,%eax cmpl $0,%eax jg L1 # } L0: movl param_list,%eax pushl 4(%eax) #argcnt pushl 20(%eax) #mask pushl 16(%eax) #retaddr pushl 12(%eax) #labaddr pushl 8(%eax) #rtnaddr pushl 4(%ebp) # push the return address to the caller of ci_restart movl 0(%ebp),%ebp # restore previous C frame pointer jmp *(%eax) ret # ci_restart ENDP # END fis-gtm-V6.0-003/sr_i386/cmerrors_ctl.c0000666000032200000250000000224212201176213016400 0ustar librarygtc/**************************************************************** * * * Copyright 2001,2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "error.h" LITDEF err_msg cmerrors[] = { "INVPROT", "Invalid protocol specified by remote partner", 0, "REGNTFND", "Region referenced not initialized", 0, "CMINTQUE", "Interlock failure accessing GT.CM server queue", 0, "INVINTMSG", "Invalid interrupt message received.", 0, "CMEXCDASTLM", "Exceeded AST limit. Cannot open database.", 0, "CMSYSSRV", "Error doing system service, status:", 0, }; LITDEF int CMERR_INVPROT = 150568970; LITDEF int CMERR_REGNTFND = 150568978; LITDEF int CMERR_CMINTQUE = 150568988; LITDEF int CMERR_INVINTMSG = 150568994; LITDEF int CMERR_CMEXCDASTLM = 150569002; LITDEF int CMERR_CMSYSSRV = 150569010; GBLDEF err_ctl cmerrors_ctl = { 249, "GTCM", &cmerrors[0], 6}; fis-gtm-V6.0-003/sr_i386/cmierrors_ctl.c0000666000032200000250000000543712201176214016563 0ustar librarygtc/**************************************************************** * * * Copyright 2001,2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "error.h" LITDEF err_msg cmierrors[] = { "DCNINPROG", "Attempt to initiate operation while disconnect was in progress", 0, "LNKNOTIDLE", "Attempt to initiate operation before previous operation completed", 0, "ASSERT", "Assert failed !AD line !UL", 3, "CMICHECK", "Internal CMI error. Report to your GT.M Support Channel.", 0, "NETFAIL", "Failure of Net operation", 0, "BADPORT", "Environment variable GTCM_TCP_PORT is not an integer", 0, "NOTND", "tnd argument to cmi_init is NULL", 0, "OVERRUN", "mbf argument in CLB is not large enough for packet", 0, "NOSERVENT", "Sevices data lookup failure", 0, "BADIPADDRPORT", "Bad specification of [ip address:port] in tnd", 0, "REASON_CONNECT", "Incoming connection", 0, "REASON_INTMSG", "Incoming urgent data", 0, "REASON_DISCON", "Disconnect encountered", 0, "REASON_ABORT", "Link aborted", 0, "REASON_EXIT", "Exit", 0, "REASON_PATHLOST", "Network path lost", 0, "REASON_PROTOCOL", "Protocol error", 0, "REASON_THIRDPARTY", "Thirdparty error", 0, "REASON_TIMEOUT", "Network timeout", 0, "REASON_NETSHUT", "Shutdown received", 0, "REASON_REJECT", "Connection rejected", 0, "REASON_IODONE", "I/O done", 0, "REASON_OVERRUN", "Input overran buffer", 0, "REASON_STATUS", "Status", 0, "REASON_CONFIRM", "Confirm", 0, }; LITDEF int CMI_DCNINPROG = 150634508; LITDEF int CMI_LNKNOTIDLE = 150634516; LITDEF int CMI_ASSERT = 150634522; LITDEF int CMI_CMICHECK = 150634532; LITDEF int CMI_NETFAIL = 150634538; LITDEF int CMI_BADPORT = 150634546; LITDEF int CMI_NOTND = 150634556; LITDEF int CMI_OVERRUN = 150634562; LITDEF int CMI_NOSERVENT = 150634570; LITDEF int CMI_BADIPADDRPORT = 150634578; LITDEF int CMI_REASON_CONNECT = 150634586; LITDEF int CMI_REASON_INTMSG = 150634594; LITDEF int CMI_REASON_DISCON = 150634602; LITDEF int CMI_REASON_ABORT = 150634610; LITDEF int CMI_REASON_EXIT = 150634618; LITDEF int CMI_REASON_PATHLOST = 150634626; LITDEF int CMI_REASON_PROTOCOL = 150634634; LITDEF int CMI_REASON_THIRDPARTY = 150634642; LITDEF int CMI_REASON_TIMEOUT = 150634650; LITDEF int CMI_REASON_NETSHUT = 150634658; LITDEF int CMI_REASON_REJECT = 150634666; LITDEF int CMI_REASON_IODONE = 150634674; LITDEF int CMI_REASON_OVERRUN = 150634682; LITDEF int CMI_REASON_STATUS = 150634690; LITDEF int CMI_REASON_CONFIRM = 150634698; GBLDEF err_ctl cmierrors_ctl = { 250, "CMI", &cmierrors[0], 25}; fis-gtm-V6.0-003/sr_i386/compswap.s0000644000032200000250000000150612201176146015556 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title compswap.s .sbttl compswap .include "linkage.si" # .386 # .MODEL FLAT, C .text ENTRY compswap movl 4(%esp),%edx # A(latch longword) movl 8(%esp),%eax # comparison value movl 12(%esp),%ecx # replacement value # LOCK cmpxchgl %ecx,(%edx) lock cmpxchgl %ecx,(%edx) # compare-n-swap jnz fail movl $1,%eax # return TRUE ret fail: xor %eax,%eax # return FALSE ret fis-gtm-V6.0-003/sr_i386/dm_start.s0000644000032200000250000000253612201176146015546 0ustar librarygtc################################################################# # # # Copyright 2001, 2010 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title dm_start.s .sbttl dm_start # .386 # .MODEL FLAT, C .include "linkage.si" .include "error.si" .DATA .extern dollar_truth .extern xfer_table .extern frame_pointer .extern msp .extern mumps_status .extern restart .text .extern mdb_condition_handler .extern op_unwind .ifndef cygwin .type dm_start,@function .endif ENTRY dm_start enter $0,$0 pushl %edi pushl %esi pushl %ebx movl $1,mumps_status leal xfer_table,%ebx movl $1,dollar_truth ESTABLISH mdb_condition_handler, l30 call *restart return: movl mumps_status,%eax popl %ebx popl %esi popl %edi leave ret ENTRY gtm_ret_code REVERT call op_unwind movl msp,%eax movl (%eax),%eax movl %eax,frame_pointer addl $4,msp jmp return # Used by triggers (and eventually call-ins) to return from a nested generated code call # (a call not at the base C stack level). ENTRY gtm_levl_ret_code REVERT jmp return # dm_start ENDP # END fis-gtm-V6.0-003/sr_i386/emit_code.c0000644000032200000250000007552412201176175015652 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include #include "stack_frame.h" #include "opcode.h" #include "xfer_enum.h" #include "mdq.h" #include "vxi.h" #include "vxt.h" #include "cgp.h" #include "obj_gen.h" #include "i386.h" #include "obj_file.h" #include #include "hashtab_mname.h" #include "stddef.h" #define BUFFERED_CODE_SIZE 50 #define LONG_JUMP_OFFSET (0x7ffffffc) #define XFER_BYTE_INST_SIZE 3 #define XFER_LONG_INST_SIZE 6 #define BRB_INST_SIZE 2 #define JMP_LONG_INST_SIZE 5 /* index in ttt from start of call[sp] and forlcldo to xfer_table index */ #define CALL_4LCLDO_XFER 2 typedef enum { CLEAR, COMPARE, INCREMENT, JUMP, LOAD, LOAD_ADDRESS, PUSH, PUSH_ADDRESS, STORE, TEST } generic_op; void emit_pcrel(generic_op op, unsigned char use_reg); void emit_trip(generic_op op, oprtype *opr, bool val_output, unsigned char use_reg); void emit_op_base_offset(generic_op op, short base_reg, int offset, short use_reg); void emit_op_alit (generic_op op, unsigned char use_reg); void emit_jmp(short vax_in, short **instp); unsigned char i386_reg(unsigned char vax_reg); union { ModR_M modrm; unsigned char byte; } modrm_byte; union { SIB sib; unsigned char byte; } sib_byte; LITREF octabstruct oc_tab[]; /* op-code table */ LITREF short ttt[]; /* triple templates */ static unsigned char code_buf[BUFFERED_CODE_SIZE]; static unsigned short code_idx; static int4 jmp_offset, code_reference; static int force_32; static int call_4lcldo_variant; /* used in emit_jmp for call[sp] and forlcldo */ GBLREF int4 curr_addr; GBLREF char cg_phase; /* code generation phase */ GBLDEF uint4 txtrel_cnt; /* count of text relocation records */ /* its referenced in ind_code.c */ GBLDEF int calculated_code_size, generated_code_size; error_def(ERR_UNIMPLOP); error_def(ERR_MAXARGCNT); void trip_gen(triple *ct) { oprtype **sopr, *opr; /* triple operand */ oprtype *saved_opr[MAX_ARGS]; unsigned short oct; short tp; /* template pointer */ short *tsp; /* template short pointer */ triple *ttp; /* temp triple pointer */ short irep_index; oprtype *irep_opr; short *repl, repcnt; /* temp irep ptr */ int4 off; tp = ttt[ct->opcode]; if (tp <= 0) { stx_error(ERR_UNIMPLOP); return; } code_idx = 0; code_reference = ct->rtaddr; oct = oc_tab[ct->opcode].octype; sopr = &saved_opr[0]; *sopr++ = &ct->destination; for (ttp = ct, opr = ttp->operand ; opr < ARRAYTOP(ttp->operand); ) { if (opr->oprclass) { if (opr->oprclass == TRIP_REF && opr->oprval.tref->opcode == OC_PARAMETER) { ttp = opr->oprval.tref; opr = ttp->operand; continue; } *sopr++ = opr; if (sopr >= ARRAYTOP(saved_opr)) /* user-visible max args is MAX_ARGS - 3 */ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MAXARGCNT, 1, MAX_ARGS - 3); } opr++; } *sopr=0; jmp_offset = 0; call_4lcldo_variant = 0; if (oct & OCT_JUMP || ct->opcode == OC_LDADDR || ct->opcode == OC_FORLOOP) { if (ct->operand[0].oprval.tref->rtaddr == 0) /* forward reference */ { jmp_offset = LONG_JUMP_OFFSET; assert(cg_phase == CGP_APPROX_ADDR); } else jmp_offset = ct->operand[0].oprval.tref->rtaddr - ct->rtaddr; switch (ct->opcode) { case OC_CALL: case OC_FORLCLDO: case OC_CALLSP: /* Changes to emit_xfer, emit_base_offset, or emit_jmp may require changes here since we try to predict how big the call into the xfer_table and the following jump will be. There is also an assumption that both the word and long variants of the opcode will be followed by a jmp with 32 bit offset while the -BYTE variants will be followed by a BRB with an 8 bit offset. */ tsp = (short *)&ttt[ttt[tp]]; if (-128 <= tsp[CALL_4LCLDO_XFER] && 127 >= tsp[CALL_4LCLDO_XFER]) off = jmp_offset - XFER_BYTE_INST_SIZE; else off = jmp_offset - XFER_LONG_INST_SIZE; if (-128 <= (off - BRB_INST_SIZE) && 127 >= (off - BRB_INST_SIZE)) call_4lcldo_variant = BRB_INST_SIZE; /* used by emit_jmp */ else { call_4lcldo_variant = JMP_LONG_INST_SIZE; /* used by emit_jmp */ tsp = (short *)&ttt[ttt[tp + 1]]; if (-128 <= tsp[CALL_4LCLDO_XFER] && 127 >= tsp[CALL_4LCLDO_XFER]) off = jmp_offset - XFER_BYTE_INST_SIZE; else off = jmp_offset - XFER_LONG_INST_SIZE; if (-32768 > (off - JMP_LONG_INST_SIZE) && 32767 < (off - JMP_LONG_INST_SIZE)) tsp = (short *)&ttt[ttt[tp + 2]]; } break; case OC_JMP: case OC_JMPEQU: case OC_JMPGEQ: case OC_JMPGTR: case OC_JMPLEQ: case OC_JMPNEQ: case OC_JMPLSS: case OC_JMPTSET: case OC_JMPTCLR: case OC_LDADDR: case OC_FORLOOP: tsp = (short *)&ttt[ttt[tp]]; break; default: GTMASSERT; break; } } else if (oct & OCT_COERCE) { switch (oc_tab[ct->operand[0].oprval.tref->opcode].octype & (OCT_VALUE | OCT_BOOL)) { case OCT_MVAL: tp = ttt[tp]; break; case OCT_MINT: tp = ttt[tp + 3]; break; case OCT_BOOL: tp = ttt[tp + 4]; break; default: GTMASSERT; break; } tsp = (short *)&ttt[tp]; } else tsp = (short *)&ttt[tp]; for (; *tsp != VXT_END; ) { if (*tsp == VXT_IREPAB || *tsp == VXT_IREPL) { repl = tsp; repl += 2; repcnt = *repl++; assert(repcnt != 1); for (irep_index = repcnt, irep_opr = &ct->operand[1]; irep_index > 2; --irep_index) { assert (irep_opr->oprclass == TRIP_REF); irep_opr = &irep_opr->oprval.tref->operand[1]; } if (irep_opr->oprclass == TRIP_REF) { repl = tsp; do { tsp = repl; tsp = emit_vax_inst(tsp, &saved_opr[0], --sopr); } while (sopr > &saved_opr[repcnt]); } else { sopr = &saved_opr[repcnt]; tsp = repl; } } else { assert(*tsp > 0 && *tsp <= 511); tsp = emit_vax_inst(tsp, &saved_opr[0], sopr); }/* else */ }/* for */ } short *emit_vax_inst(short *inst, oprtype **fst_opr, oprtype **lst_opr) /* fst_opr and lst_opr are triple operands */ { short sav_in; bool oc_int; int4 cnt; oprtype *opr; triple *ct; code_idx = 0; force_32 = 0; switch (cg_phase) { case CGP_ADDR_OPT: case CGP_APPROX_ADDR: case CGP_MACHINE: switch ((sav_in = *inst++)) { case VXI_BEQL: case VXI_BGEQ: case VXI_BGTR: case VXI_BLEQ: case VXI_BLSS: case VXI_BNEQ: case VXI_BRB: case VXI_BRW: emit_jmp(sav_in, &inst); break; case VXI_BLBC: case VXI_BLBS: assert (*inst == VXT_REG); inst++; inst++; emit_xfer(4*xf_dt_get); code_buf[code_idx++] = I386_INS_CMP_eAX_Iv; *((int4 *)&code_buf[code_idx]) = 0; code_idx += SIZEOF(int4); if (sav_in == VXI_BLBC) emit_jmp(VXI_BEQL, &inst); else { assert (sav_in == VXI_BLBS); emit_jmp(VXI_BNEQ, &inst); } break; case VXI_BICB2: case VXI_BISB2: assert (*inst == VXT_LIT); inst++; assert (*inst == 1); inst++; assert (*inst == VXT_REG); inst++; inst++; if (sav_in == VXI_BICB2) emit_xfer(4*xf_dt_false); else { assert (sav_in == VXI_BISB2); emit_xfer(4*xf_dt_true); } break; case VXI_CALLS: oc_int = TRUE; if (*inst == VXT_LIT) { inst++; cnt = (int4) *inst++; } else { assert(*inst == VXT_VAL); inst++; opr = *(fst_opr + *inst); assert (opr->oprclass == TRIP_REF); ct = opr->oprval.tref; if (ct->destination.oprclass) { opr = &ct->destination; } if (opr->oprclass == TRIP_REF) { assert(ct->opcode == OC_ILIT); cnt = ct->operand[0].oprval.ilit; if (cnt >= -128 && cnt <= 127) { code_buf[code_idx++] = I386_INS_PUSH_Ib; code_buf[code_idx++] = cnt & 0xff; } else { code_buf[code_idx++] = I386_INS_PUSH_Iv; *((int4 *)&code_buf[code_idx]) = cnt; code_idx += SIZEOF(int4); } cnt++; inst++; } else { assert(opr->oprclass == TINT_REF); oc_int = FALSE; opr = *(fst_opr + *inst++); emit_trip(PUSH, opr, TRUE, 0); } } assert (*inst == VXT_XFER); inst++; emit_xfer(*inst++); if (oc_int) { if (cnt) { code_buf[code_idx++] = I386_INS_LEA_Gv_M; emit_base_offset(I386_REG_ESP, I386_REG_ESP, 4*cnt); } } else { emit_trip(LOAD, opr, TRUE, I386_REG_EDX); code_buf[code_idx++] = I386_INS_LEA_Gv_M; emit_base_offset(I386_REG_ESP, I386_REG_ESP, 4); } break; case VXI_CLRL: assert (*inst == VXT_VAL); inst++; emit_trip(CLEAR, *(fst_opr + *inst++), TRUE, 0); break; case VXI_CMPL: assert (*inst == VXT_VAL); inst++; emit_trip(LOAD, *(fst_opr + *inst++), TRUE, I386_REG_EDX); assert (*inst == VXT_VAL); inst++; emit_trip(COMPARE, *(fst_opr + *inst++), TRUE, I386_REG_EDX); break; case VXI_INCL: assert (*inst == VXT_VAL); inst++; emit_trip(INCREMENT, *(fst_opr + *inst++), TRUE, 0); break; case VXI_JMP: if (*inst == VXT_VAL) { inst++; emit_trip(JUMP, *(fst_opr + *inst++), FALSE, 0); } else { emit_jmp(sav_in, &inst); } break; case VXI_JSB: assert (*inst == VXT_XFER); inst++; emit_xfer(*inst++); break; case VXI_MOVAB: if (*inst == VXT_JMP) { inst += 2; emit_pcrel(LOAD_ADDRESS, I386_REG_EAX); assert (*inst == VXT_ADDR); inst++; emit_trip(STORE, *(fst_opr + *inst++), FALSE, I386_REG_EAX); } else if (*inst == VXT_ADDR || *inst == VXT_VAL) { bool addr; unsigned char reg; short save_inst; addr = (*inst == VXT_VAL); inst++; save_inst = *inst++; assert (*inst == VXT_REG); inst++; reg = ((*inst++ & 0x01) ? I386_REG_EDX : I386_REG_EAX); /* r0 and r1 are only ones used */ emit_trip(LOAD_ADDRESS, *(fst_opr + save_inst), addr, reg); } else GTMASSERT; break; case VXI_MOVC3: assert (*inst == VXT_LIT); inst += 2; assert(*inst == VXT_VAL); inst++; code_buf[code_idx++] = I386_INS_PUSH_eSI; code_buf[code_idx++] = I386_INS_PUSH_eDI; emit_trip(LOAD_ADDRESS, *(fst_opr + *inst++), TRUE, I386_REG_ECX); assert(*inst == VXT_VAL); inst++; emit_trip(LOAD_ADDRESS, *(fst_opr + *inst++), TRUE, I386_REG_EDI); code_buf[code_idx++] = I386_INS_MOV_Gv_Ev; modrm_byte.modrm.reg_opcode = I386_REG_ESI; modrm_byte.modrm.mod = I386_MOD32_REGISTER; modrm_byte.modrm.r_m = I386_REG_ECX; code_buf[code_idx++] = modrm_byte.byte; code_buf[code_idx++] = I386_INS_MOV_eCX; *((int4 *)&code_buf[code_idx]) = (int4)SIZEOF(mval); code_idx += SIZEOF(int4); code_buf[code_idx++] = I386_INS_REP_E_Prefix; code_buf[code_idx++] = I386_INS_MOVSB_Xb_Yb; code_buf[code_idx++] = I386_INS_POP_eDI; code_buf[code_idx++] = I386_INS_POP_eSI; break; case VXI_MOVL: if (*inst == VXT_REG) { inst++; if (*inst > 0x5f) /* OC_CURRHD */ /* any mode >= 6 (deferred), any register */ { inst++; assert (*inst == VXT_ADDR); inst++; emit_xfer(4*xf_get_msf); emit_op_base_offset(LOAD, I386_REG_EAX, 0, I386_REG_EAX); emit_trip(STORE, *(fst_opr + *inst++), FALSE, I386_REG_EAX); } else { bool addr; assert (*inst == 0x50); /* register mode: R0 */ inst++; if (*inst == VXT_VAL || *inst == VXT_ADDR) { addr = (*inst == VXT_VAL); inst++; emit_trip(STORE, *(fst_opr + *inst++), addr, I386_REG_EAX); } else if (*inst == VXT_REG) { unsigned char reg; inst++; if ((*inst & 0x0f) == 10) /* VAX $TEST */ { code_buf[code_idx++] = I386_INS_PUSH_eAX; emit_xfer(4*xf_dt_store); code_buf[code_idx++] = I386_INS_POP_eAX; } else { code_buf[code_idx++] = I386_INS_MOV_Ev_Gv; modrm_byte.modrm.reg_opcode = I386_REG_EAX; modrm_byte.modrm.mod = I386_MOD32_REGISTER; modrm_byte.modrm.r_m = i386_reg(*inst); code_buf[code_idx++] = modrm_byte.byte; } inst++; } else GTMASSERT; } } else if (*inst == VXT_VAL) { inst++; emit_trip(LOAD, *(fst_opr + *inst++), TRUE, I386_REG_EDX); assert (*inst == VXT_REG); inst++; assert (*inst == 0x51); /* register mode: R1 */ inst++; } else GTMASSERT; break; case VXT_IREPAB: assert (*inst == VXT_VAL); inst += 2; emit_trip(PUSH_ADDRESS, *lst_opr, TRUE, 0); break; case VXI_PUSHAB: if (*inst == VXT_JMP) { inst += 2; emit_pcrel(PUSH_ADDRESS, 0); } else if (*inst == VXT_VAL) { inst++; emit_trip(PUSH_ADDRESS, *(fst_opr + *inst++), TRUE, 0); } else GTMASSERT; break; case VXT_IREPL: assert (*inst == VXT_VAL); inst += 2; emit_trip(PUSH, *lst_opr, TRUE, 0); break; case VXI_PUSHL: if (*inst == VXT_LIT) { int4 lit; inst++; lit = *inst++; if (lit >= -128 && lit <= 127) { code_buf[code_idx++] = I386_INS_PUSH_Ib; code_buf[code_idx++] = lit & 0xff; } else { code_buf[code_idx++] = I386_INS_PUSH_Iv; *((int4 *)&code_buf[code_idx]) = lit; code_idx += SIZEOF(int4); } } else if (*inst == VXT_ADDR) { inst++; emit_trip(PUSH, *(fst_opr + *inst++), FALSE, 0); } else if (*inst == VXT_VAL) { inst++; emit_trip(PUSH, *(fst_opr + *inst++), TRUE, 0); } else GTMASSERT; break; case VXI_TSTL: if (*inst == VXT_VAL) { inst++; emit_trip(TEST, *(fst_opr + *inst++), TRUE, 0); } else if (VXT_REG == *inst) { inst++; code_buf[code_idx++] = I386_INS_CMP_eAX_Iv; assert(I386_REG_EAX == i386_reg(*inst)); /* VAX R0 */ inst++; *((int4 *)&code_buf[code_idx]) = 0; /* 32 bit immediate 0 */ code_idx += SIZEOF(int4); } else GTMASSERT; break; default: GTMASSERT; } break; default: GTMASSERT; break; } assert (code_idx < BUFFERED_CODE_SIZE); if (cg_phase == CGP_MACHINE) { generated_code_size += code_idx; emit_immed ((char *)&code_buf[0], SIZEOF(unsigned char) * code_idx); } else if (cg_phase != CGP_ASSEMBLY) { if (cg_phase == CGP_APPROX_ADDR) { calculated_code_size += code_idx; } curr_addr += SIZEOF(unsigned char) * code_idx; } code_reference += SIZEOF(unsigned char) * code_idx; jmp_offset -= SIZEOF(unsigned char) * code_idx; return inst; } /* Changes here or emit_xfer may require changes in trip_gen case for OC_CALL[SP] and FORLCLDO */ void emit_jmp(short vax_in, short **instp) { assert (jmp_offset != 0); jmp_offset -= code_idx * SIZEOF(code_buf[0]); /* size of this particular instruction */ assert (**instp == VXT_JMP); *instp += 1; assert (**instp == 1); *instp += 1; if (jmp_offset == 0) { code_buf[code_idx++] = I386_INS_NOP__; } else if ((jmp_offset - 2) >= -128 && (jmp_offset - 2) <= 127 && JMP_LONG_INST_SIZE != call_4lcldo_variant) { jmp_offset -= 2; switch (vax_in) { case VXI_BEQL: code_buf[code_idx++] = I386_INS_JZ_Jb; break; case VXI_BGEQ: code_buf[code_idx++] = I386_INS_JNL_Jb; break; case VXI_BGTR: code_buf[code_idx++] = I386_INS_JNLE_Jb; break; case VXI_BLEQ: code_buf[code_idx++] = I386_INS_JLE_Jb; break; case VXI_BLSS: code_buf[code_idx++] = I386_INS_JL_Jb; break; case VXI_BNEQ: code_buf[code_idx++] = I386_INS_JNZ_Jb; break; case VXI_BRB: case VXI_BRW: case VXI_JMP: assert(0 == call_4lcldo_variant || BRB_INST_SIZE == call_4lcldo_variant); code_buf[code_idx++] = I386_INS_JMP_Jb; break; default: GTMASSERT; break; } code_buf[code_idx++] = jmp_offset & 0xff; } else { if (vax_in == VXI_BRB || vax_in == VXI_BRW || vax_in == VXI_JMP) { assert(0 == call_4lcldo_variant || JMP_LONG_INST_SIZE == call_4lcldo_variant); jmp_offset -= SIZEOF(int4) + 1; code_buf[code_idx++] = I386_INS_JMP_Jv; } else { jmp_offset -= SIZEOF(int4) + 2; code_buf[code_idx++] = I386_INS_Two_Byte_Escape_Prefix; switch (vax_in) { case VXI_BEQL: code_buf[code_idx++] = I386_INS_JZ_Jv; break; case VXI_BGEQ: code_buf[code_idx++] = I386_INS_JNL_Jv; break; case VXI_BGTR: code_buf[code_idx++] = I386_INS_JNLE_Jv; break; case VXI_BLEQ: code_buf[code_idx++] = I386_INS_JLE_Jv; break; case VXI_BLSS: code_buf[code_idx++] = I386_INS_JL_Jv; break; case VXI_BNEQ: code_buf[code_idx++] = I386_INS_JNZ_Jv; break; default: GTMASSERT; break; } } *((int4 *)&code_buf[code_idx]) = jmp_offset; code_idx += SIZEOF(int4); } } void emit_pcrel(generic_op op, unsigned char use_reg) { code_buf[code_idx++] = I386_INS_CALL_Jv; *((int4 *)&code_buf[code_idx]) = 0; code_idx += SIZEOF(int4); jmp_offset -= code_idx; code_buf[code_idx++] = I386_INS_POP_eAX; emit_op_base_offset(op, I386_REG_EAX, jmp_offset, use_reg); } GBLREF boolean_t run_time; GBLREF int4 sa_temps_offset[]; GBLREF int4 sa_temps[]; LITREF int4 sa_class_sizes[]; void emit_trip(generic_op op, oprtype *opr, bool val_output, unsigned char use_reg) { unsigned char base_reg, temp_reg; int4 offset, literal; triple *ct; if (opr->oprclass == TRIP_REF) { ct = opr->oprval.tref; if (ct->destination.oprclass) { opr = &ct->destination; } /* else lit or error */ } switch (cg_phase) { case CGP_ADDR_OPT: case CGP_APPROX_ADDR: switch (opr->oprclass) { case TRIP_REF: assert(ct->destination.oprclass == 0); assert(val_output); switch (ct->opcode) { case OC_LIT: if (run_time) { int4 pc_value_idx; switch (op) { case LOAD_ADDRESS: temp_reg = use_reg; break; case PUSH: case PUSH_ADDRESS: temp_reg = I386_REG_ECX; break; default: rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } pc_value_idx = code_idx + 5; code_idx += 1 + SIZEOF(int4) + 1; emit_addr(0, (int4)ct->operand[0].oprval.mlit->rt_addr, &offset); offset -= pc_value_idx; force_32 = 1; emit_op_base_offset(op, temp_reg, offset, temp_reg); force_32 = 0; } else { emit_op_alit(op, use_reg); code_idx += SIZEOF(int4); } if (cg_phase == CGP_APPROX_ADDR) txtrel_cnt++; break; case OC_CDLIT: if (cg_phase == CGP_APPROX_ADDR) define_symbol(GTM_LITERALS, ct->operand[0].oprval.cdlt, 0); emit_op_alit(op, use_reg); code_idx += SIZEOF(int4); break; case OC_ILIT: literal = ct->operand[0].oprval.ilit; switch(op) { case COMPARE: /* 1byte(opcode) + 1byte(ModR/M) + 4byte(literal) */ code_idx += 2 + SIZEOF(int4); break; case LOAD: code_idx += 1 + SIZEOF(int4); break; case PUSH: if (literal >= -128 && literal <= 127) code_idx += 2; else code_idx += 1 + SIZEOF(int4); break; default: rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } break; default: GTMASSERT; break; } break; case TINT_REF: case TVAL_REF: assert(val_output); offset = sa_temps_offset[opr->oprclass]; offset -= (sa_temps[opr->oprclass] - opr->oprval.temp) * sa_class_sizes[opr->oprclass]; if (offset < 0 && offset > 65535) GTMASSERT; emit_op_base_offset(op, I386_REG_EDI, offset, use_reg); break; case TCAD_REF: case TVAD_REF: case TVAR_REF: offset = sa_temps_offset[opr->oprclass]; offset -= (sa_temps[opr->oprclass] - opr->oprval.temp) * sa_class_sizes[opr->oprclass]; if (offset < 0 && offset > 65535) GTMASSERT; if (opr->oprclass == TVAR_REF) base_reg = I386_REG_ESI; else base_reg = I386_REG_EDI; switch (op) { case JUMP: if (val_output) { code_idx++; emit_base_offset(I386_REG_EAX, base_reg, offset); } code_idx++; if (val_output) emit_base_offset(I386_INS_JMP_Ev, I386_REG_EAX, 0); else emit_base_offset(I386_INS_JMP_Ev, base_reg, offset); break; case LOAD_ADDRESS: code_idx++; emit_base_offset(use_reg, base_reg, offset); if (opr->oprclass == TVAR_REF) { code_idx++; emit_base_offset(use_reg, use_reg, offsetof(ht_ent_mname, value)); } break; case PUSH: if (!val_output) { code_idx++; emit_base_offset(I386_INS_PUSH_Ev, base_reg, offset); } else { code_idx++; emit_base_offset(I386_REG_ECX, base_reg, offset); code_idx++; emit_base_offset(I386_INS_PUSH_Ev, I386_REG_ECX, 0); } break; case PUSH_ADDRESS: if (val_output) { if (opr->oprclass == TVAR_REF) { code_idx++; emit_base_offset(use_reg, base_reg, offset); code_idx++; emit_base_offset(I386_INS_PUSH_Ev, use_reg, offsetof(ht_ent_mname, value)); } else { code_idx++; emit_base_offset(I386_INS_PUSH_Ev, base_reg, offset); } } else { code_idx++; emit_base_offset(I386_REG_ECX, base_reg, offset); code_idx++; } break; case STORE: if (val_output) { if (use_reg == I386_REG_EAX) temp_reg = I386_REG_EDX; else temp_reg = I386_REG_EAX; code_idx++; emit_base_offset(temp_reg, base_reg, offset); } code_idx++; if (val_output) emit_base_offset(use_reg, temp_reg, 0); else emit_base_offset(use_reg, base_reg, offset); break; default: rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } break; } break; case CGP_MACHINE: switch (opr->oprclass) { case TRIP_REF: assert(ct->destination.oprclass == 0); assert(val_output); switch (ct->opcode) { case OC_LIT: assert(ct->operand[0].oprclass == MLIT_REF); if (run_time) { int4 pc_value_idx; switch(op) { case LOAD_ADDRESS: temp_reg = use_reg; break; case PUSH: case PUSH_ADDRESS: temp_reg = I386_REG_ECX; break; default: rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } code_buf[code_idx++] = I386_INS_CALL_Jv; *((int4 *)&code_buf[code_idx]) = 0; code_idx += SIZEOF(int4); pc_value_idx = code_idx; code_buf[code_idx++] = I386_INS_POP_eAX + temp_reg; emit_addr(0, (int4)ct->operand[0].oprval.mlit->rt_addr, &offset); offset -= pc_value_idx; force_32 = 1; emit_op_base_offset(op, temp_reg, offset, temp_reg); force_32 = 0; } else { emit_op_alit(op, use_reg); emit_addr(code_reference + (code_idx * SIZEOF(unsigned char)), (int4)ct->operand[0].oprval.mlit->rt_addr, (int4 *)&code_buf[code_idx]); code_idx += SIZEOF(int4); } break; case OC_CDLIT: emit_op_alit(op, use_reg); emit_reference(code_reference + (code_idx * SIZEOF(unsigned char)), ct->operand[0].oprval.cdlt, (uint4 *)&code_buf[code_idx]); code_idx += SIZEOF(int4); break; case OC_ILIT: literal = ct->operand[0].oprval.ilit; switch (op) { case COMPARE: /* cmpl $literal,use_reg - 1byte(opcode) + 1byte(ModR/M) + 4byte(literal) */ code_buf[code_idx++] = I386_INS_Grp1_Ev_Iv_Prefix; modrm_byte.modrm.reg_opcode = I386_INS_CMP__; modrm_byte.modrm.mod = I386_MOD32_REGISTER; modrm_byte.modrm.r_m = use_reg; code_buf[code_idx++] = modrm_byte.byte; *((int4 *)&code_buf[code_idx]) = literal; code_idx += SIZEOF(int4); break; case LOAD: code_buf[code_idx++] = I386_INS_MOV_eAX + use_reg; *((int4 *)&code_buf[code_idx]) = literal; code_idx += SIZEOF(int4); break; case PUSH: if (literal >= -128 && literal <= 127) { code_buf[code_idx++] = I386_INS_PUSH_Ib; code_buf[code_idx++] = literal & 0xff; } else { code_buf[code_idx++] = I386_INS_PUSH_Iv; *((int4 *)&code_buf[code_idx]) = literal; code_idx += SIZEOF(int4); } break; default: rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } break; default: GTMASSERT; break; } break; case TINT_REF: case TVAL_REF: assert(val_output); offset = sa_temps_offset[opr->oprclass]; offset -= (sa_temps[opr->oprclass] - opr->oprval.temp) * sa_class_sizes[opr->oprclass]; if (offset < 0 && offset > 65535) GTMASSERT; emit_op_base_offset(op, I386_REG_EDI, offset, use_reg); break; case TCAD_REF: case TVAD_REF: case TVAR_REF: offset = sa_temps_offset[opr->oprclass]; offset -= (sa_temps[opr->oprclass] - opr->oprval.temp) * sa_class_sizes[opr->oprclass]; if (offset < 0 && offset > 65535) GTMASSERT; if (opr->oprclass == TVAR_REF) base_reg = I386_REG_ESI; else base_reg = I386_REG_EDI; switch (op) { case JUMP: assert (use_reg == 0); if (val_output) { code_buf[code_idx++] = I386_INS_MOV_Gv_Ev; emit_base_offset(I386_REG_EAX, base_reg, offset); } code_buf[code_idx++] = I386_INS_Grp5_Prefix; if (val_output) emit_base_offset(I386_INS_JMP_Ev, I386_REG_EAX, 0); else emit_base_offset(I386_INS_JMP_Ev, base_reg, offset); break; case LOAD_ADDRESS: if (val_output) code_buf[code_idx++] = I386_INS_MOV_Gv_Ev; else code_buf[code_idx++] = I386_INS_LEA_Gv_M; emit_base_offset(use_reg, base_reg, offset); if (opr->oprclass == TVAR_REF) { code_buf[code_idx++] = I386_INS_MOV_Gv_Ev; emit_base_offset(use_reg, use_reg, offsetof(ht_ent_mname, value)); } break; case PUSH: if (val_output) { code_buf[code_idx++] = I386_INS_MOV_Gv_Ev; emit_base_offset(I386_REG_ECX, base_reg, offset); code_buf[code_idx++] = I386_INS_Grp5_Prefix; emit_base_offset(I386_INS_PUSH_Ev, I386_REG_ECX, 0); } else { code_buf[code_idx++] = I386_INS_Grp5_Prefix; emit_base_offset(I386_INS_PUSH_Ev, base_reg, offset); } break; case PUSH_ADDRESS: if (val_output) { if (opr->oprclass == TVAR_REF) { code_buf[code_idx++] = I386_INS_MOV_Gv_Ev; emit_base_offset(use_reg, base_reg, offset); code_buf[code_idx++] = I386_INS_Grp5_Prefix; emit_base_offset(I386_INS_PUSH_Ev, use_reg, offsetof(ht_ent_mname, value)); } else { code_buf[code_idx++] = I386_INS_Grp5_Prefix; emit_base_offset(I386_INS_PUSH_Ev, base_reg, offset); } } else { code_buf[code_idx++] = I386_INS_LEA_Gv_M; emit_base_offset(I386_REG_ECX, base_reg, offset); code_buf[code_idx++] = I386_INS_PUSH_eCX; } break; case STORE: if (val_output) { if (use_reg == I386_REG_EAX) temp_reg = I386_REG_EDX; else temp_reg = I386_REG_EAX; assert(temp_reg != use_reg); code_buf[code_idx++] = I386_INS_MOV_Gv_Ev; emit_base_offset(temp_reg, base_reg, offset); } code_buf[code_idx++] = I386_INS_MOV_Ev_Gv; if (val_output) emit_base_offset(use_reg, temp_reg, 0); else emit_base_offset(use_reg, base_reg, offset); break; default: rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } break; default: GTMASSERT; break; } break; default: GTMASSERT; break; } } /* Changes here, emit_base_offset, or emit_jmp may require changes in trip_gen case for OC_CALL[SP] and FORLCLDO */ void emit_xfer(short xfer) { code_buf[code_idx++] = I386_INS_Grp5_Prefix; emit_base_offset(I386_INS_CALL_Ev, I386_REG_EBX, (int4)xfer); } void emit_op_base_offset(generic_op op, short base_reg, int offset, short use_reg) { switch (op) { case CLEAR: code_buf[code_idx++] = I386_INS_MOV_Ev_Iv; emit_base_offset(0, base_reg, offset); *((int4 *)&code_buf[code_idx]) = 0; code_idx += SIZEOF(int4); break; case COMPARE: code_buf[code_idx++] = I386_INS_CMP_Gv_Ev; emit_base_offset(use_reg, base_reg, offset); break; case INCREMENT: code_buf[code_idx++] = I386_INS_Grp5_Prefix; emit_base_offset(I386_INS_INC_Ev, base_reg, offset); break; case LOAD: code_buf[code_idx++] = I386_INS_MOV_Gv_Ev; emit_base_offset(use_reg, base_reg, offset); break; case LOAD_ADDRESS: code_buf[code_idx++] = I386_INS_LEA_Gv_M; emit_base_offset(use_reg, base_reg, offset); break; case PUSH: code_buf[code_idx++] = I386_INS_Grp5_Prefix; emit_base_offset(I386_INS_PUSH_Ev, base_reg, offset); break; case PUSH_ADDRESS: code_buf[code_idx++] = I386_INS_LEA_Gv_M; emit_base_offset(use_reg, base_reg, offset); code_buf[code_idx++] = I386_INS_PUSH_eAX + use_reg; break; case STORE: code_buf[code_idx++] = I386_INS_MOV_Ev_Gv; emit_base_offset(use_reg, base_reg, offset); break; case TEST: code_buf[code_idx++] = I386_INS_Grp1_Ev_Ib_Prefix; emit_base_offset(I386_INS_CMP__, base_reg, offset); code_buf[code_idx++] = 0; break; default: rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } } /* Changes here, emit_base_offset, or emit_jmp may require changes in trip_gen case for OC_CALL[SP] and FORLCLDO */ void emit_base_offset (short reg_opcode, short base_reg, int4 offset) { modrm_byte.modrm.reg_opcode = reg_opcode; if (offset == 0) modrm_byte.modrm.mod = I386_MOD32_BASE; else if ((offset >= -128 && offset <= 127) && force_32 == 0) modrm_byte.modrm.mod = I386_MOD32_BASE_DISP_8; else modrm_byte.modrm.mod = I386_MOD32_BASE_DISP_32; if (base_reg == I386_REG_ESP || (base_reg == I386_REG_EBP && offset == 0)) { modrm_byte.modrm.r_m = I386_REG_SIB_FOLLOWS; code_buf[code_idx++] = modrm_byte.byte; sib_byte.sib.base = base_reg; sib_byte.sib.ss = I386_SS_TIMES_1; sib_byte.sib.index = I386_REG_NO_INDEX; code_buf[code_idx++] = sib_byte.byte; } else { modrm_byte.modrm.r_m = base_reg; code_buf[code_idx++] = modrm_byte.byte; } if (offset == 0) ; else if ((offset >= -128 && offset <= 127) && force_32 == 0) code_buf[code_idx++] = offset & 0xff; else { *((int4 *)&code_buf[code_idx]) = offset; code_idx += SIZEOF(int4); } } void emit_op_alit (generic_op op, unsigned char use_reg) { switch (op) { case LOAD_ADDRESS: code_buf[code_idx++] = I386_INS_MOV_eAX + use_reg; break; case PUSH: code_buf[code_idx++] = I386_INS_Grp5_Prefix; modrm_byte.modrm.reg_opcode = I386_INS_PUSH_Ev; modrm_byte.modrm.mod = I386_MOD32_BASE; modrm_byte.modrm.r_m = I386_REG_disp32_NO_BASE; code_buf[code_idx++] = modrm_byte.byte; break; case PUSH_ADDRESS: code_buf[code_idx++] = I386_INS_PUSH_Iv; break; default: rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP); break; } } unsigned char i386_reg(unsigned char vax_reg) { unsigned char reg; switch (vax_reg & 0xf) /* mask out VAX register mode field */ { case 0: reg = I386_REG_EAX; break; case 1: reg = I386_REG_EDX; break; case 8: reg = I386_REG_ESI; break; case 9: reg = I386_REG_EDI; break; case 11: reg = I386_REG_EBX; break; default: GTMASSERT; break; } return reg; } fis-gtm-V6.0-003/sr_i386/emit_code.h0000644000032200000250000000130412201176146015636 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef EMIT_CODE_INCLUDED #define EMIT_CODE_INCLUDED void trip_gen(triple *ct); short *emit_vax_inst(short *inst, oprtype **fst_opr, oprtype **lst_opr); void emit_xfer(short xfer); void emit_base_offset (short reg_opcode, short base_reg, int4 offset); #endif fis-gtm-V6.0-003/sr_i386/error.si0000644000032200000250000000312112201176146015222 0ustar librarygtc################################################################# # # # Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# .sbttl error.si # PAGE + #----------------------------------------------- # Mumps error condition handler macros #----------------------------------------------- .ifdef cygwin # will need another 8 to save sigmasks chnd_size = 220 .else chnd_size = 168 .endif chnd_save_active = 0 chnd_ch_active = 4 chnd_ch = 8 chnd_jmp = 12 .data .extern ctxt .extern active_ch .text .ifdef cygwin # on cygwin, sigsetjmp is a macro which calls sigprocmask then setjmp .extern _setjmp .else # setjmp is really __sigsetjmp(env,0) .extern __sigsetjmp .extern gtm_asm_establish .endif .sbttl error.si ESTABLISH .macro ESTABLISH x, label call gtm_asm_establish # Bulk of ESTABLISH macro movl ctxt,%eax movl $\x,chnd_ch(%eax) # ctxt->ch = x addl $chnd_jmp,%eax # setjmp(ctxt->jmp) .ifndef cygwin pushl $0 .endif pushl %eax .ifdef cygwin call _setjmp addl $4,%esp .else call __sigsetjmp addl $8,%esp .endif incl %eax jne \label REVERT jmp return \label: .endm .sbttl error.si REVERT .macro REVERT movl ctxt,%eax # active_ch = ctxt->save_active_c movl chnd_save_active(%eax),%eax movl %eax,active_ch subl $chnd_size,ctxt # ctxt-- .endm fis-gtm-V6.0-003/sr_i386/find_line_call.c0000644000032200000250000000522412201176175016632 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "xfer_enum.h" #include "i386.h" #include /* Needed by zbreak.h */ #include "zbreak.h" zb_code *find_line_call(void *addr) { unsigned char *call_addr; union { ModR_M modrm; unsigned char byte; } modrm_byte; call_addr = (unsigned char *)addr; modrm_byte.byte = *(call_addr + 1); if ((I386_INS_Grp5_Prefix == *call_addr) && (I386_INS_CALL_Ev == modrm_byte.modrm.reg_opcode)) { call_addr++; assert(I386_REG_EBX == modrm_byte.modrm.r_m); call_addr++; if (I386_MOD32_BASE_DISP_8 == modrm_byte.modrm.mod) { if ((xf_linestart * SIZEOF(int4) == *call_addr) || (xf_zbstart * SIZEOF(int4) == *call_addr)) return (zb_code *)call_addr; call_addr++; } else { assert (I386_MOD32_BASE_DISP_32 == modrm_byte.modrm.mod); return (zb_code *)addr; } } modrm_byte.byte = *(call_addr + 1); if ((I386_INS_PUSH_Ib == *call_addr) || (I386_INS_PUSH_Iv == *call_addr)) { while ((I386_INS_PUSH_Ib == *call_addr) || (I386_INS_PUSH_Iv == *call_addr)) { if (I386_INS_PUSH_Ib == *call_addr) call_addr += 1 + SIZEOF(unsigned char); else { assert(I386_INS_PUSH_Iv == *call_addr); call_addr += 1 + SIZEOF(int4); } } modrm_byte.byte = *(call_addr + 1); if ((I386_INS_Grp5_Prefix != *call_addr++) || (I386_INS_CALL_Ev != modrm_byte.modrm.reg_opcode)) return (zb_code *)addr; assert((I386_MOD32_BASE_DISP_8 == modrm_byte.modrm.mod) || (I386_MOD32_BASE_DISP_32 == modrm_byte.modrm.mod)); assert(I386_REG_EBX == modrm_byte.modrm.r_m); call_addr++; if (I386_MOD32_BASE_DISP_8 == modrm_byte.modrm.mod) { if ((xf_linefetch * SIZEOF(int4) != *call_addr) && (xf_zbfetch * SIZEOF(int4) != *call_addr)) return (zb_code *)addr; } } else if ((I386_INS_Grp5_Prefix == *call_addr) && (I386_INS_CALL_Ev != modrm_byte.modrm.reg_opcode)) { call_addr++; assert((I386_MOD32_BASE_DISP_8 == modrm_byte.modrm.mod) || (I386_MOD32_BASE_DISP_32 == modrm_byte.modrm.mod)); assert(I386_REG_EBX == modrm_byte.modrm.r_m); call_addr++; if (I386_MOD32_BASE_DISP_8 == modrm_byte.modrm.mod) { if ((xf_linestart * SIZEOF(int4) != *call_addr) && (xf_zbstart * SIZEOF(int4) != *call_addr)) return (zb_code *)addr; } } return (zb_code *)call_addr; } fis-gtm-V6.0-003/sr_i386/follow.s0000644000032200000250000000130512201176146015224 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title follow.s .sbttl follow .include "linkage.si" # .386 # .MODEL FLAT, C .text .extern op_follow # PUBLIC follow ENTRY follow movl 4(%esp),%eax movl 8(%esp),%edx call op_follow jle l1 movl $1,%eax ret l1: movl $0,%eax ret # follow ENDP # END fis-gtm-V6.0-003/sr_i386/g_msf.si0000644000032200000250000000376512201176146015202 0ustar librarygtc################################################################# # # # Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# .sbttl g_msf.si # PAGE + #----------------------------------------------- # Mumps stack frame manipulation macros # for the GNU gas i386 assembler version #----------------------------------------------- msf_rvector_off = 0 msf_l_symtab_off = 4 msf_mpc_off = 8 msf_ctxt_off = 12 msf_temps_ptr_off = 16 msf_vartab_ptr_off = 20 msf_vartab_len_off = 24 msf_temp_mvals_off = 26 msf_old_frame_off = 28 msf_typ_off = 32 msf_flags_off = 34 msf_for_ctrl_stack = 36 msf_frame_size = 44 SFT_COUNT = 0x01 SFT_DM = 0x02 SFT_REP_OP = 0x04 SFT_ZBRK_ACT = 0x08 SFT_DEV_ACT = 0x10 SFT_ZTRAP = 0x20 SFT_ZSTEP_ACT = 0x80 SFT_ZINTR = 0x100 SFF_INDCE = 0x01 SFF_ZTRAP_ERR = 0x02 SFF_DEV_ACT_ERR = 0x04 SFF_CI = 0x08 SFF_ETRAP_ERR = 0x10 .sbttl g_msf.si putframe .macro putframe movl frame_pointer,%edx movl %edi,msf_temps_ptr_off(%edx) movl %esi,msf_l_symtab_off(%edx) movl (%esp),%eax movl %eax,msf_mpc_off(%edx) .endm .extern error_return .sbttl g_msf.si getframe .macro getframe movl frame_pointer,%edi movb msf_flags_off(%edi),%dl andb $SFF_ETRAP_ERR,%dl jz lab1\@ call error_return lab1\@: movl frame_pointer, %edx movl msf_temps_ptr_off(%edx),%edi movl msf_l_symtab_off(%edx),%esi pushl msf_mpc_off(%edx) .endm .sbttl g_msf.si mrt_jsb = 0 mrt_src_len = 12 mrt_src_addr = 16 mrt_rtn_len = 24 mrt_rtn_addr = 28 mrt_var_ptr = 32 mrt_var_len = 36 mrt_lab_ptr = 40 mrt_lab_len = 44 mrt_lnr_ptr = 48 mrt_lnr_len = 52 mrt_ptxt_ptr = 56 mrt_checksum = 60 mrt_compiler_qlf = 64 mrt_oldr_ptr = 68 mrt_curr_ptr = 72 mrt_tmp_mv = 76 mrt_tmp_sz = 78 fis-gtm-V6.0-003/sr_i386/gdeerrors_ctl.c0000666000032200000250000001365212201176214016550 0ustar librarygtc/**************************************************************** * * * Copyright 2001,2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "error.h" LITDEF err_msg gdeerrors[] = { "BLKSIZ512", "Block size !AD rounds to !AD", 4, "EXECOM", "Executing command file !AD", 2, "FILENOTFND", "File !AD not found", 2, "GDCREATE", "Creating Global Directory file !/ !AD", 2, "GDECHECK", "Internal GDE consistency check", 0, "GDUNKNFMT", "!AD !/ is not formatted as a Global Directory", 2, "GDUPDATE", "Updating Global Directory file !/ !AD", 2, "GDUSEDEFS", "Using defaults for Global Directory !/ !AD", 2, "ILLCHAR", "!AD is not a legal character in this context", 2, "INPINTEG", "Input integrity error -- aborting load", 0, "KEYTOOBIG", "But record size !AD can only support key size !AD", 4, "KEYSIZIS", "Key size is !AD", 2, "KEYWRDAMB", "!AD is ambiguous for !AD", 4, "KEYWRDBAD", "!AD is not a valid !AD", 4, "LOADGD", "Loading Global Directory file !/ !AD", 2, "LOGOFF", "No longer logging to file !AD", 2, "LOGON", "Logging to file !AD", 2, "LVSTARALON", "The * name cannot be deleted or renamed", 0, "MAPBAD", "!AD !AD for !AD !AD does not exist", 8, "MAPDUP", "!AD !AD and !AD both map to !AD !AD", 10, "NAMSTARTBAD", "!AD must start with '%' or an alphabetic character", 2, "NOACTION", "Not updating Global Directory !AD", 2, "RPAREN", "List must end with right parenthesis or continue with comma", 0, "NOEXIT", "Cannot exit because of verification failure", 0, "NOLOG", "Logging is currently disabled!/ Log file is !AD.", 2, "NOVALUE", "Qualifier !AD does not take a value", 2, "NONEGATE", "Qualifier !AD cannot be negated", 2, "OBJDUP", "!AD !AD already exists", 4, "OBJNOTADD", "Not adding !AD !AD", 4, "OBJNOTCHG", "Not changing !AD !AD", 4, "OBJNOTFND", "!AD !AD does not exist", 4, "OBJREQD", "!AD required", 2, "PREFIXBAD", "!AD must start with an alphabetic character to be a !AD", 4, "QUALBAD", "!AD is not a valid qualifier", 2, "QUALDUP", "!AD qualifier appears more than once in the list", 2, "QUALREQD", "!AD required", 2, "RECTOOBIG", "Block size !AD and !AD reserved bytes limit record size to !AD", 6, "RECSIZIS", "Record size is !AD", 2, "REGIS", "in region !AD", 2, "SEGIS", "in !AD segment !AD", 4, "VALTOOBIG", "!AD is larger than the maximum of !AD for a !AD", 6, "VALTOOLONG", "!AD exceeds the maximum length of !AD for a !AD", 6, "VALTOOSMALL", "!AD is less than the minimum of !AD for a !AD", 6, "VALUEBAD", "!AD is not a valid !AD", 4, "VALUEREQD", "Qualifier !AD requires a value", 2, "VERIFY", "Verification !AD", 2, "BUFSIZIS", "Journal Buffer size is !AD", 2, "BUFTOOSMALL", "But block size !AD requires buffer size !AD", 4, "MMNOBEFORIMG", "MM segments do not support before image jounaling", 0, "NOJNL", "!AD segments do not support journaling", 2, "GDREADERR", "Error reading Global Directory: !AD", 2, "GDNOTSET", "Global Directory not changed because the current GD cannot be written", 0, "INVGBLDIR", "Invalid Global Directory spec: !AD.!/Continuing with !AD", 4, "WRITEERROR", "Cannot exit because of write failure. Reason for failure: !AD", 2, "NONASCII", "!AD is illegal for a !AD as it contains non-ASCII characters", 4, "CRYPTNOMM", "!AD is an encrypted database. Cannot support MM access method.", 2, "JNLALLOCGROW", "Increased Journal ALLOCATION from [!AD blocks] to [!AD blocks] to match AUTOSWITCHLIMIT for !AD !AD", 8, "KEYFORBLK", "But block size !AD can only support key size !AD", 4, }; LITDEF int GDE_BLKSIZ512 = 150503435; LITDEF int GDE_EXECOM = 150503443; LITDEF int GDE_FILENOTFND = 150503450; LITDEF int GDE_GDCREATE = 150503459; LITDEF int GDE_GDECHECK = 150503467; LITDEF int GDE_GDUNKNFMT = 150503475; LITDEF int GDE_GDUPDATE = 150503483; LITDEF int GDE_GDUSEDEFS = 150503491; LITDEF int GDE_ILLCHAR = 150503498; LITDEF int GDE_INPINTEG = 150503508; LITDEF int GDE_KEYTOOBIG = 150503515; LITDEF int GDE_KEYSIZIS = 150503523; LITDEF int GDE_KEYWRDAMB = 150503530; LITDEF int GDE_KEYWRDBAD = 150503538; LITDEF int GDE_LOADGD = 150503547; LITDEF int GDE_LOGOFF = 150503555; LITDEF int GDE_LOGON = 150503563; LITDEF int GDE_LVSTARALON = 150503570; LITDEF int GDE_MAPBAD = 150503579; LITDEF int GDE_MAPDUP = 150503587; LITDEF int GDE_NAMSTARTBAD = 150503594; LITDEF int GDE_NOACTION = 150503603; LITDEF int GDE_RPAREN = 150503610; LITDEF int GDE_NOEXIT = 150503619; LITDEF int GDE_NOLOG = 150503627; LITDEF int GDE_NOVALUE = 150503634; LITDEF int GDE_NONEGATE = 150503642; LITDEF int GDE_OBJDUP = 150503650; LITDEF int GDE_OBJNOTADD = 150503658; LITDEF int GDE_OBJNOTCHG = 150503666; LITDEF int GDE_OBJNOTFND = 150503674; LITDEF int GDE_OBJREQD = 150503682; LITDEF int GDE_PREFIXBAD = 150503690; LITDEF int GDE_QUALBAD = 150503698; LITDEF int GDE_QUALDUP = 150503706; LITDEF int GDE_QUALREQD = 150503714; LITDEF int GDE_RECTOOBIG = 150503723; LITDEF int GDE_RECSIZIS = 150503731; LITDEF int GDE_REGIS = 150503739; LITDEF int GDE_SEGIS = 150503747; LITDEF int GDE_VALTOOBIG = 150503755; LITDEF int GDE_VALTOOLONG = 150503762; LITDEF int GDE_VALTOOSMALL = 150503771; LITDEF int GDE_VALUEBAD = 150503778; LITDEF int GDE_VALUEREQD = 150503786; LITDEF int GDE_VERIFY = 150503795; LITDEF int GDE_BUFSIZIS = 150503803; LITDEF int GDE_BUFTOOSMALL = 150503811; LITDEF int GDE_MMNOBEFORIMG = 150503819; LITDEF int GDE_NOJNL = 150503827; LITDEF int GDE_GDREADERR = 150503835; LITDEF int GDE_GDNOTSET = 150503843; LITDEF int GDE_INVGBLDIR = 150503851; LITDEF int GDE_WRITEERROR = 150503859; LITDEF int GDE_NONASCII = 150503866; LITDEF int GDE_CRYPTNOMM = 150503874; LITDEF int GDE_JNLALLOCGROW = 150503883; LITDEF int GDE_KEYFORBLK = 150503891; GBLDEF err_ctl gdeerrors_ctl = { 248, "GDE", &gdeerrors[0], 58}; fis-gtm-V6.0-003/sr_i386/incr_link.c0000644000032200000250000003045512201176175015664 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_unistd.h" #include "gtm_stdio.h" #include "gtm_string.h" #include #include #include "compiler.h" #include "urx.h" #include "objlabel.h" /* needed for masscomp.h */ #include "masscomp.h" #include "gtmio.h" #include "incr_link.h" #include "min_max.h" /* MIDENT_CMP needs MIN */ #include "cmd_qlf.h" /* needed for CQ_UTF8 */ #include "gtm_text_alloc.h" /* INCR_LINK - read and process a mumps object module. Link said module to currently executing image */ LITREF char gtm_release_name[]; LITREF int4 gtm_release_name_len; static char *code; GBLREF mident_fixed zlink_mname; GBLREF boolean_t gtm_utf8_mode; error_def(ERR_INVOBJ); error_def(ERR_LOADRUNNING); error_def(ERR_TEXT); #define RELREAD 50 /* number of relocation entries to buffer */ typedef struct res_list_struct { struct res_list_struct *next, *list; unsigned int addr, symnum; } res_list; void res_free(res_list *root); bool addr_fix(int file, struct exec *fhead, urx_rtnref *urx_lcl, rhdtyp *code); void zl_error(int4 file, int4 err, int4 err2, int4 len, char *addr); bool incr_link(int file_desc) { rhdtyp *hdr, *old_rhead; int code_size, save_errno, cnt; int4 rhd_diff, read_size; char *literal_ptr; var_tabent *curvar; char module_name[SIZEOF(mident_fixed)]; lab_tabent *lbt_ent, *lbt_bot, *lbt_top, *olbt_ent, *olbt_bot, *olbt_top, *curlab; urx_rtnref urx_lcl_anchor; int order; struct exec file_hdr; urx_lcl_anchor.len = 0; urx_lcl_anchor.addr = 0; urx_lcl_anchor.lab = 0; urx_lcl_anchor.next = 0; code = NULL; DOREADRL(file_desc, &file_hdr, SIZEOF(file_hdr), read_size); if (read_size != SIZEOF(file_hdr)) { if (-1 == read_size) { save_errno = errno; zl_error(file_desc, ERR_INVOBJ, ERR_TEXT, strlen(STRERROR(save_errno)), STRERROR(save_errno)); } else zl_error(file_desc, ERR_INVOBJ, ERR_TEXT, RTS_ERROR_TEXT("reading file header")); } else if (OMAGIC != file_hdr.a_magic) zl_error(file_desc, ERR_INVOBJ, ERR_TEXT, RTS_ERROR_TEXT("bad magic")); else if (OBJ_LABEL != file_hdr.a_stamp) return FALSE; /* wrong version */ assert(0 == file_hdr.a_bss); code_size = file_hdr.a_text + file_hdr.a_data; code = GTM_TEXT_ALLOC(code_size); DOREADRL(file_desc, code, code_size, read_size); if (read_size != code_size) { if (-1 == read_size) { save_errno = errno; zl_error(file_desc, ERR_INVOBJ, ERR_TEXT, strlen(STRERROR(save_errno)), STRERROR(save_errno)); /* BYPASSOK */ } else zl_error(file_desc, ERR_INVOBJ, ERR_TEXT, RTS_ERROR_TEXT("reading code")); } hdr = (rhdtyp *)code; if (memcmp(&hdr->jsb[0], "GTM_CODE", SIZEOF(hdr->jsb))) zl_error(file_desc, ERR_INVOBJ, ERR_TEXT, RTS_ERROR_TEXT("missing GTM_CODE")); if ((hdr->compiler_qlf & CQ_UTF8) && !gtm_utf8_mode) zl_error(file_desc, ERR_INVOBJ, ERR_TEXT, RTS_ERROR_TEXT("Object compiled with CHSET=UTF-8 which is different from $ZCHSET")); if (!(hdr->compiler_qlf & CQ_UTF8) && gtm_utf8_mode) zl_error(file_desc, ERR_INVOBJ, ERR_TEXT, RTS_ERROR_TEXT("Object compiled with CHSET=M which is different from $ZCHSET")); literal_ptr = code + file_hdr.a_text; for (cnt = hdr->vartab_len, curvar = VARTAB_ADR(hdr); cnt; --cnt, ++curvar) { /* relocate the variable table */ assert(0 < curvar->var_name.len); curvar->var_name.addr += (uint4)literal_ptr; } for (cnt = hdr->labtab_len, curlab = LABTAB_ADR(hdr); cnt; --cnt, ++curlab) /* relocate the label table */ curlab->lab_name.addr += (uint4)literal_ptr; if (!addr_fix(file_desc, &file_hdr, &urx_lcl_anchor, hdr)) { urx_free(&urx_lcl_anchor); zl_error(file_desc, ERR_INVOBJ, ERR_TEXT, RTS_ERROR_TEXT("address fixup failure")); } if (!zlput_rname(hdr)) { urx_free(&urx_lcl_anchor); /* Copy routine name to local variable because zl_error free's it. */ memcpy(&module_name[0], hdr->routine_name.addr, hdr->routine_name.len); zl_error(file_desc, 0, ERR_LOADRUNNING, hdr->routine_name.len, &module_name[0]); } urx_add(&urx_lcl_anchor); old_rhead = (rhdtyp *)hdr->old_rhead_ptr; lbt_bot = (lab_tabent *)((char *)hdr + hdr->labtab_ptr); lbt_top = lbt_bot + hdr->labtab_len; while (old_rhead) { lbt_ent = lbt_bot; olbt_bot = (lab_tabent *)((char *)old_rhead + old_rhead->labtab_ptr); olbt_top = olbt_bot + old_rhead->labtab_len; for (olbt_ent = olbt_bot; olbt_ent < olbt_top; olbt_ent++) { for (; lbt_ent < lbt_top; lbt_ent++) { MIDENT_CMP(&olbt_ent->lab_name, &lbt_ent->lab_name, order); if (order <= 0) break; } if ((lbt_ent < lbt_top) && !order) { olbt_ent->lab_ln_ptr = lbt_ent->lab_ln_ptr; olbt_ent->has_parms = lbt_ent->has_parms; } else olbt_ent->lab_ln_ptr = 0; } rhd_diff = (char *)hdr - (char *)old_rhead; old_rhead->src_full_name = hdr->src_full_name; old_rhead->routine_name = hdr->routine_name; old_rhead->vartab_len = hdr->vartab_len; old_rhead->vartab_ptr = hdr->vartab_ptr + rhd_diff; old_rhead->ptext_ptr = hdr->ptext_ptr + rhd_diff; old_rhead->current_rhead_ptr = rhd_diff; old_rhead->temp_mvals = hdr->temp_mvals; old_rhead->temp_size = hdr->temp_size; old_rhead = (rhdtyp *) old_rhead->old_rhead_ptr; } urx_resolve(hdr, lbt_bot, lbt_top); return TRUE; } bool addr_fix(int file, struct exec *fhead, urx_rtnref *urx_lcl, rhdtyp *code) { res_list *res_root, *new_res, *res_temp, *res_temp1; char *symbols, *sym_temp, *sym_temp1, *symtop, *res_addr; struct relocation_info rel[RELREAD]; int numrel, rel_read, i, string_size, sym_size; size_t status; mident_fixed rtnid, labid; mstr rtn_str; rhdtyp *rtn; lab_tabent *label, *labtop; bool labsym; urx_rtnref *urx_rp; urx_addr *urx_tmpaddr; res_root = 0; numrel = (fhead->a_trsize + fhead->a_drsize) / SIZEOF(struct relocation_info); if (numrel * SIZEOF(struct relocation_info) != fhead->a_trsize + fhead->a_drsize) return FALSE; for ( ; numrel;) { rel_read = numrel < RELREAD ? numrel : RELREAD; DOREADRC(file, rel, rel_read * SIZEOF(struct relocation_info), status); if (0 != status) { res_free(res_root); return FALSE; } numrel -= rel_read; for (i = 0; i < rel_read; i++) { if (rel[i].r_extern) { new_res = (res_list *)malloc(SIZEOF(*new_res)); new_res->symnum = rel[i].r_symbolnum; new_res->addr = rel[i].r_address; new_res->next = new_res->list = 0; /* Insert the relocation entry in symbol number order on the unresolved chain */ if (!res_root) res_root = new_res; else { res_temp = res_root; res_temp1 = 0; while (res_temp) { if (res_temp->symnum >= new_res->symnum) break; res_temp1 = res_temp; res_temp = res_temp->next; } if (res_temp) { if (res_temp->symnum == new_res->symnum) { new_res->list = res_temp->list; res_temp->list = new_res; } else { if (res_temp1) { new_res->next = res_temp1->next; res_temp1->next = new_res; } else { assert(res_temp == res_root); new_res->next = res_root; res_root = new_res; } } } else res_temp1->next = new_res; } } else *(unsigned int *)(((char *)code) + rel[i].r_address) += (unsigned int)code; } } /* All relocations within the routine should have been done, so copy the routine_name */ assert(code->routine_name.len < SIZEOF(zlink_mname.c)); memcpy(&zlink_mname.c[0], code->routine_name.addr, code->routine_name.len); zlink_mname.c[code->routine_name.len] = 0; if (!res_root) return TRUE; if ((off_t)-1 == lseek(file, (off_t)fhead->a_syms, SEEK_CUR)) { res_free(res_root); return FALSE; } DOREADRC(file, &string_size, SIZEOF(string_size), status); if (0 != status) { res_free(res_root); return FALSE; } string_size -= SIZEOF(string_size); symbols = malloc(string_size); DOREADRC(file, symbols, string_size, status); if (0 != status) { free(symbols); res_free(res_root); return FALSE; } /* Match up unresolved entries with the null terminated symbol name entries from the * symbol text pool we just read in. */ sym_temp = sym_temp1 = symbols; symtop = symbols + string_size; for (i = 0; res_root; i++) { while (i < res_root->symnum) { /* Forward symbol space until our symnum index (i) matches the symbol we are processing in res_root */ while (*sym_temp) { if (sym_temp >= symtop) { free(symbols); res_free(res_root); return FALSE; } sym_temp++; } sym_temp++; sym_temp1 = sym_temp; i++; } assert (i == res_root->symnum); /* Find end of routine name that we care about */ while (('.' != *sym_temp1) && *sym_temp1) { if (sym_temp1 >= symtop) { free(symbols); res_free(res_root); return FALSE; } sym_temp1++; } sym_size = sym_temp1 - sym_temp; assert(sym_size <= MAX_MIDENT_LEN); memcpy(&rtnid.c[0], sym_temp, sym_size); rtnid.c[sym_size] = 0; if ('_' == rtnid.c[0]) rtnid.c[0] = '%'; assert((sym_size != mid_len(&zlink_mname)) || (0 != memcmp(&zlink_mname.c[0], &rtnid.c[0], sym_size))); rtn_str.addr = &rtnid.c[0]; rtn_str.len = sym_size; rtn = find_rtn_hdr(&rtn_str); /* Routine already resolved? */ sym_size = 0; labsym = FALSE; if (*sym_temp1 == '.') { /* If symbol is for a label, find the end of the label name */ sym_temp1++; sym_temp = sym_temp1; while (*sym_temp1) { if (sym_temp1 >= symtop) { free(symbols); res_free(res_root); return FALSE; } sym_temp1++; } sym_size = sym_temp1 - sym_temp; assert(sym_size <= MAX_MIDENT_LEN); memcpy(&labid.c[0], sym_temp, sym_size); labid.c[sym_size] = 0; if ('_' == labid.c[0]) labid.c[0] = '%'; labsym = TRUE; } sym_temp1++; sym_temp = sym_temp1; if (rtn) { /* The routine part at least is known */ if (labsym) { /* Look our target label up in the routines label table */ label = (lab_tabent *)((char *)rtn + rtn->labtab_ptr); labtop = label + rtn->labtab_len; for (; label < labtop && ((sym_size != label->lab_name.len) || memcmp(&labid.c[0], label->lab_name.addr, sym_size)); label++) ; if (label < labtop) res_addr = (char *)&label->LABENT_LNR_OFFSET; else res_addr = 0; } else res_addr = (char *)rtn; if (res_addr) { /* The external symbol definition is available. Resolve all references to it */ res_temp = res_root->next; while (res_root) { *(uint4 *)(((char *)code) + res_root->addr) = (unsigned int)res_addr; res_temp1 = res_root->list; free(res_root); res_root = res_temp1; } res_root = res_temp; continue; } } /* This symbol is unknown. Put on the (local) unresolved extern chain -- either for labels or routines */ urx_rp = urx_putrtn(rtn_str.addr, rtn_str.len, urx_lcl); res_temp = res_root->next; while (res_root) { if (labsym) urx_putlab(&labid.c[0], sym_size, urx_rp, ((char *)code) + res_root->addr); else { urx_tmpaddr = (urx_addr *)malloc(SIZEOF(urx_addr)); urx_tmpaddr->next = urx_rp->addr; urx_tmpaddr->addr = (INTPTR_T *)(((char *)code) + res_root->addr); urx_rp->addr = urx_tmpaddr; } res_temp1 = res_root->list; free(res_root); res_root = res_temp1; } res_root = res_temp; } free(symbols); return TRUE; } void res_free(res_list *root) { res_list *temp; while (root) { while (root->list) { temp = root->list->list; free(root->list); root->list = temp; } temp = root->next; free(root); root = temp; } } /* ZL_ERROR - perform cleanup and signal errors found in zlinking a mumps object module * err - an error code that accepts no arguments and * err2 - an error code that accepts two arguments (!AD) */ void zl_error(int4 file, int4 err, int4 err2, int4 len, char *addr) { int rc; if (code) { GTM_TEXT_FREE(code); code = NULL; } CLOSEFILE_RESET(file, rc); /* resets "file" to FD_INVALID */ if ((0 != err) && (0 != err2)) rts_error(VARLSTCNT(6) err, 0, err2, 2, len, addr); else if (0 != err) rts_error(VARLSTCNT(1) err); else { assert(0 != err2); rts_error(VARLSTCNT(4) err2, 2, len, addr); } } fis-gtm-V6.0-003/sr_i386/linkage.si0000644000032200000250000000136212201176146015510 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # #define SYMBOL_NAME_STR(X) #X # #define SYMBOL_NAME(X) X # #ifdef __STDC__ # #define SYMBOL_NAME_LABEL(X) X##: # #else # #define SYMBOL_NAME_LABEL(X) X/**/: # #endif .macro SYMBOL_NAME_LABEL X \X: .endm .macro ENTRY name # .globl SYMBOL_NAME \name .globl \name .align 16,0x90 SYMBOL_NAME_LABEL \name .endm fis-gtm-V6.0-003/sr_i386/make_cimode.c0000644000032200000250000000664012201176176016151 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "error.h" #include #include "op.h" #include "i386.h" #include "inst_flush.h" #include "gtmci.h" #include "gtm_text_alloc.h" #define CALL_SIZE 5 #define CODE_SIZE (3 * CALL_SIZE) #define CODE_LINES 3 /* The code created and returned by make_cimode() is executed in the frame GTM$CI at level 1 of * every nested call-in environment. For every M routine being called-in from C, GTM$CI code * will setup argument registers/stack and executes the M routine. When the M routine returns * from its final QUIT, GTM$CI returns to gtm_ci(). make_cimode generates machine equivalents * for the following operations in that order: * * CALL ci_restart :setup register/stack arguments from 'param_list' and transfer control * to op_extcall/op_extexfun which return only after the M routine finishes and QUITs. * CALL ci_ret_code :transfer control from the M routine back to C (gtm_ci). Never returns. * CALL opp_ret :an implicit QUIT although it is never executed. * * Before GTM$CI executes, it is assumed that the global 'param_list' has been populated with * argument/return mval*. */ rhdtyp *make_cimode(void) { static rhdtyp *base_address = NULL; lab_tabent *lbl; int *lnr; unsigned char *code; if (NULL != base_address) return base_address; base_address = (rhdtyp *)GTM_TEXT_ALLOC(SIZEOF(rhdtyp) + CODE_SIZE + SIZEOF(lab_tabent) + CODE_LINES * SIZEOF(int4)); memset(base_address,0,SIZEOF(rhdtyp) + CODE_SIZE + SIZEOF(lab_tabent) + CODE_LINES * SIZEOF(int4)); base_address->routine_name.len = STR_LIT_LEN(GTM_CIMOD); base_address->routine_name.addr = GTM_CIMOD; base_address->ptext_ptr = SIZEOF(rhdtyp); base_address->vartab_ptr = base_address->labtab_ptr = SIZEOF(rhdtyp) + CODE_SIZE; /* hdr + code */ base_address->lnrtab_ptr = SIZEOF(rhdtyp) + CODE_SIZE + SIZEOF(lab_tabent); base_address->labtab_len = 1; base_address->lnrtab_len = CODE_LINES; code = (unsigned char *) base_address + base_address->ptext_ptr; *code++ = I386_INS_CALL_Jv; *((int4 *)code) = (int4)((unsigned char *)ci_restart - (code + SIZEOF(int4))); code += SIZEOF(int4); *code++ = I386_INS_CALL_Jv; /* a CALL to return control from M to ci_ret_code() which in turn returns to gtm_ci() */ *((int4 *)code) = (int4)((unsigned char *)ci_ret_code - (code + SIZEOF(int4))); code += SIZEOF(int4); *code++ = I386_INS_JMP_Jv; *((int4 *)code) = (int4)((unsigned char *)opp_ret - (code + SIZEOF(int4))); code += SIZEOF(int4); lbl = (lab_tabent *)((int) base_address + base_address->labtab_ptr); lbl->lab_ln_ptr = base_address->lnrtab_ptr; lnr = (int *)((int)base_address + base_address->lnrtab_ptr); *lnr++ = base_address->ptext_ptr; *lnr++ = base_address->ptext_ptr; *lnr++ = base_address->ptext_ptr + 2 * CALL_SIZE; assert(code - ((unsigned char *)base_address + base_address->ptext_ptr) == CODE_SIZE); zlput_rname(base_address); inst_flush(base_address, SIZEOF(rhdtyp) + CODE_SIZE + SIZEOF(lab_tabent) + CODE_LINES * SIZEOF(int4)); return base_address; } fis-gtm-V6.0-003/sr_i386/make_dmode.c0000644000032200000250000000521012201176176015771 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "error.h" #include #include "op.h" #include "i386.h" #include "inst_flush.h" #include "dm_setup.h" #include "gtm_text_alloc.h" #define CALL_SIZE 5 #define CODE_SIZE 3*CALL_SIZE #define CODE_LINES 3 rhdtyp *make_dmode(void) { rhdtyp *base_address; lab_tabent *lbl; int *lnr; unsigned char *code; /* dummy code + label entry + line entries */ base_address = (rhdtyp *)GTM_TEXT_ALLOC(SIZEOF(rhdtyp) + CODE_SIZE + SIZEOF(lab_tabent) + CODE_LINES * SIZEOF(int4)); memset(base_address,0,SIZEOF(rhdtyp) + CODE_SIZE + SIZEOF(lab_tabent) + CODE_LINES*SIZEOF(int4)); base_address->routine_name.len = STR_LIT_LEN(GTM_DMOD); base_address->routine_name.addr = GTM_DMOD; base_address->ptext_ptr = SIZEOF(rhdtyp); base_address->vartab_ptr = base_address->labtab_ptr = SIZEOF(rhdtyp) + CODE_SIZE; /* hdr + code */ base_address->lnrtab_ptr = SIZEOF(rhdtyp) + CODE_SIZE + SIZEOF(lab_tabent); base_address->labtab_len = 1; base_address->lnrtab_len = CODE_LINES; code = (unsigned char *) base_address + base_address->ptext_ptr; *code++ = I386_INS_CALL_Jv; *((int4 *)code) = (int4)((unsigned char *)dm_setup - (code + SIZEOF(int4))); code += SIZEOF(int4); *code++ = I386_INS_CALL_Jv; /* this should be a CALL to maintain uniformity between transfer to mum_tstart from baseframe and transfers to mum_tstart from error processing (MUM_TSTART marco in mdb_condition_handler) */ *((int4 *)code) = (int4)((unsigned char *)mum_tstart - (code + SIZEOF(int4))); code += SIZEOF(int4); *code++ = I386_INS_JMP_Jv; *((int4 *)code) = (int4)((unsigned char *)opp_ret - (code + SIZEOF(int4))); code += SIZEOF(int4); lbl = (lab_tabent *)((int) base_address + base_address->labtab_ptr); lbl->lab_ln_ptr = base_address->lnrtab_ptr; lnr = (int *)((int)base_address + base_address->lnrtab_ptr); *lnr++ = base_address->ptext_ptr; *lnr++ = base_address->ptext_ptr; *lnr++ = base_address->ptext_ptr + 2 * CALL_SIZE; assert(code - ((unsigned char *)base_address + base_address->ptext_ptr) == CODE_SIZE); zlput_rname(base_address); inst_flush(base_address, SIZEOF(rhdtyp) + CODE_SIZE + SIZEOF(lab_tabent) + CODE_LINES * SIZEOF(int4)); return base_address; } fis-gtm-V6.0-003/sr_i386/masscomp.h0000644000032200000250000000451512201176146015537 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ struct exec { short a_magic; /* magic number */ short a_stamp; /* version stamp - RTU 2.0+ uses this - see below */ uint4 a_text; /* size of text segment */ uint4 a_data; /* size of initialized data */ uint4 a_bss; /* size of uninitialized data */ uint4 a_syms; /* size of symbol table */ uint4 a_entry; /* entry point */ uint4 a_trsize; /* size of text relocation */ uint4 a_drsize; /* size of data relocation */ }; /* * Format of a relocation datum. */ struct relocation_info { int r_address; /* address which is relocated */ unsigned int r_symbolnum:24, /* local symbol ordinal */ r_pcrel:1, /* was relocated pc relative already */ r_length:2, /* 0=byte, 1=word, 2=int4 */ r_extern:1, /* does not include value of sym referenced */ r_pad:4; /* nothing, yet */ }; struct rel_table { struct rel_table *next, *resolve; struct relocation_info r; }; /* * Format of a symbol table entry; this file is included by * and should be used if you aren't interested the a.out header * or relocation information. */ struct nlist { int4 n_strx; /* index into file string table */ unsigned char n_type; /* type flag, i.e. N_TEXT etc; see below */ char n_other; /* unused */ short n_desc; /* see */ uint4 n_value; /* value of this symbol (or sdb offset) */ }; struct sym_table { struct sym_table *next; struct nlist n; struct rel_table *resolve; unsigned short name_len; unsigned char name[1]; }; /* * Simple values for n_type. */ #define N_UNDF 0x0 /* undefined */ #define N_ABS 0x2 /* absolute */ #define N_TEXT 0x4 /* text */ #define N_DATA 0x6 /* data */ #define N_BSS 0x8 /* bss */ #define N_COMM 0x12 /* common (internal to ld) */ #define N_IPCOMM 0x16 /* initialized private */ #define N_PCOMM 0x18 /* uninitialized private */ #define N_FN 0x1f /* file name symbol */ #define N_EXT 01 /* external bit, or'ed in */ #define N_TYPE 0x1e /* mask for all the type bits */ fis-gtm-V6.0-003/sr_i386/merrors_ansi.h0000666000032200000250000010170712201176212016417 0ustar librarygtc/**************************************************************** * * * Copyright 2001,2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ const static readonly int error_ansi[] = { 0, /* ACK */ 0, /* BREAKZST */ 0, /* BADACCMTHD */ 0, /* BADJPIPARAM */ 0, /* BADSYIPARAM */ 0, /* BITMAPSBAD */ 0, /* BREAK */ 0, /* BREAKDEA */ 0, /* BREAKZBA */ 0, /* STATCNT */ 0, /* BTFAIL */ 0, /* MUPRECFLLCK */ 0, /* CMD */ 0, /* COLON */ 0, /* COMMA */ 0, /* COMMAORRPAREXP */ 0, /* COMMENT */ 0, /* CTRAP */ 0, /* CTRLC */ 0, /* CTRLY */ 0, /* DBCCERR */ 0, /* DUPTOKEN */ 0, /* DBJNLNOTMATCH */ 0, /* DBFILERR */ 0, /* DBNOTGDS */ 0, /* DBOPNERR */ 0, /* DBRDERR */ 0, /* CCEDUMPNOW */ 0, /* DEVPARINAP */ 0, /* RECORDSTAT */ 0, /* NOTGBL */ 0, /* DEVPARPROT */ 0, /* PREMATEOF */ 0, /* GVINVALID */ 0, /* DEVPARTOOBIG */ 0, /* DEVPARUNK */ 0, /* DEVPARVALREQ */ 0, /* DEVPARMNEG */ 0, /* DSEBLKRDFAIL */ 0, /* DSEFAIL */ 0, /* NOTALLREPLON */ 0, /* BADLKIPARAM */ 0, /* JNLREADBOF */ 0, /* DVIKEYBAD */ 0, /* ENQ */ 0, /* EQUAL */ 0, /* ERRORSUMMARY */ 0, /* ERRWEXC */ 0, /* ERRWIOEXC */ 0, /* ERRWZBRK */ 0, /* ERRWZTRAP */ 0, /* NUMUNXEOR */ 0, /* EXPR */ 0, /* STRUNXEOR */ 0, /* JNLEXTEND */ 0, /* FCHARMAXARGS */ 0, /* FCNSVNEXPECTED */ 2, /* FNARGINC */ 0, /* JNLACCESS */ 44, /* TRANSNOSTART */ 0, /* FNUMARG */ 0, /* FOROFLOW */ 0, /* YDIRTSZ */ 0, /* JNLSUCCESS */ 29, /* GBLNAME */ 0, /* GBLOFLOW */ 0, /* CORRUPT */ 0, /* GTMCHECK */ 0, /* GVDATAFAIL */ 0, /* EORNOTFND */ 0, /* GVGETFAIL */ 0, /* GVIS */ 0, /* GVKILLFAIL */ 1, /* GVNAKED */ 0, /* GVNEXTARG */ 0, /* GVORDERFAIL */ 0, /* GVPUTFAIL */ 0, /* PATTABSYNTAX */ 0, /* GVSUBOFLOW */ 7, /* GVUNDEF */ 0, /* TRANSNEST */ 0, /* INDEXTRACHARS */ 0, /* UNUSEDMSG260 */ 0, /* INDRMAXLEN */ 0, /* INSFFBCNT */ 0, /* INTEGERRS */ 0, /* INVCMD */ 0, /* INVFCN */ 0, /* INVOBJ */ 8, /* INVSVN */ 0, /* IOEOF */ 0, /* IONOTOPEN */ 0, /* MUPIPINFO */ 0, /* IVTIME */ 0, /* JOBFAIL */ 13, /* JOBLABOFF */ 0, /* JOBPARNOVAL */ 0, /* JOBPARNUM */ 0, /* JOBPARSTR */ 0, /* JOBPARUNK */ 0, /* JOBPARVALREQ */ 0, /* JUSTFRACT */ 0, /* KEY2BIG */ 0, /* LABELEXPECTED */ 13, /* LABELMISSING */ 13, /* LABELUNKNOWN */ 9, /* DIVZERO */ 0, /* LKNAMEXPECTED */ 0, /* JNLRDERR */ 25, /* LOADRUNNING */ 0, /* LPARENMISSING */ 0, /* LSEXPECTED */ 0, /* LVORDERARG */ 0, /* MAXFORARGS */ 0, /* TRANSMINUS */ 0, /* MAXNRSUBSCRIPTS */ 75, /* MAXSTRLEN */ 0, /* JNLDBERR */ 0, /* JNLFILOPN */ 0, /* MBXRDONLY */ 0, /* JNLINVALID */ 0, /* MBXWRTONLY */ 0, /* MEMORY */ 70, /* MTBLKTOOBIG */ 70, /* MTBLKTOOSM */ 70, /* MTFIXRECSZ */ 0, /* MTIS */ 0, /* MTRDBADBLK */ 62, /* MTRDONLY */ 0, /* MTRDTHENWRT */ 71, /* MTRECGTRBLK */ 72, /* MTRECTOOBIG */ 72, /* MTRECTOOSM */ 0, /* JNLTMQUAL3 */ 57, /* MULTLAB */ 0, /* BLKCNT */ 0, /* CCEDUMPOFF */ 0, /* NOPLACE */ 0, /* JNLCLOSE */ 0, /* NOTPRINCIO */ 0, /* NOTTOEOFONPUT */ 0, /* NOZBRK */ 0, /* NULSUBSC */ 92, /* NUMOFLOW */ 0, /* PARFILSPC */ 0, /* PATCLASS */ 10, /* PATCODE */ 0, /* PATLIT */ 0, /* PATMAXLEN */ 0, /* LPARENREQD */ 10, /* PATUPPERLIM */ 0, /* PCONDEXPECTED */ 0, /* PRCNAMLEN */ 3, /* RANDARGNEG */ 0, /* DBPRIVERR */ 75, /* REC2BIG */ 0, /* RHMISSING */ 62, /* DEVICEREADONLY */ 0, /* COLLDATAEXISTS */ 88, /* ROUTINEUNKNOWN */ 0, /* RPARENMISSING */ 0, /* RTNNAME */ 0, /* VIEWGVN */ 0, /* RTSLOC */ 0, /* RWARG */ 0, /* RWFORMAT */ 0, /* JNLWRTDEFER */ 4, /* SELECTFALSE */ 0, /* SPOREOL */ 0, /* SRCLIN */ 0, /* SRCLOC */ 0, /* SRCLOCUNKNOWN */ 0, /* STACKCRIT */ 0, /* STACKOFLOW */ 0, /* STACKUNDERFLO */ 0, /* STRINGOFLOW */ 0, /* SVNOSET */ 0, /* VIEWFN */ 0, /* TERMASTQUOTA */ 5, /* TEXTARG */ 0, /* TMPSTOREMAX */ 0, /* VIEWCMD */ 0, /* JNI */ 0, /* TXTSRCFMT */ 0, /* UIDMSG */ 0, /* UIDSND */ 6, /* UNDEF */ 0, /* UNIMPLOP */ 39, /* VAREXPECTED */ 0, /* VARRECBLKSZ */ 0, /* MAXARGCNT */ 0, /* GTMSECSHRSEMGET */ 0, /* VIEWARGCNT */ 0, /* GTMSECSHRDMNSTARTED */ 0, /* ZATTACHERR */ 0, /* ZDATEFMT */ 0, /* ZEDFILSPEC */ 75, /* ZFILENMTOOLONG */ 0, /* ZFILKEYBAD */ 0, /* ZFILNMBAD */ 0, /* ZGOTOLTZERO */ 0, /* ZGOTOTOOBIG */ 0, /* ZLINKFILE */ 0, /* ZPARSETYPE */ 0, /* ZPARSFLDBAD */ 0, /* ZPIDBADARG */ 0, /* ZPRIVARGBAD */ 0, /* ZPRIVSYNTAXERR */ 13, /* ZPRTLABNOTFND */ 0, /* VIEWAMBIG */ 0, /* VIEWNOTFOUND */ 0, /* ZSETPRVARGBAD */ 0, /* INVSPECREC */ 0, /* ZSETPRVSYNTAX */ 0, /* ZSRCHSTRMCT */ 0, /* VERSION */ 0, /* MUNOTALLSEC */ 0, /* MUSECDEL */ 0, /* MUSECNOTDEL */ 0, /* RPARENREQD */ 26, /* ZGBLDIRACC */ 0, /* GVNAKEDEXTNM */ 0, /* EXTGBLDEL */ 0, /* DSEWCINITCON */ 0, /* LASTFILCMPLD */ 0, /* NOEXCNOZTRAP */ 0, /* UNSDCLASS */ 0, /* UNSDDTYPE */ 0, /* ZCUNKTYPE */ 0, /* ZCUNKMECH */ 0, /* ZCUNKQUAL */ 0, /* JNLDBTNNOMATCH */ 0, /* ZCALLTABLE */ 58, /* ZCARGMSMTCH */ 58, /* ZCCONMSMTCH */ 0, /* ZCOPT0 */ 0, /* ZCSTATUS */ 0, /* ZCUSRRTN */ 0, /* ZCPOSOVR */ 0, /* ZCINPUTREQ */ 0, /* JNLTNOUTOFSEQ */ 0, /* ACTRANGE */ 0, /* ZCCONVERT */ 0, /* ZCRTENOTF */ 0, /* GVRUNDOWN */ 0, /* LKRUNDOWN */ 0, /* IORUNDOWN */ 0, /* FILENOTFND */ 0, /* MUFILRNDWNFL */ 0, /* JNLTMQUAL1 */ 0, /* FORCEDHALT */ 0, /* LOADEOF */ 0, /* WILLEXPIRE */ 0, /* LOADEDBG */ 0, /* LABELONLY */ 0, /* MUREORGFAIL */ 0, /* GVZPREVFAIL */ 21, /* MULTFORMPARM */ 16, /* QUITARGUSE */ 0, /* NAMEEXPECTED */ 11, /* FALLINTOFLST */ 16, /* NOTEXTRINSIC */ 0, /* GTMSECSHRREMSEMFAIL */ 20, /* FMLLSTMISSING */ 58, /* ACTLSTTOOLONG */ 0, /* ACTOFFSET */ 0, /* MAXACTARG */ 0, /* GTMSECSHRREMSEM */ 0, /* JNLTMQUAL2 */ 0, /* GDINVALID */ 0, /* ASSERT */ 0, /* MUFILRNDWNSUC */ 0, /* LOADEDSZ */ 16, /* QUITARGLST */ 17, /* QUITARGREQD */ 0, /* CRITRESET */ 0, /* UNKNOWNFOREX */ 0, /* FSEXP */ 0, /* WILDCARD */ 0, /* DIRONLY */ 0, /* FILEPARSE */ 0, /* QUALEXP */ 0, /* BADQUAL */ 0, /* QUALVAL */ 0, /* ZROSYNTAX */ 0, /* COMPILEQUALS */ 0, /* ZLNOOBJECT */ 0, /* ZLMODULE */ 0, /* DBBLEVMX */ 0, /* DBBLEVMN */ 0, /* DBBSIZMN */ 0, /* DBBSIZMX */ 0, /* DBRSIZMN */ 0, /* DBRSIZMX */ 0, /* DBCMPNZRO */ 0, /* DBSTARSIZ */ 0, /* DBSTARCMP */ 0, /* DBCMPMX */ 0, /* DBKEYMX */ 0, /* DBKEYMN */ 0, /* DBCMPBAD */ 0, /* DBKEYORD */ 0, /* DBPTRNOTPOS */ 0, /* DBPTRMX */ 0, /* DBPTRMAP */ 0, /* IFBADPARM */ 0, /* IFNOTINIT */ 0, /* GTMSECSHRSOCKET */ 0, /* LOADBGSZ */ 0, /* LOADFMT */ 0, /* LOADFILERR */ 0, /* NOREGION */ 0, /* PATLOAD */ 0, /* EXTRACTFILERR */ 0, /* FREEZE */ 0, /* NOSELECT */ 0, /* EXTRFAIL */ 0, /* LDBINFMT */ 0, /* NOPREVLINK */ 0, /* CCEDUMPON */ 0, /* CCEDMPQUALREQ */ 0, /* CCEDBDUMP */ 0, /* CCEDBNODUMP */ 0, /* CCPMBX */ 0, /* REQRUNDOWN */ 0, /* CCPINTQUE */ 0, /* CCPBADMSG */ 0, /* CNOTONSYS */ 0, /* CCPNAME */ 0, /* CCPNOTFND */ 0, /* OPRCCPSTOP */ 0, /* SELECTSYNTAX */ 0, /* LOADABORT */ 0, /* FNOTONSYS */ 0, /* AMBISYIPARAM */ 0, /* PREVJNLNOEOF */ 0, /* LKSECINIT */ 0, /* MTDOSLAB */ 0, /* MTDOSFOR */ 0, /* MTINVLAB */ 0, /* TXTSRCMAT */ 0, /* CCENOGROUP */ 0, /* BADDBVER */ 0, /* LINKVERSION */ 0, /* TOTALBLKMAX */ 0, /* LOADCTRLY */ 0, /* CLSTCONFLICT */ 0, /* SRCNAM */ 0, /* LCKGONE */ 0, /* SUB2LONG */ 0, /* EXTRACTCTRLY */ 0, /* CCENOWORLD */ 0, /* GVQUERYFAIL */ 0, /* LCKSCANCELLED */ 0, /* INVNETFILNM */ 0, /* NETDBOPNERR */ 0, /* BADSRVRNETMSG */ 0, /* BADGTMNETMSG */ 0, /* SERVERERR */ 0, /* NETFAIL */ 0, /* NETLCKFAIL */ 0, /* TTINVFILTER */ 0, /* MTANSILAB */ 0, /* MTANSIFOR */ 0, /* BADTRNPARAM */ 0, /* DSEONLYBGMM */ 0, /* DSEINVLCLUSFN */ 18, /* RDFLTOOSHORT */ 0, /* TIMRBADVAL */ 0, /* CCENOSYSLCK */ 0, /* CCPGRP */ 0, /* UNSOLCNTERR */ 0, /* BACKUPCTRL */ 0, /* NOCCPPID */ 0, /* CCPJNLOPNERR */ 0, /* LCKSGONE */ 0, /* ZLKIDBADARG */ 0, /* DBFILOPERR */ 0, /* CCERDERR */ 0, /* CCEDBCL */ 0, /* CCEDBNTCL */ 0, /* CCEWRTERR */ 0, /* CCEBADFN */ 0, /* CCERDTIMOUT */ 0, /* CCPSIGCONT */ 0, /* CCEBGONLY */ 0, /* CCENOCCP */ 0, /* CCECCPPID */ 0, /* CCECLSTPRCS */ 0, /* ZSHOWBADFUNC */ 0, /* NOTALLJNLEN */ 0, /* ZSHOWGLOSMALL */ 0, /* NOLBRSRC */ 0, /* INVZSTEP */ 0, /* ZSTEPARG */ 0, /* INVSTRLEN */ 0, /* RECCNT */ 0, /* TEXT */ 0, /* ZWRSPONE */ 0, /* FILEDEL */ 0, /* JNLBADLABEL */ 0, /* JNLREADEOF */ 0, /* JNLRECFMT */ 0, /* BLKTOODEEP */ 0, /* NESTFORMP */ 0, /* BINHDR */ 0, /* GOQPREC */ 0, /* LDGOQFMT */ 0, /* BEGINST */ 0, /* INVMVXSZ */ 0, /* JNLWRTNOWWRTR */ 0, /* GTMSECSHRSHMCONCPROC */ 0, /* JNLINVALLOC */ 0, /* JNLINVEXT */ 0, /* MUPCLIERR */ 0, /* JNLTMQUAL4 */ 0, /* GTMSECSHRREMSHM */ 0, /* GTMSECSHRREMFILE */ 0, /* MUNODBNAME */ 0, /* FILECREATE */ 0, /* FILENOTCREATE */ 0, /* JNLPROCSTUCK */ 0, /* INVGLOBALQUAL */ 0, /* COLLARGLONG */ 0, /* NOPINI */ 0, /* DBNOCRE */ 0, /* JNLSPACELOW */ 0, /* DBCOMMITCLNUP */ 0, /* BFRQUALREQ */ 0, /* REQDVIEWPARM */ 0, /* COLLFNMISSING */ 0, /* JNLACTINCMPLT */ 0, /* NCTCOLLDIFF */ 0, /* DLRCUNXEOR */ 0, /* DLRCTOOBIG */ 0, /* WCERRNOTCHG */ 0, /* WCWRNNOTCHG */ 0, /* ZCWRONGDESC */ 0, /* MUTNWARN */ 0, /* GTMSECSHRUPDDBHDR */ 0, /* LCKSTIMOUT */ 0, /* CTLMNEMAXLEN */ 0, /* CTLMNEXPECTED */ 0, /* USRIOINIT */ 0, /* CRITSEMFAIL */ 0, /* TERMWRITE */ 0, /* COLLTYPVERSION */ 0, /* LVNULLSUBS */ 0, /* GVREPLERR */ 0, /* MTIOERR */ 72, /* RMWIDTHPOS */ 13, /* OFFSETINV */ 0, /* JOBPARTOOLONG */ 0, /* JOBARGMISSING */ 0, /* RUNPARAMERR */ 0, /* FNNAMENEG */ 0, /* ORDER2 */ 0, /* MUNOUPGRD */ 0, /* REORGCTRLY */ 0, /* TSTRTPARM */ 0, /* TRIGNAMENF */ 0, /* TRIGZBREAKREM */ 44, /* TLVLZERO */ 27, /* TRESTNOT */ 41, /* TPLOCK */ 42, /* TPQUIT */ 0, /* TPFAIL */ 0, /* TPRETRY */ 0, /* TPTOODEEP */ 0, /* ZDEFACTIVE */ 0, /* ZDEFOFLOW */ 0, /* MUPRESTERR */ 0, /* MUBCKNODIR */ 0, /* TRANS2BIG */ 0, /* INVBITLEN */ 0, /* INVBITSTR */ 0, /* INVBITPOS */ 0, /* PARNORMAL */ 0, /* PARBUFSM */ 72, /* RMWIDTHTOOBIG */ 0, /* PATTABNOTFND */ 0, /* OBJFILERR */ 0, /* SRCFILERR */ 95, /* NEGFRACPWR */ 0, /* MTNOSKIP */ 0, /* CETOOMANY */ 0, /* CEUSRERROR */ 0, /* CEBIGSKIP */ 0, /* CETOOLONG */ 0, /* CENOINDIR */ 0, /* COLLATIONUNDEF */ 0, /* RBWRNNOTCHG */ 0, /* GTMSECSHRSRVF */ 0, /* FREEZECTRL */ 0, /* JNLFLUSH */ 0, /* CCPSIGDMP */ 0, /* NOPRINCIO */ 0, /* INVPORTSPEC */ 0, /* INVADDRSPEC */ 78, /* SOCKPARMREQ */ 0, /* IPADDRREQ */ 80, /* SOCKWAIT */ 81, /* SOCKACPT */ 80, /* SOCKINIT */ 81, /* OPENCONN */ 0, /* DEVNOTIMP */ 0, /* JNLEXTR */ 0, /* DBREMOTE */ 0, /* JNLREQUIRED */ 0, /* TPMIXUP */ 0, /* HTOFLOW */ 72, /* RMNOBIGRECORD */ 0, /* DBBMSIZE */ 0, /* DBBMBARE */ 0, /* DBBMINV */ 0, /* DBBMMSTR */ 0, /* DBROOTBURN */ 0, /* REPLSTATEERR */ 0, /* VMSMEMORY */ 0, /* DBDIRTSUBSC */ 0, /* TIMEROVFL */ 0, /* GTMASSERT */ 0, /* DBFHEADERR4 */ 0, /* DBADDRANGE */ 0, /* DBQUELINK */ 0, /* DBCRERR */ 0, /* MUSTANDALONE */ 0, /* MUNOACTION */ 0, /* RMBIGSHARE */ 0, /* TPRESTART */ 0, /* SOCKWRITE */ 0, /* DBCNTRLERR */ 0, /* NOTERMENV */ 0, /* NOTERMENTRY */ 0, /* NOTERMINFODB */ 0, /* INVACCMETHOD */ 0, /* JNLOPNERR */ 0, /* JNLRECTYPE */ 0, /* JNLTRANSGTR */ 0, /* JNLTRANSLSS */ 0, /* JNLWRERR */ 0, /* FILEIDMATCH */ 0, /* EXTSRCLIN */ 0, /* EXTSRCLOC */ 0, /* BIGNOACL */ 0, /* ERRCALL */ 0, /* ZCCTENV */ 0, /* ZCCTOPN */ 0, /* ZCCTNULLF */ 0, /* ZCUNAVAIL */ 0, /* ZCENTNAME */ 0, /* ZCCOLON */ 0, /* ZCRTNTYP */ 0, /* ZCRCALLNAME */ 0, /* ZCRPARMNAME */ 0, /* ZCUNTYPE */ 0, /* ZCMLTSTATUS */ 0, /* ZCSTATUSRET */ 0, /* ZCMAXPARAM */ 0, /* ZCCSQRBR */ 0, /* ZCPREALLNUMEX */ 0, /* ZCPREALLVALPAR */ 0, /* VERMISMATCH */ 0, /* JNLCNTRL */ 0, /* TRIGNAMBAD */ 0, /* BUFRDTIMEOUT */ 0, /* INVALIDRIP */ 0, /* BLKSIZ512 */ 0, /* MUTEXERR */ 0, /* JNLVSIZE */ 0, /* MUTEXLCKALERT */ 0, /* MUTEXFRCDTERM */ 0, /* GTMSECSHR */ 0, /* GTMSECSHRSRVFID */ 0, /* GTMSECSHRSRVFIL */ 0, /* FREEBLKSLOW */ 0, /* PROTNOTSUP */ 0, /* DELIMSIZNA */ 0, /* INVCTLMNE */ 0, /* SOCKLISTEN */ 0, /* LQLENGTHNA */ 0, /* ADDRTOOLONG */ 0, /* GTMSECSHRGETSEMFAIL */ 0, /* CPBEYALLOC */ 0, /* DBRDONLY */ 0, /* DUPTN */ 0, /* TRESTLOC */ 0, /* REPLPOOLINST */ 0, /* ZCVECTORINDX */ 0, /* REPLNOTON */ 0, /* JNLMOVED */ 0, /* EXTRFMT */ 0, /* CALLERID */ 0, /* KRNLKILL */ 0, /* MEMORYRECURSIVE */ 0, /* FREEZEID */ 0, /* BLKWRITERR */ 0, /* STOPTIMEOUT */ 0, /* TRIGMODINTP */ 0, /* BCKUPBUFLUSH */ 0, /* NOFORKCORE */ 0, /* JNLREAD */ 0, /* JNLMINALIGN */ 0, /* UNUSEDMSG781 */ 0, /* JNLPOOLSETUP */ 0, /* JNLSTATEOFF */ 0, /* RECVPOOLSETUP */ 0, /* REPLCOMM */ 0, /* NOREPLCTDREG */ 0, /* REPLINFO */ 0, /* REPLWARN */ 0, /* REPLERR */ 0, /* JNLNMBKNOTPRCD */ 0, /* REPLFILIOERR */ 0, /* REPLBRKNTRANS */ 0, /* TTWIDTHTOOBIG */ 0, /* REPLLOGOPN */ 0, /* REPLFILTER */ 0, /* GBLMODFAIL */ 0, /* TTLENGTHTOOBIG */ 0, /* TPTIMEOUT */ 0, /* DEFEREVENT */ 0, /* JNLFILNOTCHG */ 0, /* EVENTLOGERR */ 0, /* UPDATEFILEOPEN */ 0, /* JNLBADRECFMT */ 0, /* NULLCOLLDIFF */ 0, /* MUKILLIP */ 0, /* JNLRDONLY */ 0, /* ANCOMPTINC */ 0, /* ABNCOMPTINC */ 0, /* UNUSEDMSG809 */ 0, /* SOCKNOTFND */ 0, /* CURRSOCKOFR */ 79, /* SOCKETEXIST */ 76, /* LISTENPASSBND */ 0, /* DBCLNUPINFO */ 0, /* MUNODWNGRD */ 0, /* REPLTRANS2BIG */ 0, /* RDFLTOOLONG */ 0, /* MUNOFINISH */ 0, /* DBFILEXT */ 0, /* JNLFSYNCERR */ 0, /* FSYNCTIMOUT */ 0, /* ZCPREALLVALINV */ 0, /* NEWJNLFILECREAT */ 0, /* DSKSPACEFLOW */ 0, /* GVINCRFAIL */ 0, /* ISOLATIONSTSCHN */ 0, /* REPLGBL2LONG */ 0, /* TRACEON */ 0, /* TOOMANYCLIENTS */ 0, /* NOEXCLUDE */ 0, /* GVINCRISOLATION */ 0, /* EXCLUDEREORG */ 0, /* REORGINC */ 0, /* ASC2EBCDICCONV */ 0, /* GTMSECSHRSTART */ 0, /* DBVERPERFWARN1 */ 0, /* FILEIDGBLSEC */ 0, /* GBLSECNOTGDS */ 0, /* BADGBLSECVER */ 0, /* RECSIZENOTEVEN */ 0, /* BUFFLUFAILED */ 0, /* MUQUALINCOMP */ 0, /* DISTPATHMAX */ 0, /* UNUSEDMSG844 */ 0, /* IMAGENAME */ 0, /* GTMSECSHRPERM */ 0, /* GTMDISTUNDEF */ 0, /* SYSCALL */ 0, /* MAXGTMPATH */ 0, /* TROLLBK2DEEP */ 0, /* INVROLLBKLVL */ 0, /* OLDBINEXTRACT */ 0, /* ACOMPTBINC */ 0, /* NOTREPLICATED */ 0, /* DBPREMATEOF */ 0, /* KILLBYSIG */ 0, /* KILLBYSIGUINFO */ 0, /* KILLBYSIGSINFO1 */ 0, /* KILLBYSIGSINFO2 */ 0, /* SIGILLOPC */ 0, /* SIGILLOPN */ 0, /* SIGILLADR */ 0, /* SIGILLTRP */ 0, /* SIGPRVOPC */ 0, /* SIGPRVREG */ 0, /* SIGCOPROC */ 0, /* SIGBADSTK */ 0, /* SIGADRALN */ 0, /* SIGADRERR */ 0, /* SIGOBJERR */ 0, /* SIGINTDIV */ 0, /* SIGINTOVF */ 0, /* SIGFLTDIV */ 0, /* SIGFLTOVF */ 0, /* SIGFLTUND */ 0, /* SIGFLTRES */ 0, /* SIGFLTINV */ 0, /* SIGMAPERR */ 0, /* SIGACCERR */ 0, /* TRNLOGFAIL */ 0, /* INVDBGLVL */ 0, /* DBMAXNRSUBS */ 0, /* GTMSECSHRSCKSEL */ 0, /* GTMSECSHRTMOUT */ 0, /* GTMSECSHRRECVF */ 0, /* GTMSECSHRSENDF */ 0, /* SIZENOTVALID8 */ 0, /* GTMSECSHROPCMP */ 0, /* GTMSECSHRSUIDF */ 0, /* GTMSECSHRSGIDF */ 0, /* GTMSECSHRSSIDF */ 0, /* GTMSECSHRFORKF */ 0, /* DBFSYNCERR */ 0, /* SECONDAHEAD */ 0, /* SCNDDBNOUPD */ 0, /* MUINFOUINT4 */ 0, /* NLMISMATCHCALC */ 0, /* UNUSEDMSG898 */ 0, /* UNUSEDMSG899 */ 0, /* DBBADNSUB */ 0, /* DBBADKYNM */ 0, /* DBBADPNTR */ 0, /* DBBNPNTR */ 0, /* DBINCLVL */ 0, /* DBBFSTAT */ 0, /* DBBDBALLOC */ 0, /* DBMRKFREE */ 0, /* DBMRKBUSY */ 0, /* DBBSIZZRO */ 0, /* DBSZGT64K */ 0, /* DBNOTMLTP */ 0, /* DBTNTOOLG */ 0, /* DBBPLMLT512 */ 0, /* DBBPLMGT2K */ 0, /* MUINFOUINT8 */ 0, /* DBBPLNOT512 */ 0, /* MUINFOSTR */ 0, /* DBUNDACCMT */ 0, /* DBTNNEQ */ 0, /* MUPGRDSUCC */ 0, /* DBDSRDFMTCHNG */ 0, /* DBFGTBC */ 0, /* DBFSTBC */ 0, /* DBFSTHEAD */ 0, /* DBCREINCOMP */ 0, /* DBFLCORRP */ 0, /* DBHEADINV */ 0, /* DBINCRVER */ 0, /* DBINVGBL */ 0, /* DBKEYGTIND */ 0, /* DBGTDBMAX */ 0, /* DBKGTALLW */ 0, /* DBLTSIBL */ 0, /* DBLRCINVSZ */ 0, /* MUREUPDWNGRDEND */ 0, /* DBLOCMBINC */ 0, /* DBLVLINC */ 0, /* DBMBSIZMX */ 0, /* DBMBSIZMN */ 0, /* DBMBTNSIZMX */ 0, /* DBMBMINCFRE */ 0, /* DBMBPINCFL */ 0, /* DBMBPFLDLBM */ 0, /* DBMBPFLINT */ 0, /* DBMBPFLDIS */ 0, /* DBMBPFRDLBM */ 0, /* DBMBPFRINT */ 0, /* DBMAXKEYEXC */ 0, /* DBMXRSEXCMIN */ 0, /* UNUSEDMSG950 */ 0, /* DBREADBM */ 0, /* DBCOMPTOOLRG */ 0, /* DBVERPERFWARN2 */ 0, /* DBRBNTOOLRG */ 0, /* DBRBNLBMN */ 0, /* DBRBNNEG */ 0, /* DBRLEVTOOHI */ 0, /* DBRLEVLTONE */ 0, /* DBSVBNMIN */ 0, /* DBTTLBLK0 */ 0, /* DBNOTDB */ 0, /* DBTOTBLK */ 0, /* DBTN */ 0, /* DBNOREGION */ 0, /* DBTNRESETINC */ 0, /* DBTNLTCTN */ 0, /* DBTNRESET */ 0, /* MUTEXRSRCCLNUP */ 0, /* SEMWT2LONG */ 0, /* REPLINSTOPEN */ 0, /* REPLINSTCLOSE */ 0, /* UNUSEDMSG972 */ 0, /* DBCRERR8 */ 0, /* NUMPROCESSORS */ 0, /* DBADDRANGE8 */ 0, /* RNDWNSEMFAIL */ 0, /* GTMSECSHRSHUTDN */ 0, /* NOSPACECRE */ 0, /* LOWSPACECRE */ 0, /* WAITDSKSPACE */ 0, /* OUTOFSPACE */ 0, /* JNLPVTINFO */ 0, /* NOSPACEEXT */ 0, /* WCBLOCKED */ 0, /* REPLJNLCLOSED */ 0, /* RENAMEFAIL */ 0, /* FILERENAME */ 0, /* JNLBUFINFO */ 0, /* UNUSEDMSG989 */ 0, /* UNUSEDMSG990 */ 0, /* TPNOTACID */ 0, /* JNLSETDATA2LONG */ 0, /* JNLNEWREC */ 0, /* REPLFTOKSEM */ 0, /* UNUSEDMSG995 */ 0, /* EXTRIOERR */ 0, /* EXTRCLOSEERR */ 0, /* UNUSEDMSG998 */ 0, /* REPLEXITERR */ 0, /* MUDESTROYSUC */ 0, /* DBRNDWN */ 0, /* MUDESTROYFAIL */ 0, /* NOTALLDBOPN */ 0, /* MUSELFBKUP */ 0, /* DBDANGER */ 0, /* TRUNCATEFAIL */ 0, /* TCGETATTR */ 0, /* TCSETATTR */ 0, /* IOWRITERR */ 0, /* REPLINSTWRITE */ 0, /* DBBADFREEBLKCTR */ 0, /* REQ2RESUME */ 0, /* TIMERHANDLER */ 0, /* FREEMEMORY */ 0, /* MUREPLSECDEL */ 0, /* MUREPLSECNOTDEL */ 0, /* MUJPOOLRNDWNSUC */ 0, /* MURPOOLRNDWNSUC */ 0, /* MUJPOOLRNDWNFL */ 0, /* MURPOOLRNDWNFL */ 0, /* MUREPLPOOL */ 0, /* REPLACCSEM */ 0, /* JNLFLUSHNOPROG */ 0, /* REPLINSTCREATE */ 0, /* SUSPENDING */ 0, /* SOCKBFNOTEMPTY */ 0, /* ILLESOCKBFSIZE */ 0, /* NOSOCKETINDEV */ 0, /* SETSOCKOPTERR */ 0, /* GETSOCKOPTERR */ 0, /* NOSUCHPROC */ 0, /* DSENOFINISH */ 0, /* LKENOFINISH */ 0, /* NOCHLEFT */ 0, /* MULOGNAMEDEF */ 0, /* BUFOWNERSTUCK */ 0, /* ACTIVATEFAIL */ 0, /* DBRNDWNWRN */ 0, /* DLLNOOPEN */ 0, /* DLLNORTN */ 0, /* DLLNOCLOSE */ 0, /* FILTERNOTALIVE */ 0, /* FILTERCOMM */ 0, /* FILTERBADCONV */ 0, /* PRIMARYISROOT */ 0, /* GVQUERYGETFAIL */ 0, /* DBCREC2BIGINBLK */ 19, /* MERGEDESC */ 0, /* MERGEINCOMPL */ 0, /* DBNAMEMISMATCH */ 0, /* DBIDMISMATCH */ 0, /* DEVOPENFAIL */ 0, /* IPCNOTDEL */ 0, /* XCVOIDRET */ 0, /* MURAIMGFAIL */ 0, /* REPLINSTUNDEF */ 0, /* REPLINSTACC */ 0, /* NOJNLPOOL */ 0, /* NORECVPOOL */ 0, /* FTOKERR */ 0, /* REPLREQRUNDOWN */ 0, /* BLKCNTEDITFAIL */ 0, /* SEMREMOVED */ 0, /* REPLINSTFMT */ 0, /* SEMKEYINUSE */ 0, /* XTRNTRANSERR */ 0, /* XTRNTRANSDLL */ 0, /* XTRNRETVAL */ 0, /* XTRNRETSTR */ 101, /* INVECODEVAL */ 0, /* SETECODE */ 0, /* INVSTACODE */ 0, /* REPEATERROR */ 90, /* NOCANONICNAME */ 0, /* NOSUBSCRIPT */ 0, /* SYSTEMVALUE */ 0, /* SIZENOTVALID4 */ 0, /* STRNOTVALID */ 0, /* UNUSEDMSG1079 */ 0, /* ERRWETRAP */ 0, /* TRACINGON */ 0, /* CITABENV */ 0, /* CITABOPN */ 0, /* CIENTNAME */ 0, /* CIRTNTYP */ 0, /* CIRCALLNAME */ 0, /* CIRPARMNAME */ 0, /* CIDIRECTIVE */ 0, /* CIPARTYPE */ 0, /* CIUNTYPE */ 0, /* CINOENTRY */ 0, /* JNLINVSWITCHLMT */ 0, /* SETZDIR */ 40, /* JOBACTREF */ 0, /* ECLOSTMID */ 0, /* ZFF2MANY */ 0, /* JNLFSYNCLSTCK */ 0, /* DELIMWIDTH */ 0, /* DBBMLCORRUPT */ 0, /* DLCKAVOIDANCE */ 0, /* WRITERSTUCK */ 0, /* PATNOTFOUND */ 0, /* INVZDIRFORM */ 0, /* ZDIROUTOFSYNC */ 0, /* GBLNOEXIST */ 0, /* MAXBTLEVEL */ 0, /* UNUSEDMSG1107 */ 0, /* JNLALIGNSZCHG */ 0, /* UNUSEDMSG1109 */ 0, /* GVFAILCORE */ 0, /* DBCDBNOCERTIFY */ 0, /* DBFRZRESETSUC */ 0, /* JNLFILEXTERR */ 0, /* JOBEXAMDONE */ 0, /* JOBEXAMFAIL */ 0, /* JOBINTRRQST */ 0, /* ERRWZINTR */ 0, /* CLIERR */ 0, /* REPLNOBEFORE */ 0, /* REPLJNLCNFLCT */ 0, /* JNLDISABLE */ 0, /* FILEEXISTS */ 0, /* JNLSTATE */ 0, /* REPLSTATE */ 0, /* JNLCREATE */ 0, /* JNLNOCREATE */ 0, /* JNLFNF */ 0, /* PREVJNLLINKCUT */ 0, /* PREVJNLLINKSET */ 0, /* FILENAMETOOLONG */ 0, /* REQRECOV */ 0, /* JNLTRANS2BIG */ 0, /* JNLSWITCHTOOSM */ 0, /* JNLSWITCHSZCHG */ 0, /* NOTRNDMACC */ 0, /* TMPFILENOCRE */ 0, /* SHRMEMEXHAUSTED */ 0, /* JNLSENDOPER */ 0, /* DDPSUBSNUL */ 0, /* DDPNOCONNECT */ 0, /* DDPCONGEST */ 0, /* DDPSHUTDOWN */ 0, /* DDPTOOMANYPROCS */ 0, /* DDPBADRESPONSE */ 0, /* DDPINVCKT */ 0, /* DDPVOLSETCONFIG */ 0, /* DDPCONFGOOD */ 0, /* DDPCONFIGNORE */ 0, /* DDPCONFINCOMPL */ 0, /* DDPCONFBADVOL */ 0, /* DDPCONFBADUCI */ 0, /* DDPCONFBADGLD */ 0, /* DDPRECSIZNOTNUM */ 0, /* DDPOUTMSG2BIG */ 0, /* DDPNOSERVER */ 0, /* MUTEXRELEASED */ 0, /* JNLCRESTATUS */ 0, /* ZBREAKFAIL */ 0, /* DLLVERSION */ 0, /* INVZROENT */ 0, /* DDPLOGERR */ 0, /* GETSOCKNAMERR */ 0, /* INVGTMEXIT */ 0, /* CIMAXPARAM */ 0, /* CITPNESTED */ 0, /* CIMAXLEVELS */ 0, /* JOBINTRRETHROW */ 0, /* STARFILE */ 0, /* NOSTARFILE */ 0, /* MUJNLSTAT */ 0, /* JNLTPNEST */ 0, /* REPLOFFJNLON */ 0, /* FILEDELFAIL */ 0, /* INVQUALTIME */ 0, /* NOTPOSITIVE */ 0, /* INVREDIRQUAL */ 0, /* INVERRORLIM */ 0, /* INVIDQUAL */ 0, /* INVTRNSQUAL */ 0, /* JNLNOBIJBACK */ 0, /* SETREG2RESYNC */ 0, /* JNLALIGNTOOSM */ 0, /* JNLFILEOPNERR */ 0, /* JNLFILECLOSERR */ 0, /* REPLSTATEOFF */ 0, /* MUJNLPREVGEN */ 0, /* MUPJNLINTERRUPT */ 0, /* ROLLBKINTERRUPT */ 0, /* RLBKJNSEQ */ 0, /* REPLRECFMT */ 0, /* PRIMARYNOTROOT */ 0, /* DBFRZRESETFL */ 0, /* JNLCYCLE */ 0, /* JNLPREVRECOV */ 0, /* RESOLVESEQNO */ 0, /* BOVTNGTEOVTN */ 0, /* BOVTMGTEOVTM */ 0, /* BEGSEQGTENDSEQ */ 0, /* DBADDRALIGN */ 0, /* DBWCVERIFYSTART */ 0, /* DBWCVERIFYEND */ 0, /* MUPIPSIG */ 0, /* HTSHRINKFAIL */ 0, /* STPEXPFAIL */ 0, /* DBBTUWRNG */ 0, /* DBBTUFIXED */ 0, /* DBMAXREC2BIG */ 0, /* DBCSCNNOTCMPLT */ 0, /* DBCBADFILE */ 0, /* DBCNOEXTND */ 0, /* DBCINTEGERR */ 0, /* DBMINRESBYTES */ 0, /* DBCNOTSAMEDB */ 0, /* DBCDBCERTIFIED */ 0, /* DBCMODBLK2BIG */ 0, /* DBCREC2BIG */ 0, /* DBCCMDFAIL */ 0, /* DBCKILLIP */ 0, /* DBCNOFINISH */ 0, /* DYNUPGRDFAIL */ 0, /* MMNODYNDWNGRD */ 0, /* MMNODYNUPGRD */ 0, /* MUDWNGRDNRDY */ 0, /* MUDWNGRDTN */ 0, /* MUDWNGRDNOTPOS */ 0, /* MUUPGRDNRDY */ 0, /* TNWARN */ 0, /* TNTOOLARGE */ 0, /* SHMPLRECOV */ 0, /* MUNOSTRMBKUP */ 0, /* EPOCHTNHI */ 0, /* CHNGTPRSLVTM */ 0, /* JNLUNXPCTERR */ 0, /* OMISERVHANG */ 0, /* RSVDBYTE2HIGH */ 0, /* BKUPTMPFILOPEN */ 0, /* BKUPTMPFILWRITE */ 0, /* VMSMEMORY2 */ 0, /* LOADBGSZ2 */ 0, /* LOADEDSZ2 */ 0, /* REPLINSTMISMTCH */ 0, /* REPLINSTREAD */ 0, /* REPLINSTDBMATCH */ 0, /* REPLINSTNMSAME */ 0, /* REPLINSTNMUNDEF */ 0, /* REPLINSTNMLEN */ 0, /* REPLINSTNOHIST */ 0, /* REPLINSTSECLEN */ 0, /* REPLINSTSECMTCH */ 0, /* REPLINSTSECNONE */ 0, /* REPLINSTSECUNDF */ 0, /* REPLINSTSEQORD */ 0, /* REPLINSTSTNDALN */ 0, /* REPLREQROLLBACK */ 0, /* REQROLLBACK */ 0, /* UNUSEDMSG1256 */ 0, /* SRCSRVEXISTS */ 0, /* SRCSRVNOTEXIST */ 0, /* SRCSRVTOOMANY */ 0, /* JNLPOOLBADSLOT */ 0, /* NOENDIANCVT */ 0, /* ENDIANCVT */ 0, /* DBENDIAN */ 0, /* BADCHSET */ 0, /* BADCASECODE */ 0, /* BADCHAR */ 0, /* DLRCILLEGAL */ 0, /* NONUTF8LOCALE */ 0, /* INVDLRCVAL */ 0, /* DBMISALIGN */ 0, /* LOADINVCHSET */ 0, /* DLLCHSETM */ 0, /* DLLCHSETUTF8 */ 0, /* BOMMISMATCH */ 0, /* WIDTHTOOSMALL */ 80, /* SOCKMAX */ 0, /* PADCHARINVALID */ 0, /* ZCNOPREALLOUTPAR */ 0, /* SVNEXPECTED */ 0, /* SVNONEW */ 0, /* ZINTDIRECT */ 0, /* ZINTRECURSEIO */ 0, /* MRTMAXEXCEEDED */ 0, /* JNLCLOSED */ 0, /* RLBKNOBIMG */ 0, /* RLBKJNLNOBIMG */ 0, /* RLBKLOSTTNONLY */ 0, /* KILLBYSIGSINFO3 */ 0, /* GTMSECSHRTMPPATH */ 0, /* GTMERREXIT */ 0, /* INVMEMRESRV */ 0, /* OPCOMMISSED */ 0, /* COMMITWAITSTUCK */ 0, /* COMMITWAITPID */ 0, /* UPDREPLSTATEOFF */ 0, /* LITNONGRAPH */ 0, /* DBFHEADERR8 */ 0, /* MMBEFOREJNL */ 0, /* MMNOBFORRPL */ 0, /* KILLABANDONED */ 0, /* BACKUPKILLIP */ 0, /* LOGTOOLONG */ 0, /* NOALIASLIST */ 0, /* ALIASEXPECTED */ 0, /* VIEWLVN */ 0, /* DZWRNOPAREN */ 0, /* DZWRNOALIAS */ 0, /* FREEZEERR */ 0, /* CLOSEFAIL */ 0, /* CRYPTINIT */ 0, /* CRYPTOPFAILED */ 0, /* CRYPTDLNOOPEN */ 0, /* CRYPTNOV4 */ 0, /* CRYPTNOMM */ 0, /* CRYPTJNLWRONGHASH */ 0, /* CRYPTKEYFETCHFAILED */ 0, /* CRYPTKEYFETCHFAILEDNF */ 0, /* CRYPTHASHGENFAILED */ 0, /* CRYPTNOPSWDINTP */ 0, /* BADTAG */ 0, /* ICUVERLT36 */ 0, /* ICUSYMNOTFOUND */ 0, /* STUCKACT */ 0, /* CALLINAFTERXIT */ 0, /* LOCKSPACEFULL */ 0, /* IOERROR */ 0, /* MAXSSREACHED */ 0, /* SNAPSHOTNOV4 */ 0, /* SSV4NOALLOW */ 0, /* SSTMPDIRSTAT */ 0, /* SSTMPCREATE */ 0, /* JNLFILEDUP */ 0, /* SSPREMATEOF */ 0, /* SSFILOPERR */ 0, /* REGSSFAIL */ 0, /* SSSHMCLNUPFAIL */ 0, /* SSFILCLNUPFAIL */ 0, /* SETINTRIGONLY */ 0, /* MAXTRIGNEST */ 0, /* TRIGCOMPFAIL */ 0, /* NOZTRAPINTRIG */ 0, /* ZTWORMHOLE2BIG */ 0, /* JNLENDIANLITTLE */ 0, /* JNLENDIANBIG */ 0, /* TRIGINVCHSET */ 0, /* TRIGREPLSTATE */ 0, /* GVDATAGETFAIL */ 0, /* TRIG2NOTRIG */ 0, /* ZGOTOINVLVL */ 0, /* TRIGTCOMMIT */ 0, /* TRIGTLVLCHNG */ 0, /* TRIGNAMEUNIQ */ 0, /* ZTRIGINVACT */ 0, /* INDRCOMPFAIL */ 0, /* QUITALSINV */ 0, /* PROCTERM */ 0, /* SRCLNNTDSP */ 0, /* ARROWNTDSP */ 0, /* TRIGDEFBAD */ 0, /* TRIGSUBSCRANGE */ 0, /* TRIGDATAIGNORE */ 0, /* TRIGIS */ 0, /* TCOMMITDISALLOW */ 0, /* SSATTACHSHM */ 0, /* TRIGDEFNOSYNC */ 0, /* TRESTMAX */ 0, /* UNUSEDMSG1367 */ 0, /* GBLEXPECTED */ 0, /* GVZTRIGFAIL */ 0, /* MUUSERLBK */ 0, /* SETINSETTRIGONLY */ 0, /* DZTRIGINTRIG */ 0, /* SECNODZTRIGINTP */ 0, /* BOOLSIDEFFECT */ 0, /* DBBADUPGRDSTATE */ 0, /* WRITEWAITPID */ 0, /* ZGOCALLOUTIN */ 0, /* REPLNOXENDIAN */ 0, /* REPLXENDIANFAIL */ 0, /* ZGOTOINVLVL2 */ 0, /* GTMSECSHRCHDIRF */ 0, /* JNLORDBFLU */ 0, /* ZCCLNUPRTNMISNG */ 0, /* ZCINVALIDKEYWORD */ 0, /* REPLNOMULTILINETRG */ 0, /* DBSHMNAMEDIFF */ 0, /* SHMREMOVED */ 0, /* DEVICEWRITEONLY */ 0, /* ICUERROR */ 0, /* ZDATEBADDATE */ 0, /* ZDATEBADTIME */ 0, /* COREINPROGRESS */ 0, /* MAXSEMGETRETRY */ 0, /* JNLNOREPL */ 0, /* JNLRECINCMPL */ 0, /* JNLALLOCGROW */ 0, /* INVTRCGRP */ 0, /* MUINFOUINT6 */ 0, /* NOLOCKMATCH */ 0, /* BADREGION */ 0, /* LOCKSPACEUSE */ 0, /* JIUNHNDINT */ 0, /* GTMASSERT2 */ 0, /* ZTRIGNOTRW */ 0, /* TRIGMODREGNOTRW */ 0, /* INSNOTJOINED */ 0, /* INSROLECHANGE */ 0, /* INSUNKNOWN */ 0, /* NORESYNCSUPPLONLY */ 0, /* NORESYNCUPDATERONLY */ 0, /* NOSUPPLSUPPL */ 0, /* REPL2OLD */ 0, /* EXTRFILEXISTS */ 0, /* MUUSERECOV */ 0, /* SECNOTSUPPLEMENTARY */ 0, /* SUPRCVRNEEDSSUPSRC */ 0, /* UNUSEDMSG1417 */ 0, /* UNUSEDMSG1418 */ 0, /* UPDSYNC2MTINS */ 0, /* UPDSYNCINSTFILE */ 0, /* REUSEINSTNAME */ 0, /* RCVRMANYSTRMS */ 0, /* RSYNCSTRMVAL */ 0, /* RLBKSTRMSEQ */ 0, /* RESOLVESEQSTRM */ 0, /* REPLINSTDBSTRM */ 0, /* RESUMESTRMNUM */ 0, /* ORLBKSTART */ 0, /* ORLBKTERMNTD */ 0, /* ORLBKCMPLT */ 0, /* ORLBKNOSTP */ 0, /* ORLBKFRZPROG */ 0, /* ORLBKFRZOVER */ 0, /* ORLBKNOV4BLK */ 0, /* DBROLLEDBACK */ 0, /* DSEWCREINIT */ 0, /* MURNDWNOVRD */ 0, /* REPLONLNRLBK */ 0, /* SRVLCKWT2LNG */ 0, /* IGNBMPMRKFREE */ 0, /* PERMGENFAIL */ 0, /* PERMGENDIAG */ 0, /* MUTRUNC1ATIME */ 0, /* MUTRUNCBACKINPROG */ 0, /* MUTRUNCERROR */ 0, /* MUTRUNCFAIL */ 0, /* MUTRUNCNOSPACE */ 0, /* MUTRUNCNOTBG */ 0, /* MUTRUNCNOV4 */ 0, /* MUTRUNCPERCENT */ 0, /* MUTRUNCSSINPROG */ 0, /* MUTRUNCSUCCESS */ 0, /* RSYNCSTRMSUPPLONLY */ 0, /* STRMNUMIS */ 0, /* STRMNUMMISMTCH1 */ 0, /* STRMNUMMISMTCH2 */ 0, /* STRMSEQMISMTCH */ 0, /* LOCKSPACEINFO */ 0, /* JRTNULLFAIL */ 0, /* LOCKSUB2LONG */ 0, /* RESRCWAIT */ 0, /* RESRCINTRLCKBYPAS */ 0, /* DBFHEADERRANY */ 0, /* REPLINSTFROZEN */ 0, /* REPLINSTFREEZECOMMENT */ 0, /* REPLINSTUNFROZEN */ 0, /* DSKNOSPCAVAIL */ 0, /* DSKNOSPCBLOCKED */ 0, /* DSKSPCAVAILABLE */ 0, /* ENOSPCQIODEFER */ 0, /* CUSTOMFILOPERR */ 0, /* CUSTERRNOTFND */ 0, /* CUSTERRSYNTAX */ 0, /* ORLBKINPROG */ 0, /* DBSPANGLOINCMP */ 0, /* DBSPANCHUNKORD */ 0, /* DBDATAMX */ 0, /* DBIOERR */ 0, /* INITORRESUME */ 0, /* GTMSECSHRNOARG0 */ 0, /* GTMSECSHRISNOT */ 0, /* GTMSECSHRBADDIR */ 0, /* JNLBUFFREGUPD */ 0, /* JNLBUFFDBUPD */ 0, /* LOCKINCR2HIGH */ 0, /* LOCKIS */ 0, /* LDSPANGLOINCMP */ 0, /* MUFILRNDWNFL2 */ 0, /* MUINSTFROZEN */ 0, /* MUINSTUNFROZEN */ 0, /* GTMEISDIR */ 0, /* SPCLZMSG */ 0, /* MUNOTALLINTEG */ 0, /* BKUPRUNNING */ 0, /* MUSIZEINVARG */ 0, /* MUSIZEFAIL */ 0, /* SIDEEFFECTEVAL */ 0, /* CRYPTINIT2 */ 0, /* CRYPTDLNOOPEN2 */ 0, /* CRYPTBADCONFIG */ 0, /* DBCOLLREQ */ 0, /* SETEXTRENV */ 0, /* NOTALLDBRNDWN */ 0, /* TPRESTNESTERR */ 0, /* JNLFILRDOPN */ 0, /* SEQNUMSEARCHTIMEOUT */ 0, /* FTOKKEY */ 0, /* SEMID */ 0, /* JNLQIOSALVAGE */ 0, /* FAKENOSPCLEARED */ 0, /* MMFILETOOLARGE */ 0, /* BADZPEEKARG */ 0, /* BADZPEEKRANGE */ 0, /* BADZPEEKFMT */ 0, /* DBMBMINCFREFIXED */ 0, /* NULLENTRYREF */ 0, /* ZPEEKNORPLINFO */ 0, /* MMREGNOACCESS */ 0, /* MALLOCMAXUNIX */ 0, /* MALLOCMAXVMS */ 0, /* HOSTCONFLICT */ 0, /* GETADDRINFO */ 0, /* GETNAMEINFO */ 0, /* SOCKBIND */ 0, /* INSTFRZDEFER */ 0, /* REGOPENRETRY */ 0, /* REGOPENFAIL */ }; fis-gtm-V6.0-003/sr_i386/merrors_ctl.c0000666000032200000250000047222612201176214016253 0ustar librarygtc/**************************************************************** * * * Copyright 2001,2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "error.h" LITDEF err_msg merrors[] = { "ACK", "", 0, "BREAKZST", "Break instruction encountered during ZSTEP action", 0, "BADACCMTHD", "Invalid access method was specified, file not created", 0, "BADJPIPARAM", "!AD is not a legal parameter for $ZGETJPI()", 2, "BADSYIPARAM", "!AD is not a legal parameter for $ZGETSYI()", 2, "BITMAPSBAD", "Database bit maps are incorrect", 0, "BREAK", "Break instruction encountered", 0, "BREAKDEA", "Break instruction encountered during Device error action", 0, "BREAKZBA", "Break instruction encountered during ZBREAK action", 0, "STATCNT", "!AD:!_ Key cnt: !UL max subsc len: !UL max data len: !UL", 5, "BTFAIL", "The database block table is corrupt; error type !UL", 1, "MUPRECFLLCK", "Database file !AD is locked by MUPIP RECOVER. Could not secure access.", 2, "CMD", "Command expected but not found", 0, "COLON", "Colon (:) expected in this context", 0, "COMMA", "Comma expected in this context", 0, "COMMAORRPAREXP", "Comma or right parenthesis expected but not found", 0, "COMMENT", "Comment line. Placed zbreak at next executable line.", 0, "CTRAP", "Character trap $C(!UL) encountered", 1, "CTRLC", "CTRL_C encountered", 0, "CTRLY", "User interrupt encountered", 0, "DBCCERR", "Interlock instruction failure in critical mechanism for region !AD", 2, "DUPTOKEN", "Token 0x!16@XQ is duplicate in the journal file !AD for database !AD", 5, "DBJNLNOTMATCH", "Database !AD points to journal file name !AD but the journal file points to database file !AD", 6, "DBFILERR", "Error with database file !AD", 2, "DBNOTGDS", "!AD - Unrecognized database file format", 2, "DBOPNERR", "Error opening database file !AD", 2, "DBRDERR", "Cannot read database file !AD after opening", 2, "CCEDUMPNOW", "", 0, "DEVPARINAP", "Device parameter inappropriate to this command", 0, "RECORDSTAT", "!AD:!_ Key cnt: !UL max subsc len: !UL max data len: !UL max rec len: !UL", 6, "NOTGBL", "!_!AD!/!_!_!_\"^\" Expected", 2, "DEVPARPROT", "The protection specification is invalid", 0, "PREMATEOF", "Premature end of file detected", 0, "GVINVALID", "!_!AD!/!_!_!_Invalid global name", 2, "DEVPARTOOBIG", "String deviceparameter exceeds 255 character limit", 0, "DEVPARUNK", "Deviceparameter unknown", 0, "DEVPARVALREQ", "A value is required for this device parameter", 0, "DEVPARMNEG", "Deviceparameter must be a positive value", 0, "DSEBLKRDFAIL", "Failed attempt to read block", 0, "DSEFAIL", "DSE failed. Failure code: !AD.", 2, "NOTALLREPLON", "Replication state is not on for all regions", 0, "BADLKIPARAM", "!AD is not a legal parameter for $ZGETLKI()", 2, "JNLREADBOF", "Beginning of journal file encountered for !AD", 2, "DVIKEYBAD", "$ZGETDVI(\"!AD\",\"!AD\") contains an illegal keyword", 4, "ENQ", "", 0, "EQUAL", "Equal sign expected but not found", 0, "ERRORSUMMARY", "Errors occurred during compilation", 0, "ERRWEXC", "Error while processing exception string", 0, "ERRWIOEXC", "Error while processing I/O exception string", 0, "ERRWZBRK", "Error while processing ZBREAK action string", 0, "ERRWZTRAP", "Error while processing $ZTRAP", 0, "NUMUNXEOR", "!_!AD!/!_!_!_unexpected end of record in numeric subscript", 2, "EXPR", "Expression expected but not found", 0, "STRUNXEOR", "!_!AD!/!_!_!_unexpected end of record in string subscript", 2, "JNLEXTEND", "Journal file extension error for file !AD", 2, "FCHARMAXARGS", "Argument count of $CHAR function exceeded the maximum of 255", 0, "FCNSVNEXPECTED", "Function or special variable expected in this context", 0, "FNARGINC", "Format specifiers to $FNUMBER are incompatible: \"!AD\"", 2, "JNLACCESS", "Error accessing journal file !AD", 2, "TRANSNOSTART", "ZTCOMMIT(s) issued without corresponding ZTSTART(s)", 0, "FNUMARG", "$FNUMBER format specifier \"!AD\" contains an illegal character: \"!AD\"", 4, "FOROFLOW", "FOR commands nested more than !UL deep on a line", 1, "YDIRTSZ", "Size of YDIRT data too large", 0, "JNLSUCCESS", "!AD successful", 2, "GBLNAME", "Either an identifier or a left parenthesis is expected after a ^ in this context", 0, "GBLOFLOW", "Database segment is full", 0, "CORRUPT", "Corrupt input in Blk # !UL, Key #!UL; resuming with next global block", 2, "GTMCHECK", "Internal GT.M error--Report to your GT.M Support Channel", 0, "GVDATAFAIL", "Global variable $DATA function failed. Failure code: !AD.", 2, "EORNOTFND", "!_!AD!/!_!_!_End of record not found", 2, "GVGETFAIL", "Global variable retrieval failed. Failure code: !AD.", 2, "GVIS", "!_!_Global variable: !AD", 2, "GVKILLFAIL", "Global variable kill failed. Failure code: !AD.", 2, "GVNAKED", "Illegal naked global reference", 0, "GVNEXTARG", "Argument to global variable $NEXT must be subscripted", 0, "GVORDERFAIL", "Global variable $ORDER or $NEXT function failed. Failure code: !AD.", 2, "GVPUTFAIL", "Global variable put failed. Failure code: !AD.", 2, "PATTABSYNTAX", "Error in !AD at line !UL", 3, "GVSUBOFLOW", "Maximum combined length of subscripts exceeded", 0, "GVUNDEF", "Global variable undefined: !AD", 2, "TRANSNEST", "Maximum transaction nesting levels exceeded", 0, "INDEXTRACHARS", "Indirection string contains extra trailing characters", 0, "UNUSEDMSG260", "INDMAXNEST Last used in V6.0-000", 0, "INDRMAXLEN", "Maximum length !UL of an indirection argument was exceeded", 1, "INSFFBCNT", "Insufficient byte count quota left for requested operation", 0, "INTEGERRS", "Database integrity errors", 0, "INVCMD", "Invalid command keyword encountered", 0, "INVFCN", "Invalid function name", 0, "INVOBJ", "Cannot ZLINK object file due to unexpected format", 0, "INVSVN", "Invalid special variable name", 0, "IOEOF", "Attempt to read past an end-of-file", 0, "IONOTOPEN", "Attempt to USE an I/O device which has not been opened", 0, "MUPIPINFO", "!AD", 2, "IVTIME", "Invalid time specification: !AD", 2, "JOBFAIL", "JOB command failure", 0, "JOBLABOFF", "Label and offset not found in created process", 0, "JOBPARNOVAL", "This job parameter cannot take a value", 0, "JOBPARNUM", "The value of this job parameter must be an integer", 0, "JOBPARSTR", "The value of this job parameter must be a string", 0, "JOBPARUNK", "Job parameter unknown", 0, "JOBPARVALREQ", "A value is required for this job parameter", 0, "JUSTFRACT", "Fraction specifier to $JUSTIFY cannot be negative", 0, "KEY2BIG", "Key size (!UL) is greater than maximum (!UL) for region: !AD", 4, "LABELEXPECTED", "Label expected in this context", 0, "LABELMISSING", "Label referenced but not defined: !AD", 2, "LABELUNKNOWN", "Label referenced but not defined", 0, "DIVZERO", "Attempt to divide by zero", 0, "LKNAMEXPECTED", "An identifier is expected after a ^ in this context", 0, "JNLRDERR", "Error reading journal file !AD. Unable to initialize.", 2, "LOADRUNNING", "Cannot ZLINK an active routine !AD", 2, "LPARENMISSING", "Left parenthesis expected", 0, "LSEXPECTED", "A line separator is expected here", 0, "LVORDERARG", "Argument to local variable $NEXT must be subscripted", 0, "MAXFORARGS", "Maximum number of arguments to a single FOR command exceeded", 0, "TRANSMINUS", "Negative numbers not allowed with ZTCOMMIT", 0, "MAXNRSUBSCRIPTS", "Maximum number of subscripts exceeded", 0, "MAXSTRLEN", "Maximum string length exceeded", 0, "JNLDBERR", "Journal file !AD does not correspond to database file !AD", 4, "JNLFILOPN", "Error opening journal file !AD for database file !AD", 4, "MBXRDONLY", "Mailbox is read only, cannot write to it", 0, "JNLINVALID", "!AD is not a valid journal file !/ for database file: !AD", 4, "MBXWRTONLY", "Mailbox is write only, cannot read from it", 0, "MEMORY", "Central memory exhausted during request for !UJ bytes from 0x!XJ", 2, "MTBLKTOOBIG", "Magtape BLOCK_SIZE exceeds maximum size allowed", 0, "MTBLKTOOSM", "Magtape BLOCK_SIZE is less than !UL bytes", 1, "MTFIXRECSZ", "BLOCK_SIZE !UL must be multiple of fixed record size !UL", 2, "MTIS", "Magnetic tape: !AD", 2, "MTRDBADBLK", "Block read too small, contained only !UL bytes, block size = !UL", 2, "MTRDONLY", "Cannot write to a READONLY magtape", 0, "MTRDTHENWRT", "Attempt to read after a write to a magtape", 0, "MTRECGTRBLK", "Magtape record size cannot exceed block size", 0, "MTRECTOOBIG", "Magtape record size exceeds maximum allowed", 0, "MTRECTOOSM", "Magtape record size is too small for record type", 0, "JNLTMQUAL3", "Time qualifier BEFORE_TIME=\"!AZ\" is less than the journal file(s) minimum timestamp=\"!AZ\"", 2, "MULTLAB", "This label has been previously defined", 0, "BLKCNT", "Last LOAD Block/RMS Record number: !UL", 1, "CCEDUMPOFF", "", 0, "NOPLACE", "Line specified in a ZBREAK cannot be found", 0, "JNLCLOSE", "Error closing journal file !AD", 2, "NOTPRINCIO", "Output currently directed to device !AD", 2, "NOTTOEOFONPUT", "Not positioned to EOF on write (sequential organization only)", 0, "NOZBRK", "No zbreak at that location", 0, "NULSUBSC", "Null subscripts are not allowed for region: !AD", 2, "NUMOFLOW", "Numeric overflow", 0, "PARFILSPC", "Parameter: !AD file specification: !AD", 4, "PATCLASS", "Illegal character class for pattern code", 0, "PATCODE", "Illegal syntax for pattern", 0, "PATLIT", "Illegal character or unbalanced quotes for pattern literal", 0, "PATMAXLEN", "Pattern code exceeds maximum length", 0, "LPARENREQD", "!_!AD!/!_!_!_Left parenthesis expected", 2, "PATUPPERLIM", "Pattern code upper limit is less than lower limit", 0, "PCONDEXPECTED", "Post-conditional expression expected but not found", 0, "PRCNAMLEN", "Process name !AD length is greater than !SL", 3, "RANDARGNEG", "Random number generator argument must be greater than or equal to one", 0, "DBPRIVERR", "No privilege for attempted update operation for file: !AD", 2, "REC2BIG", "Record size (!UL) is greater than maximum (!UL) for region: !AD", 4, "RHMISSING", "Right-hand side of expression expected", 0, "DEVICEREADONLY", "Cannot write to read-only device", 0, "COLLDATAEXISTS", "Collation type cannot be changed while data exists", 0, "ROUTINEUNKNOWN", "Routine could not be found", 0, "RPARENMISSING", "Right parenthesis expected", 0, "RTNNAME", "Routine name expected here", 0, "VIEWGVN", "Invalid global key name used with VIEW/$VIEW(): !AD", 2, "RTSLOC", "!_!_At M source location !AD", 2, "RWARG", "This is not a legal argument for a READ command", 0, "RWFORMAT", "A valid format expression (!!, #, or ?expr) expected here", 0, "JNLWRTDEFER", "Journal write start deferred", 0, "SELECTFALSE", "No argument to $SELECT was true", 0, "SPOREOL", "Either a space or an end-of-line was expected but not found", 0, "SRCLIN", "!_!AD!/!_!AD", 4, "SRCLOC", "!_!_At column !UL, line !UL, source module !AD", 4, "SRCLOCUNKNOWN", "!_!_M source location unknown", 0, "STACKCRIT", "Stack space critical", 0, "STACKOFLOW", "Stack overflow", 0, "STACKUNDERFLO", "Stack underflow", 0, "STRINGOFLOW", "String pool overflow", 0, "SVNOSET", "Cannot SET this special variable", 0, "VIEWFN", "View parameter is not valid with $VIEW()", 0, "TERMASTQUOTA", "Process AST quota exceeded, cannot open terminal", 0, "TEXTARG", "Invalid argument to $TEXT function", 0, "TMPSTOREMAX", "Maximum space for temporary values exceeded", 0, "VIEWCMD", "View parameter is not valid with VIEW command", 0, "JNI", "!AD", 2, "TXTSRCFMT", "$TEXT encountered an invalid source program file format", 0, "UIDMSG", "Unidentified message received", 0, "UIDSND", "Unidentified sender PID", 0, "UNDEF", "Undefined local variable: !AD", 2, "UNIMPLOP", "Unimplemented construct encountered", 0, "VAREXPECTED", "Variable expected in this context", 0, "VARRECBLKSZ", "Blocksize must be at least record size + 4 bytes", 0, "MAXARGCNT", "Maximum number of arguments !UL exceeded", 1, "GTMSECSHRSEMGET", "semget error errno = !UL", 1, "VIEWARGCNT", "View parameter !AD has inappropriate number of subparameters", 2, "GTMSECSHRDMNSTARTED", "gtmsecshr daemon started (key: 0x!XL) for version !AD from !AD", 5, "ZATTACHERR", "Error attaching to \"!AD\"", 2, "ZDATEFMT", "$ZDATE format string contains invalid character", 0, "ZEDFILSPEC", "Illegal ZEDIT file specification: !AD", 2, "ZFILENMTOOLONG", "!AD is longer than 255 characters", 2, "ZFILKEYBAD", "!AD is not a legal keyword for $ZFILE()", 2, "ZFILNMBAD", "!AD is not a legal file name", 2, "ZGOTOLTZERO", "Cannot ZGOTO a level less than zero", 0, "ZGOTOTOOBIG", "Cannot ZGOTO a level greater than present level", 0, "ZLINKFILE", "Error while zlinking \"!AD\"", 2, "ZPARSETYPE", "Illegal TYPE argument to $ZPARSE(): !AD", 2, "ZPARSFLDBAD", "Illegal $ZPARSE() field parameter: !AD", 2, "ZPIDBADARG", "The tvexpr must be FALSE if last $ZPID() not found", 0, "ZPRIVARGBAD", "!AD is not a legal privilege for $ZPRIV()", 2, "ZPRIVSYNTAXERR", "Privilege string cannot end with a comma", 0, "ZPRTLABNOTFND", "Label not found in routine", 0, "VIEWAMBIG", "View parameter !AD is ambiguous", 2, "VIEWNOTFOUND", "View parameter !AD not valid", 2, "ZSETPRVARGBAD", "!AD is not a legal privilege for $ZSETPRIV()", 2, "INVSPECREC", "Invalid global modifier record", 0, "ZSETPRVSYNTAX", "$ZSETPRIV() privileges string cannot end with a comma", 0, "ZSRCHSTRMCT", "Search stream identifier out of range", 0, "VERSION", "Version mismatch - This program must be recompiled", 0, "MUNOTALLSEC", "WARNING: not all global sections accessed were successfully rundown", 0, "MUSECDEL", "Section !AD deleted", 2, "MUSECNOTDEL", "Section !AD not deleted", 2, "RPARENREQD", "!_!AD!/!_!_!_Right parenthesis expected", 2, "ZGBLDIRACC", "Cannot access global directory !AD!AD!AD.", 6, "GVNAKEDEXTNM", "Cannot reference different global directory in a naked reference", 0, "EXTGBLDEL", "Invalid delimiter for extended global syntax", 0, "DSEWCINITCON", "No action taken, enter YES at CONFIRMATION prompt to initialize global buffers", 0, "LASTFILCMPLD", "The file currently being compiled is !AD", 2, "NOEXCNOZTRAP", "Neither an exception nor a Ztrap is specified", 0, "UNSDCLASS", "Unsupported descriptor class", 0, "UNSDDTYPE", "Unsupported descriptor data type", 0, "ZCUNKTYPE", "External call: Unknown argument type", 0, "ZCUNKMECH", "External call: Unknown parameter-passing mechanism", 0, "ZCUNKQUAL", "External call: Unknown input qualifier", 0, "JNLDBTNNOMATCH", "Journal file !AD has !AD transaction number [0x!16@XQ], but database !AD has current transaction number [0x!16@XQ] and journal end transaction number [0x!16@XQ]", 9, "ZCALLTABLE", "External call Table format error", 0, "ZCARGMSMTCH", "External call: Actual argument count, !UL, is greater than formal argument count, !UL", 2, "ZCCONMSMTCH", "External call: Too many input arguments", 0, "ZCOPT0", "External call: Qualifier OPTIONAL_0 can be used only with mechanisms REFERENCE or DESCRIPTOR", 0, "ZCSTATUS", "External call: Unsuccessful return status", 0, "ZCUSRRTN", "External call: Run-time error in user routine", 0, "ZCPOSOVR", "External call: Invalid overlapping of arguments in table position !UL", 1, "ZCINPUTREQ", "External call: Required input argument missing", 0, "JNLTNOUTOFSEQ", "End transaction [0x!16@XQ] of journal !AD different from Begin transaction [0x!16@XQ] of next generation journal !AD", 6, "ACTRANGE", "Alternate Collating Type !UL is out of range", 1, "ZCCONVERT", "External call: error converting output argument", 0, "ZCRTENOTF", "External call routine !AD not found", 2, "GVRUNDOWN", "Error during global database rundown", 0, "LKRUNDOWN", "Error during lock database rundown", 0, "IORUNDOWN", "Error during image rundown", 0, "FILENOTFND", "File !AD not found", 2, "MUFILRNDWNFL", "File !AD rundown failed", 2, "JNLTMQUAL1", "Time qualifier BEFORE_TIME=\"!AZ\" is less than SINCE_TIME=\"!AZ\"", 2, "FORCEDHALT", "Image HALTed by MUPIP STOP", 0, "LOADEOF", "Load error: EOF reached prior to BEGIN record !UL. No records loaded.", 1, "WILLEXPIRE", "This copy of GT.M will expire within one week", 0, "LOADEDBG", "Load error: END smaller than BEGIN. No records loaded.", 0, "LABELONLY", "Routine !AD was compiled for label-only entry", 2, "MUREORGFAIL", "MUPIP REORG failed. Failure code: !AD.", 2, "GVZPREVFAIL", "Global variable $ZPREVIOUS function failed. Failure code: !AD.", 2, "MULTFORMPARM", "This formal parameter is multiply defined", 0, "QUITARGUSE", "Quit cannot take an argument in this context", 0, "NAMEEXPECTED", "A local variable name is expected in this context", 0, "FALLINTOFLST", "Fall-through to a label with formallist is not allowed", 0, "NOTEXTRINSIC", "Quit does not return to an extrinsic function: argument not allowed", 0, "GTMSECSHRREMSEMFAIL", "error removing semaphore errno = !UL", 1, "FMLLSTMISSING", "The formal list is absent from a label called with an actual list: !AD", 2, "ACTLSTTOOLONG", "More actual parameters than formal parameters: !AD", 2, "ACTOFFSET", "Actuallist not allowed with offset", 0, "MAXACTARG", "Maximum number of actual arguments exceeded", 0, "GTMSECSHRREMSEM", "[client pid !UL] Semaphore (!UL) removed", 2, "JNLTMQUAL2", "Time qualifier LOOKBACK_TIME=\"!AZ\" is later than SINCE_TIME=\"!AZ\"", 2, "GDINVALID", "Unrecognized Global Directory file format: !AD, expected label: !AD, found: !AD", 6, "ASSERT", "Assert failed in !AD line !UL for expression (!AD)", 5, "MUFILRNDWNSUC", "File !AD successfully rundown", 2, "LOADEDSZ", "Load error: END too small. No records loaded.", 0, "QUITARGLST", "Quit cannot take a list of arguments", 0, "QUITARGREQD", "Quit from an extrinsic must have an argument", 0, "CRITRESET", "The critical section crash count for region !AD has been incremented", 2, "UNKNOWNFOREX", "Process halted by a forced exit from a source other than MUPIP", 0, "FSEXP", "File specification expected but not found", 0, "WILDCARD", "Wild cards are prohibited: !AD", 2, "DIRONLY", "Directories only are allowed in file specs: !AD", 2, "FILEPARSE", "Error parsing file specification: !AD", 2, "QUALEXP", "Qualifier expected but not found", 0, "BADQUAL", "Unrecognized qualifier: !AD", 2, "QUALVAL", "Qualifier value required but not found", 0, "ZROSYNTAX", "$ZROUTINES syntax error: !AD", 2, "COMPILEQUALS", "Error in compiler qualifiers: !AD", 2, "ZLNOOBJECT", "No object module was produced", 0, "ZLMODULE", "Object file name does not match module name: !AD", 2, "DBBLEVMX", "!AD Block level higher than maximum", 2, "DBBLEVMN", "!AD Block level less than zero", 2, "DBBSIZMN", "!AD Block too small", 2, "DBBSIZMX", "!AD Block larger than file block size", 2, "DBRSIZMN", "!AD Physical record too small", 2, "DBRSIZMX", "!AD Physical record too large", 2, "DBCMPNZRO", "!AD First record of block has nonzero compression count", 2, "DBSTARSIZ", "!AD Star record has wrong size", 2, "DBSTARCMP", "!AD Star record has nonzero compression count", 2, "DBCMPMX", "!AD Record compression count is too large", 2, "DBKEYMX", "!AD Key too long", 2, "DBKEYMN", "!AD Key too short", 2, "DBCMPBAD", "!AD Compression count not maximal", 2, "DBKEYORD", "!AD Keys out of order", 2, "DBPTRNOTPOS", "!AD Block pointer negative", 2, "DBPTRMX", "!AD Block pointer larger than file maximum", 2, "DBPTRMAP", "!AD Block pointer is a bit map block number", 2, "IFBADPARM", "External Interface Bad Parameter", 0, "IFNOTINIT", "External Interface must first call GTM$INIT or M routine", 0, "GTMSECSHRSOCKET", "!AD - !UL : Error initializing gtmsecshr socket", 3, "LOADBGSZ", "Load error: BEGIN too small. No records loaded.", 0, "LOADFMT", "Load error: invalid format type. Must be ZWR, GO, BINARY, or GOQ.", 0, "LOADFILERR", "Error with load file !AD", 2, "NOREGION", "REGION not found: !AD", 2, "PATLOAD", "Error loading pattern file !AD", 2, "EXTRACTFILERR", "Error with extract file !AD", 2, "FREEZE", "Region: !AD is already frozen", 2, "NOSELECT", "None of the selected variables exist -- halting", 0, "EXTRFAIL", "Extract failed for the global ^!AD. MUPIP INTEG should be run.", 2, "LDBINFMT", "Corrupt binary format header information", 0, "NOPREVLINK", "Journal file !AD has a null previous link", 2, "CCEDUMPON", "", 0, "CCEDMPQUALREQ", "A qualifier (DB,[NO]ON, or NOW) is required with the DUMP command", 0, "CCEDBDUMP", "Section !AD dumped", 2, "CCEDBNODUMP", "Section !AD not dumped; status = ", 2, "CCPMBX", "Error accessing Cluster Control Program Mailbox", 0, "REQRUNDOWN", "Error accessing database !AD. Must be rundown on cluster node !AD.", 4, "CCPINTQUE", "Interlock failure accessing Cluster Control Program queue", 0, "CCPBADMSG", "Invalid message code received by Cluster Control Program", 0, "CNOTONSYS", "Command is not supported by this operating system", 0, "CCPNAME", "Error setting the Cluster Control Program process name", 0, "CCPNOTFND", "The Cluster Control Program is not responding", 0, "OPRCCPSTOP", "The Cluster Control Program has been halted by an operator stop request", 0, "SELECTSYNTAX", "Argument to !AD clause is not valid", 2, "LOADABORT", "Aborting load at record !UL", 1, "FNOTONSYS", "Function or special variable is not supported by this operating system", 0, "AMBISYIPARAM", "Parameter !AD is ambiguous to $ZGETSYI()", 2, "PREVJNLNOEOF", "A previous generation journal file !AD does not have valid EOF", 2, "LKSECINIT", "Error creating lock section for database !AD", 2, "MTDOSLAB", "Tape label is not in valid DOS-11 format", 0, "MTDOSFOR", "Use of DOS-11 labels requires stream format", 0, "MTINVLAB", "Invalid label type specified in magtape OPEN", 0, "TXTSRCMAT", "M object module and source file do not match", 0, "CCENOGROUP", "CCE does not have GROUP privilege. Information may be incomplete.", 0, "BADDBVER", "Incorrect database version: !AD", 2, "LINKVERSION", "This image must be relinked with the current version of GT.M", 0, "TOTALBLKMAX", "Extension exceeds maximum total blocks. Not extending.", 0, "LOADCTRLY", "User interrupt encountered during load. Load halting.", 0, "CLSTCONFLICT", "Cluster conflict opening database file !AD; could not secure access. Already open on node !AD.", 4, "SRCNAM", "in source module !AD", 2, "LCKGONE", "Lock removed: !AD", 2, "SUB2LONG", "Subscript invalid, too long", 0, "EXTRACTCTRLY", "User interrupt encountered during extract -- halting", 0, "CCENOWORLD", "CCE does not have WORLD privilege. Information may be incomplete.", 0, "GVQUERYFAIL", "Global variable $QUERY function failed. Failure code: !AD.", 2, "LCKSCANCELLED", "Error on remote node holding locks or zallocates. All locks and zallocates cancelled.", 0, "INVNETFILNM", "Invalid file name following node designation in global directory", 0, "NETDBOPNERR", "Error while attempting to open database across net", 0, "BADSRVRNETMSG", "Invalid message received from GT.CM server", 0, "BADGTMNETMSG", "Invalid message sent to GT.CM server, type: 0x!XL", 1, "SERVERERR", "Severe error on server: !AD", 2, "NETFAIL", "Failure of Net operation", 0, "NETLCKFAIL", "Lock operation across Net failed", 0, "TTINVFILTER", "Invalid FILTER argument", 0, "MTANSILAB", "Tape label is not in valid ANSI format", 0, "MTANSIFOR", "Use of ANSI labels does not allow stream format", 0, "BADTRNPARAM", "!AD is not a legal parameter to $ZTRNLNM", 2, "DSEONLYBGMM", "!AD is supported only for BG/MM access methods", 2, "DSEINVLCLUSFN", "Specified function is invalid for clustered databases", 0, "RDFLTOOSHORT", "Length specified for fixed length read less than or equal to zero", 0, "TIMRBADVAL", "Bad value specified. Timer not changed.", 0, "CCENOSYSLCK", "CCE does not have SYSLCK privilege. Information may be incomplete.", 0, "CCPGRP", "Error with the Cluster Control Program's group number", 0, "UNSOLCNTERR", "An unsolicited error message has been received from the network", 0, "BACKUPCTRL", "Control Y or control C encountered during backup, aborting backup", 0, "NOCCPPID", "Cannot find CCP process id", 0, "CCPJNLOPNERR", "Error opening journal file. Database not opened.", 0, "LCKSGONE", "Locks selected for deletion removed", 0, "ZLKIDBADARG", "The tvexpr must be FALSE if last ZLKID not found", 0, "DBFILOPERR", "Error doing database I/O to region !AD", 2, "CCERDERR", "Error reading from database file !AD", 2, "CCEDBCL", "Database file !AD is clustered", 2, "CCEDBNTCL", "Database file !AD is not clustered", 2, "CCEWRTERR", "Error writing to database file !AD", 2, "CCEBADFN", "Filename error", 0, "CCERDTIMOUT", "Read timeout, CCP has not responded to request", 0, "CCPSIGCONT", "CCP non fatal error at pc 0x!XJ. Continuing operation.", 1, "CCEBGONLY", "Only BG databases can be clustered", 0, "CCENOCCP", "The cluster control program is not running on this node", 0, "CCECCPPID", "The cluster control program has PID 0x!XL", 1, "CCECLSTPRCS", "!UL processes are accessing clustered database files", 1, "ZSHOWBADFUNC", "An illegal function was specified for ZSHOW", 0, "NOTALLJNLEN", "Journaling not enabled and on for all regions", 0, "ZSHOWGLOSMALL", "Global output variable is too small for ZSHOW output", 0, "NOLBRSRC", "Object libraries cannot have SRC paths associated", 0, "INVZSTEP", "Invalid ZSTEP qualifier", 0, "ZSTEPARG", "ZSTEP argument expected", 0, "INVSTRLEN", "Invalid string length !UL: max !UL", 2, "RECCNT", "Last LOAD record number: !UL", 1, "TEXT", "!AD", 2, "ZWRSPONE", "Subscript patterns in ZWRITE are atomic; Invalid delimiter", 0, "FILEDEL", "File !AD successfully deleted", 2, "JNLBADLABEL", "Journal file !AD does not have a GT.M Journal File Label", 2, "JNLREADEOF", "End of journal file encountered for !AD", 2, "JNLRECFMT", "Journal file record format error encountered", 0, "BLKTOODEEP", "Block level too deep", 0, "NESTFORMP", "Formal parameter list cannot be combined with nested line", 0, "BINHDR", "!AD!/!/Date: !AD!/Time: !AD!/Extract Region Characteristics!/!_Blk Size: !AD!/!_Rec Size: !AD!/!_Key Size: !AD!/!_Std Null Coll: !AD!/!AD!/", 16, "GOQPREC", "Numeric precision in key error: Blk #!UL, Key #!UL. Record not loaded.", 2, "LDGOQFMT", "Corrupt GOQ format header information!/", 0, "BEGINST", "Beginning LOAD at record number: !UL", 1, "INVMVXSZ", "Invalid block size for GOQ load format", 0, "JNLWRTNOWWRTR", "Journal writer attempting another write", 0, "GTMSECSHRSHMCONCPROC", "More than one process attached to Shared memory segment (!UL) not removed (!UL)", 2, "JNLINVALLOC", "Journal file allocation !UL is not within the valid range of !UL to !UL. Journal file not created.", 3, "JNLINVEXT", "Journal file extension !UL is greater than the maximum allowed size of !UL. Journal file not created.", 2, "MUPCLIERR", "Action not taken due to CLI errors", 0, "JNLTMQUAL4", "Time qualifier BEFORE_TIME=\"!AZ\" is less than AFTER_TIME=\"!AZ\"", 2, "GTMSECSHRREMSHM", "[client pid !UL] Shared memory segment (!UL) removed, nattch = !UL", 3, "GTMSECSHRREMFILE", "[client pid !UL] File (!AD) removed", 3, "MUNODBNAME", "A database name or the region qualifier must be specified", 0, "FILECREATE", "!AD file !AD created", 4, "FILENOTCREATE", "!AD file !AD not created", 4, "JNLPROCSTUCK", "Journal file writes blocked by process !UL", 1, "INVGLOBALQUAL", "Error in GLOBAL qualifier : Parse error at offset !UL in !AD", 3, "COLLARGLONG", "Collation sequence !UL does not contain routines for long strings", 1, "NOPINI", "PINI journal record expected but not found in journal file !AD at offset [0x!XL]", 3, "DBNOCRE", "Not all specified database files, or their associated journal files were created", 0, "JNLSPACELOW", "Journal file !AD nearing maximum size, !UL blocks to go", 3, "DBCOMMITCLNUP", "Pid !UL [0x!XL] handled error (code = !UL) during commit of !AZ transaction in database file !AD", 6, "BFRQUALREQ", "The [NO]BEFORE qualifier is required for this command", 0, "REQDVIEWPARM", "Required View parameter is missing", 0, "COLLFNMISSING", "Routine !AD is not found for collation sequence !UL", 3, "JNLACTINCMPLT", "Mupip journal action might be incomplete", 0, "NCTCOLLDIFF", "Source and destination for MERGE cannot have different numerical collation type", 0, "DLRCUNXEOR", "!_!AD!/!_!_!_unexpected end of record in $CHAR()/$ZCHAR() subscript", 2, "DLRCTOOBIG", "!_!AD!/!_!_!_!AD value cannot be greater than 255", 4, "WCERRNOTCHG", "Not all specified database files were changed", 0, "WCWRNNOTCHG", "Not all specified database files were changed", 0, "ZCWRONGDESC", "A string longer than 65535 is passed via 32-bit descriptor", 0, "MUTNWARN", "Database file !AD has 0x!16@XQ more transactions to go before reaching the transaction number limit (0x!16@XQ). Renew database with MUPIP INTEG TN_RESET", 4, "GTMSECSHRUPDDBHDR", "[client pid !UL] database fileheader (!AD) updated !AD", 5, "LCKSTIMOUT", "DAL timed lock request expired", 0, "CTLMNEMAXLEN", "The maximum length of a control mnemonic has been exceeded", 0, "CTLMNEXPECTED", "Control mnemonic is expected in this context", 0, "USRIOINIT", "User-defined device driver not successfully initialized", 0, "CRITSEMFAIL", "Error with semaphores for region !AD", 2, "TERMWRITE", "Error writing to terminal", 0, "COLLTYPVERSION", "Collation type !UL, version !UL mismatch", 2, "LVNULLSUBS", "Null subscripts not allowed in local variables", 0, "GVREPLERR", "Error replicating global in region !AD", 2, "MTIOERR", "I/O Error with magnetic tape device !AD", 2, "RMWIDTHPOS", "File record size or width must be greater than zero", 0, "OFFSETINV", "Entry point !AD+!SL not valid", 3, "JOBPARTOOLONG", "Total parameter length is too long for job command", 0, "JOBARGMISSING", "Missing job argument !UL - can't skip non-trailing arguments to a JOB command in OpenVMS editions", 1, "RUNPARAMERR", "Error accessing parameter for run command", 0, "FNNAMENEG", "Depth argument to $NAME cannot be negative", 0, "ORDER2", "Invalid second argument to $ORDER. Must be -1 or 1.", 0, "MUNOUPGRD", "Database not upgraded because of preceding errors", 0, "REORGCTRLY", "User interrupt encountered during database reorg -- halting", 0, "TSTRTPARM", "Error parsing TSTART qualifier", 0, "TRIGNAMENF", "Trigger name !AD not found with the current default global directory", 2, "TRIGZBREAKREM", "ZBREAK in trigger !AD removed due to trigger being reloaded", 2, "TLVLZERO", "Transaction is not in progress", 0, "TRESTNOT", "Cannot TRESTART, transaction is not restartable", 0, "TPLOCK", "Cannot release lock(s) held prior to current TSTART", 0, "TPQUIT", "Cannot QUIT out of a routine with an active transaction", 0, "TPFAIL", "Transaction COMMIT failed. Failure code: !AD.", 2, "TPRETRY", "Restart transaction from non-concurrency DB failure", 0, "TPTOODEEP", "$TLEVEL cannot exceed 127", 0, "ZDEFACTIVE", "ZDEFER already active", 0, "ZDEFOFLOW", "ZDEFER Buffer overflow to node !AD", 2, "MUPRESTERR", "MUPIP restore aborted due to preceding errors", 0, "MUBCKNODIR", "MUPIP backup aborted due to error in output directory", 0, "TRANS2BIG", "Transaction exceeded available buffer space for region !AD", 2, "INVBITLEN", "Invalid size of the bit string", 0, "INVBITSTR", "Invalid bit string", 0, "INVBITPOS", "Invalid position in the bit string", 0, "PARNORMAL", "Parse successful", 0, "PARBUFSM", "Parse buffer too small", 0, "RMWIDTHTOOBIG", "File record size or width too big", 0, "PATTABNOTFND", "Pattern table !AD not found", 2, "OBJFILERR", "Error with object file I/O on file !AD", 2, "SRCFILERR", "Error with source file I/O on file !AD", 2, "NEGFRACPWR", "Invalid operation: fractional power of negative number", 0, "MTNOSKIP", "SKIP operation not supported on this device", 0, "CETOOMANY", "Too many compiler escape substitutions in a single statement", 0, "CEUSRERROR", "Compiler escape user routine returned error code !UL", 1, "CEBIGSKIP", "Compiler escape user routine skip count is too large", 0, "CETOOLONG", "Compiler escape substitution exceeds maximum line size", 0, "CENOINDIR", "Indirection type information not available for compiler escape feature", 0, "COLLATIONUNDEF", "Collation type !UL is not defined", 1, "RBWRNNOTCHG", "Not all specified database files were changed", 0, "GTMSECSHRSRVF", "!AD - !UL : Attempt to service request failed (retry = !UL)", 4, "FREEZECTRL", "Control Y or control C encountered during attempt to freeze the database. Aborting freeze.", 0, "JNLFLUSH", "Error flushing journal buffers to journal file !AD", 2, "CCPSIGDMP", "CCP non fatal dump, continuing operation. Report to your GT.M Support Channel.", 0, "NOPRINCIO", "Unable to write to principal device", 0, "INVPORTSPEC", "Invalid port specification", 0, "INVADDRSPEC", "Invalid IP address specification", 0, "SOCKPARMREQ", "Socket device parameter is required for TCP open", 0, "IPADDRREQ", "Active connection requires IP address", 0, "SOCKWAIT", "Error waiting for socket connection", 0, "SOCKACPT", "Error accepting socket connection", 0, "SOCKINIT", "Error initializing TCP socket: (errno == !UL) !AD", 3, "OPENCONN", "Error opening TCP connection", 0, "DEVNOTIMP", "!AD device not implemented on in this environment", 2, "JNLEXTR", "Error writing journal extract file: !AD", 2, "DBREMOTE", "Database region !AD is remote; perform maintenance on the server node", 2, "JNLREQUIRED", "Journaling is required for clustered operation with file !AD", 2, "TPMIXUP", "!AZ transaction cannot be started within !AZ transaction", 2, "HTOFLOW", "Hash table overflow: Failed to allocate !UL elements", 1, "RMNOBIGRECORD", "File record size requires BIGRECORD parameter", 0, "DBBMSIZE", "!AD Bit map has incorrect size", 2, "DBBMBARE", "!AD Bit map does not protect itself", 2, "DBBMINV", "!AD Bit map contains an invalid pattern", 2, "DBBMMSTR", "!AD Bit map does not match master map", 2, "DBROOTBURN", "!AD Root block has data level", 2, "REPLSTATEERR", "Replication state cannot be changed to the specified value for database file !AD", 2, "VMSMEMORY", "Central memory exhausted during request for !UL bytes from 0x!XJ - check page file quota and page file size", 2, "DBDIRTSUBSC", "!AD Directory tree block contains non name-level entries", 2, "TIMEROVFL", "Timer overflow; interval probably too large", 0, "GTMASSERT", "!AD - Assert failed !AD line !UL", 5, "DBFHEADERR4", "Database file !AD: control problem: !AD was 0x!XL expecting 0x!XL", 6, "DBADDRANGE", "Database file !AD, element location 0x!XJ: blk = 0x!XL: control 0x!XJ was outside !AD range 0x!XJ to 0x!XJ", 9, "DBQUELINK", "Database file !AD, element location 0x!XJ: blk = 0x!XL: control !AD queue problem: was 0x!XJ, expecting 0x!XJ", 8, "DBCRERR", "Database file !AD, cr location 0x!XJ blk = 0x!XL error: !AD was 0x!XL, expecting 0x!XL -- called from module !AD at line !UL", 11, "MUSTANDALONE", "Could not get exclusive access to !AD", 2, "MUNOACTION", "MUPIP unable to perform requested action", 0, "RMBIGSHARE", "File with BIGRECORD specified may only be shared if READONLY", 0, "TPRESTART", "Database !AD; code: !AD; blk: 0x!XL in glbl: ^!AD; pvtmods: !UL, blkmods: !UL, blklvl: !UL, type: !UL, readset: !UL, writeset: !UL, local_tn: 0x!16@XQ", 14, "SOCKWRITE", "Write to a TCP/IP socket failed", 0, "DBCNTRLERR", "Database file !AD: control error suspected but not found", 2, "NOTERMENV", "Environment variable TERM not set. Assuming \"unknown.\"", 0, "NOTERMENTRY", "TERM = \"!AD\" has no \"terminfo\" entry. Possible terminal handling problems.", 2, "NOTERMINFODB", "No \"terminfo\" database. Terminal handling problems likely.", 0, "INVACCMETHOD", "Invalid access method", 0, "JNLOPNERR", "Error opening journal file !AD!/ for database !AD", 4, "JNLRECTYPE", "Journal record type does not match expected type", 0, "JNLTRANSGTR", "Transaction number in journal is greater than in database", 0, "JNLTRANSLSS", "Transaction number in journal is less than in database", 0, "JNLWRERR", "Error writing journal file !AD. Unable to update header.", 2, "FILEIDMATCH", "Saved File ID does not match the current ID - the file appears to have been moved", 0, "EXTSRCLIN", "!_!AD!/!_!AD", 4, "EXTSRCLOC", "!_!_At column !UL, line !UL, source module !AD", 4, "BIGNOACL", "Existing file found when BIGRECORD specified with UDF format but no GT.M ACE, perhaps lost during COPY", 0, "ERRCALL", "Error called from !AD line !UL", 3, "ZCCTENV", "Environmental variable for external package !AD not set", 2, "ZCCTOPN", "Unable to open external call table: !AD", 2, "ZCCTNULLF", "External call table contains no records: !AD", 2, "ZCUNAVAIL", "Package, !AD unavailable", 2, "ZCENTNAME", "No entry name found in external call table", 0, "ZCCOLON", "Colon expected but not found", 0, "ZCRTNTYP", "Unknown return type", 0, "ZCRCALLNAME", "Routine name expected but not found", 0, "ZCRPARMNAME", "Parameter name expected but not found", 0, "ZCUNTYPE", "Unknown type encountered", 0, "ZCMLTSTATUS", "Multiple entries of xc_status in a single entry in external call table", 0, "ZCSTATUSRET", "External call returned error status", 0, "ZCMAXPARAM", "Exceeded maximum number of external call parameters", 0, "ZCCSQRBR", "Closing Square bracket expected", 0, "ZCPREALLNUMEX", "Pre-allocation value should be a decimal number", 0, "ZCPREALLVALPAR", "Pre-allocation allowed only for variables passed by reference", 0, "VERMISMATCH", "Attempt to access !AD with version !AD, while already using !AD", 6, "JNLCNTRL", "Journal control unsynchronized for !AD.", 2, "TRIGNAMBAD", "Trigger initialization failed. Error while processing ^#t(\"!AD\",!AD)", 4, "BUFRDTIMEOUT", "Pid [0x!XL] timed out waiting for buffered read of blk [0x!XL] into cr [0x!XL] by process [0x!XL] to complete in database file !AD", 6, "INVALIDRIP", "Invalid read-in-progress field in Cache Record. Resetting and continuing. Region: !AD.", 2, "BLKSIZ512", "Block size !UL rounds to !UL", 2, "MUTEXERR", "Mutual Exclusion subsystem failure", 0, "JNLVSIZE", "Journal File !AD has incorrect virtual_filesize !UL. Allocation : !UL, Extension : !UL, Filesize : !UL, File system block size : !UL", 7, "MUTEXLCKALERT", "Mutual Exclusion subsystem ALERT - lock attempt threshold crossed for region !AD. Process !UL is in crit cycle !UL.", 4, "MUTEXFRCDTERM", "Mutual Exclusion subsystem detected forced termination of process !UL. Crit salvaged from region !AD.", 3, "GTMSECSHR", "!UL : Error during gtmsecshr operation", 1, "GTMSECSHRSRVFID", "!AD: !UL - Attempt to service request failed.!/ client id: !UL, mesg type: !UL, mesg data: !UL", 6, "GTMSECSHRSRVFIL", "!AD: !UL - Attempt to service request failed.!/ client id: !UL, mesg type: !UL!/file: !AD", 7, "FREEBLKSLOW", "Only !UL free blocks left out of !UL total blocks for !AD", 4, "PROTNOTSUP", "Protocol !AD not supported", 2, "DELIMSIZNA", "Delimiter size is not appropriate", 0, "INVCTLMNE", "Invalid control mnemonics", 0, "SOCKLISTEN", "Error listening on a socket", 0, "LQLENGTHNA", "Listening queue length !UL not appropriate. Must be between 1 and 5.", 1, "ADDRTOOLONG", "Socket address !AD of length !UL is longer than the maximum permissible length !UL", 4, "GTMSECSHRGETSEMFAIL", "error getting semaphore errno = !UL", 1, "CPBEYALLOC", "Attempt to copy beyond the allocated buffer", 0, "DBRDONLY", "Database file !AD read only", 2, "DUPTN", "Duplicate transaction found [TN = 0x!16@XQ] at offset 0x!XL in journal file !AD", 4, "TRESTLOC", "Transaction start: !AD, Transaction failure: !AD", 4, "REPLPOOLINST", "Error with replication pool (id = !UL) for instance file !AD", 3, "ZCVECTORINDX", "Invalid Vector Index !UL", 1, "REPLNOTON", "Replication is not on for journal file !AD, rollback will not continue", 2, "JNLMOVED", "Journal file appears to have been moved. Journaling activity will not be done.", 0, "EXTRFMT", "Extract error: invalid format type. Must be ZWR, GO, or BINARY.", 0, "CALLERID", "Routine !AD called from 0x!XJ", 3, "KRNLKILL", "Process was terminated by SIGDANGER signal from the system -- System swap space is too low -- Report to System Administrator", 0, "MEMORYRECURSIVE", "Memory Subsystem called recursively", 0, "FREEZEID", "Cache !AD on !AD by freeze id 0x!XL with match 0x!XL from 0x!XJ", 7, "BLKWRITERR", "Unable to queue disk write for block 0x!XL. Will keep trying.", 1, "STOPTIMEOUT", "Waited too long for stopped process to release. Region: !AD.", 2, "TRIGMODINTP", "Triggers for a given global cannot be both used and modified or removed in the same transaction", 0, "BCKUPBUFLUSH", "Unable to flush buffer for online backup", 0, "NOFORKCORE", "Unable to fork off process to create core. Core creation postponed.", 0, "JNLREAD", "Error reading from journal file !AD at offset [0x!XL]", 3, "JNLMINALIGN", "Journal Record Alignment !UL is less than the minimum value of !UL", 2, "UNUSEDMSG781", "JNLDSKALIGN : Last used in V4.3-000", 0, "JNLPOOLSETUP", "Journal Pool setup error", 0, "JNLSTATEOFF", "ROLLBACK or RECOVER BACKWARD cannot proceed as database file !AD does not have journaling ENABLED and ON", 2, "RECVPOOLSETUP", "Receive Pool setup error", 0, "REPLCOMM", "Replication subsystem communication failure", 0, "NOREPLCTDREG", "Replication subsystem found no region replicated for !AD !AZ", 3, "REPLINFO", "!AD", 2, "REPLWARN", "!AD", 2, "REPLERR", "!AD", 2, "JNLNMBKNOTPRCD", "Journal file !AD does not match the current journal file !AD of database file !AD", 6, "REPLFILIOERR", "Replication subsystem file I/O error !AD", 2, "REPLBRKNTRANS", "Replication subsystem found seqno !16@XQ broken or missing in the journal files", 1, "TTWIDTHTOOBIG", "Terminal WIDTH exceeds the maximum allowed limit", 0, "REPLLOGOPN", "Replication subsystem could not open log file !AD: !AD. Logging done to !AD.", 6, "REPLFILTER", "Replication filter subsystem failure", 0, "GBLMODFAIL", "Global variable Conflict Test failed. Failure code: !AD.", 2, "TTLENGTHTOOBIG", "Terminal LENGTH exceeds the maximum allowed limit", 0, "TPTIMEOUT", "Transaction timeout", 0, "DEFEREVENT", "Transfer table reset for event type !UL when set for type !UL", 2, "JNLFILNOTCHG", "Journal file not changed", 0, "EVENTLOGERR", "Error in event logging subsystem", 0, "UPDATEFILEOPEN", "Update file open error", 0, "JNLBADRECFMT", "Journal File Record Format Error encountered for file !AD at disk address 0x!XL", 3, "NULLCOLLDIFF", "Null collation order must be the same for all regions", 0, "MUKILLIP", "Kill in progress indicator is set for file !AD - this !AD operation is likely to result in incorrectly marked busy errors", 4, "JNLRDONLY", "Journal file !AD read only", 2, "ANCOMPTINC", "Deviceparameter !AD is not compatible with any other deviceparameters in the !AD command", 4, "ABNCOMPTINC", "Deviceparameter !AD and deviceparameter !AD are not compatible in the !AD command", 6, "UNUSEDMSG809", "GTMSECSHRLOGF last used in V5.5-000", 0, "SOCKNOTFND", "Socket !AD not found", 2, "CURRSOCKOFR", "Current socket of index !UL is out of range. There are only !UL sockets.", 2, "SOCKETEXIST", "Socket !AD already exists", 2, "LISTENPASSBND", "Controlmnemonic LISTEN can be applied to PASSIVE socket in the state BOUND only", 0, "DBCLNUPINFO", "Database file !AD !/!AD", 4, "MUNODWNGRD", "Database not downgraded because of preceding errors", 0, "REPLTRANS2BIG", "Transaction !16@XQ of size !UL (pre-filter size !UL) too large to be accommodated in the !AD pool", 5, "RDFLTOOLONG", "Length specified for fixed length read exceeds the maximum string size", 0, "MUNOFINISH", "MUPIP unable to finish all requested actions", 0, "DBFILEXT", "Database file !AD extended from 0x!XL blocks to 0x!XL at transaction 0x!16@XQ", 5, "JNLFSYNCERR", "Error synchronizing journal file !AD to disk", 2, "FSYNCTIMOUT", "Timed out on fsync for journal file !AD", 2, "ZCPREALLVALINV", "The pre-allocation value exceeded the maximum string length", 0, "NEWJNLFILECREAT", "Journal file !AD nearing maximum size. New journal file created.", 2, "DSKSPACEFLOW", "Disk Space for file !AD nearing maximum size. !UL blocks available.", 3, "GVINCRFAIL", "Global variable $INCR failed. Failure code: !AD.", 2, "ISOLATIONSTSCHN", "Error changing NOISOLATION status for global ^!AD within a TP transaction from !UL to !UL", 4, "REPLGBL2LONG", "Global names longer than 8 characters cannot be handled at the secondary", 0, "TRACEON", "Missing global name (with optional subscripts) for recording M-tracing information", 0, "TOOMANYCLIENTS", "GT.CM is serving the maximum number of clients. Try again later.", 0, "NOEXCLUDE", "None of the excluded variables exist", 0, "GVINCRISOLATION", "$INCREMENT cannot be performed on global ^!AD as it has NOISOLATION turned ON", 2, "EXCLUDEREORG", "Global: !AD is present in the EXCLUDE option. REORG will skip the global.", 2, "REORGINC", "Reorg was incomplete. Not all globals were reorged.", 0, "ASC2EBCDICCONV", "ASCII/EBCDIC conversion failed when calling !AD", 2, "GTMSECSHRSTART", "!AD - !UL : gtmsecshr failed to startup", 3, "DBVERPERFWARN1", "Performance warning: Database !AD is running in compatibility mode which degrades performance. Run MUPIP REORG UPGRADE for best overall performance", 2, "FILEIDGBLSEC", "File ID in global section does not match with the database file !AD", 2, "GBLSECNOTGDS", "Global Section !AD is not a GT.M global section", 2, "BADGBLSECVER", "Global Section !AD does not match the current database version", 2, "RECSIZENOTEVEN", "RECORDSIZE [!UL] needs to be a multiple of 2 if ICHSET or OCHSET is UTF-16, UTF-16LE or UTF-16BE", 1, "BUFFLUFAILED", "Error flushing buffers from !AD for database file !AD", 4, "MUQUALINCOMP", "Incompatible qualifiers - FILE and REGION", 0, "DISTPATHMAX", "$gtm_dist path is greater than maximum (!UL)", 1, "UNUSEDMSG844", "MAXTRACEHEIGHT last used in V5.4-002", 0, "IMAGENAME", "The executing module name should be !AD instead of !AD", 4, "GTMSECSHRPERM", "The gtmsecshr module in $gtm_dist does not have the correct permission and uid", 0, "GTMDISTUNDEF", "Environment variable $gtm_dist is not defined", 0, "SYSCALL", "Error received from system call !AD -- called from module !AD at line !UL", 5, "MAXGTMPATH", "The executing module path is greater than the maximum !UL", 1, "TROLLBK2DEEP", "Intended rollback(!SL) deeper than the current $tlevel(!UL)", 2, "INVROLLBKLVL", "Rollback level (!UL) not less than current $TLEVEL(!UL). Can't rollback.", 2, "OLDBINEXTRACT", "Loading an older version(!UL) of binary extract. !/Database or global collation changes since the extract, if any, will result in database corruption.", 1, "ACOMPTBINC", "Deviceparameter !AD is compatible with only !AD in the command !AD", 6, "NOTREPLICATED", "Transaction number !16@XQ generated by the !AD process (PID = !UL) is not replicated to the secondary", 4, "DBPREMATEOF", "Premature end of file with database file !AD", 2, "KILLBYSIG", "!AD process !UL has been killed by a signal !UL", 4, "KILLBYSIGUINFO", "!AD process !UL has been killed by a signal !UL from process !UL with userid number !UL", 6, "KILLBYSIGSINFO1", "!AD process !UL has been killed by a signal !UL at address 0x!XJ (vaddr 0x!XJ)", 6, "KILLBYSIGSINFO2", "!AD process !UL has been killed by a signal !UL at address 0x!XJ", 5, "SIGILLOPC", "Signal was caused by an illegal opcode", 0, "SIGILLOPN", "Signal was caused by an illegal operand", 0, "SIGILLADR", "Signal was caused by illegal addressing mode", 0, "SIGILLTRP", "Signal was caused by an illegal trap", 0, "SIGPRVOPC", "Signal was caused by a privileged opcode", 0, "SIGPRVREG", "Signal was caused by a privileged register", 0, "SIGCOPROC", "Signal was caused by a coprocessor error", 0, "SIGBADSTK", "Signal was caused by an internal stack error", 0, "SIGADRALN", "Signal was caused by invalid address alignment", 0, "SIGADRERR", "Signal was caused by a non-existent physical address", 0, "SIGOBJERR", "Signal was caused by an object specific hardware error", 0, "SIGINTDIV", "Signal was caused by an integer divided by zero", 0, "SIGINTOVF", "Signal was caused by an integer overflow", 0, "SIGFLTDIV", "Signal was caused by a floating point divide by zero", 0, "SIGFLTOVF", "Signal was caused by a floating point overflow", 0, "SIGFLTUND", "Signal was caused by a floating point underflow", 0, "SIGFLTRES", "Signal was caused by a floating point inexact result", 0, "SIGFLTINV", "Signal was caused by an invalid floating point operation", 0, "SIGMAPERR", "Signal was caused by an address not mapped to an object", 0, "SIGACCERR", "Signal was caused by invalid permissions for mapped object", 0, "TRNLOGFAIL", "Translation of (VMS) logical name or (UNIX) environment variable !AD failed", 2, "INVDBGLVL", "Invalid non-numeric debug level specified !AD in (VMS) logical name or (UNIX) environment variable !AD", 4, "DBMAXNRSUBS", "!AD Maximum number of subscripts exceeded", 2, "GTMSECSHRSCKSEL", "gtmsecshr select on socket failed", 0, "GTMSECSHRTMOUT", "gtmsecshr exiting due to idle timeout", 0, "GTMSECSHRRECVF", "gtmsecshr receive on server socket failed", 0, "GTMSECSHRSENDF", "gtmsecshr send on server socket failed", 0, "SIZENOTVALID8", "Size (in bytes) must be either 1, 2, 4, or 8", 0, "GTMSECSHROPCMP", "gtmsecshr operation may be compromised", 0, "GTMSECSHRSUIDF", "gtmsecshr server setuid to root failed", 0, "GTMSECSHRSGIDF", "gtmsecshr server setgid to root failed", 0, "GTMSECSHRSSIDF", "gtmsecshr server setsid failed", 0, "GTMSECSHRFORKF", "gtmsecshr server unable to fork off a child process", 0, "DBFSYNCERR", "Error synchronizing database file !AD to disk", 2, "SECONDAHEAD", "Secondary ahead of primary. !/ Secondary database possibly updated by process other than the update process. First perform rollback.", 0, "SCNDDBNOUPD", "Database Updates not allowed on the secondary", 0, "MUINFOUINT4", "!AD : !UL [0x!XL]", 4, "NLMISMATCHCALC", "Location of !AD expected at 0x!XL, but found at 0x!XL", 4, "UNUSEDMSG898", "GTMSECSHRLOGSWH last used in V5.5-000", 0, "UNUSEDMSG899", "GTMSECSHRDEFLOG last used in V5.5-000", 0, "DBBADNSUB", "!AD Bad numeric subscript", 2, "DBBADKYNM", "!AD Bad key name", 2, "DBBADPNTR", "!AD Bad pointer value in directory", 2, "DBBNPNTR", "!AD Bit map block number as pointer", 2, "DBINCLVL", "!AD Block at incorrect level", 2, "DBBFSTAT", "!AD Block busy/free status unknown (local bitmap corrupted)", 2, "DBBDBALLOC", "!AD Block doubly allocated", 2, "DBMRKFREE", "!AD Block incorrectly marked free", 2, "DBMRKBUSY", "!AD Block incorrectly marked busy", 2, "DBBSIZZRO", "!AD Block size equals zero", 2, "DBSZGT64K", "!AD Block size is greater than 64K", 2, "DBNOTMLTP", "!AD Block size not a multiple of 512 bytes", 2, "DBTNTOOLG", "!AD Block transaction number too large", 2, "DBBPLMLT512", "!AD Blocks per local map is less than 512", 2, "DBBPLMGT2K", "!AD Blocks per local map is greater than 2K", 2, "MUINFOUINT8", "!AD : !@ZQ [0x!16@XQ]", 4, "DBBPLNOT512", "!AD Blocks per local map is not 512", 2, "MUINFOSTR", "!AD : !AD", 4, "DBUNDACCMT", "!AD Cannot determine access method; trying with BG", 2, "DBTNNEQ", "!AD Current tn and early tn are not equal", 2, "MUPGRDSUCC", "Database file !AD successfully !AD to !AD", 6, "DBDSRDFMTCHNG", "Database file !AD, Desired DB Format set to !AD by !AD with pid !UL [0x!XL] at transaction number [0x!16@XQ]", 9, "DBFGTBC", "!AD File size larger than block count would indicate", 2, "DBFSTBC", "!AD File size smaller than block count would indicate", 2, "DBFSTHEAD", "!AD File smaller than database header", 2, "DBCREINCOMP", "!AD Header indicates database file creation was interrupted before completion", 2, "DBFLCORRP", "!AD Header indicates database file is corrupt", 2, "DBHEADINV", "!AD Header size not valid for database", 2, "DBINCRVER", "!AD Incorrect version of GT.M database", 2, "DBINVGBL", "!AD Invalid mixing of global names", 2, "DBKEYGTIND", "!AD Key greater than index key", 2, "DBGTDBMAX", "!AD Key larger than database maximum", 2, "DBKGTALLW", "!AD Key larger than maximum allowed length", 2, "DBLTSIBL", "!AD Keys less than sibling's index key", 2, "DBLRCINVSZ", "!AD Last record of block has invalid size", 2, "MUREUPDWNGRDEND", "Region !AD : MUPIP REORG UPGRADE/DOWNGRADE finished by pid !UL [0x!XL] at transaction number [0x!16@XQ]", 5, "DBLOCMBINC", "!AD Local bit map incorrect", 2, "DBLVLINC", "!AD Local bitmap block level incorrect", 2, "DBMBSIZMX", "!AD Map block too large", 2, "DBMBSIZMN", "!AD Map block too small", 2, "DBMBTNSIZMX", "!AD Map block transaction number too large", 2, "DBMBMINCFRE", "!AD Master bit map incorrectly asserts this local map has free space", 2, "DBMBPINCFL", "!AD Master bit map incorrectly marks this local map full", 2, "DBMBPFLDLBM", "!AD Master bit map shows this map full, agreeing with disk local map", 2, "DBMBPFLINT", "!AD Master bit map shows this map full, agreeing with MUPIP INTEG", 2, "DBMBPFLDIS", "!AD Master bit map shows this map full, in disagreement with both disk and INTEG result", 2, "DBMBPFRDLBM", "!AD Master bit map shows this map has space, agreeing with disk local map", 2, "DBMBPFRINT", "!AD Master bit map shows this map has space, agreeing with MUPIP INTEG", 2, "DBMAXKEYEXC", "!AD Maximum key size for database exceeds design maximum", 2, "DBMXRSEXCMIN", "!AD Maximum record size for database is less than the design minimum", 2, "UNUSEDMSG950", "DBMAXRSEXBL : Last used in V5.5-000", 0, "DBREADBM", "!AD Read error on bitmap", 2, "DBCOMPTOOLRG", "!AD Record has too large compression count", 2, "DBVERPERFWARN2", "Peformance warning: Database !AD is not fully upgraded. Run MUPIP REORG UPGRADE for best overall performance", 2, "DBRBNTOOLRG", "!AD Root block number greater than last block number in file", 2, "DBRBNLBMN", "!AD Root block number is a local bit map number", 2, "DBRBNNEG", "!AD Root block number negative", 2, "DBRLEVTOOHI", "!AD Root level higher than maximum", 2, "DBRLEVLTONE", "!AD Root level less than one", 2, "DBSVBNMIN", "!AD Start VBN smaller than possible", 2, "DBTTLBLK0", "!AD Total blocks equal zero", 2, "DBNOTDB", "!AD File does not have a valid GDS file header", 2, "DBTOTBLK", "Total blocks should be 0x!XL, is 0x!XL", 2, "DBTN", "Block TN is 0x!16@XQ", 1, "DBNOREGION", "None of the database regions accessible", 0, "DBTNRESETINC", "WARNING: tn_reset for database is incomplete due to integrity errors", 0, "DBTNLTCTN", "Transaction numbers greater than the current transaction were found", 0, "DBTNRESET", "Cannot reset transaction number for this region", 0, "MUTEXRSRCCLNUP", "Mutex subsystem leftover resource !AD removed", 2, "SEMWT2LONG", "Process !UL waited !UL second(s) for the !AD lock for region !AD, lock held by pid !UL", 7, "REPLINSTOPEN", "Error opening replication instance file !AD", 2, "REPLINSTCLOSE", "Error closing replication instance file !AD", 2, "UNUSEDMSG972", "JNLNOTFOUND : Last used in V4.4-000", 0, "DBCRERR8", "Database file !AD, cr location 0x!XJ blk = 0x!XL error: !AD was 0x!16@XQ, expecting 0x!16@XQ -- called from module !AD at line !UL", 11, "NUMPROCESSORS", "Could not determine number of processors", 0, "DBADDRANGE8", "Database file !AD, element location 0x!XJ: blk = 0x!XL: control 0x!16@XQ was outside !AD range 0x!16@XQ to 0x!16@XQ", 9, "RNDWNSEMFAIL", "Attempting to acquire gds_rundown semaphore when it is already owned", 0, "GTMSECSHRSHUTDN", "gtmsecshr process has received a shutdown request -- shutting down", 0, "NOSPACECRE", "Not enough space to create database file !AD. !@ZQ blocks are needed, only !@ZQ available.", 4, "LOWSPACECRE", "Disk space for database file !AD is not enough for !UL future extensions. !@ZQ !UL-byte blocks are needed, only !@ZQ available.", 6, "WAITDSKSPACE", "Process 0x!XL will wait !UL seconds for necessary disk space to become available for !AD ", 4, "OUTOFSPACE", "Database file !AD ran out of disk space. Detected by process !UL. !/Exit without clearing shared memory due to the disk space constraints. !/Make space and then perform mupip rundown to ensure database integrity.", 3, "JNLPVTINFO", "Pid 0x!XL!/ cycle 0x!XL fd_mismatch 0x!XL channel 0x!XL sync_io 0x!XL!/ pini_addr 0x!XL qio_active 0x!XL old_channel 0x!XL", 8, "NOSPACEEXT", "Not enough disk space for file !AD to extend. !UL blocks needed. !UL blocks available.", 4, "WCBLOCKED", "Field !AD is set by process !UL at transaction number 0x!16@XQ for database file !AD", 6, "REPLJNLCLOSED", "Replication in jeopardy as journaling got closed for database file !AD. Current region seqno is !@ZQ [0x!16@XQ] and system seqno is !@ZQ [0x!16@XQ]", 6, "RENAMEFAIL", "Rename of file !AD to !AD failed", 4, "FILERENAME", "File !AD is renamed to !AD", 4, "JNLBUFINFO", "Pid 0x!XL!/ dsk 0x!XL free 0x!XL bytcnt 0x!XL io_in_prog 0x!XL fsync_in_prog 0x!XL!/ dskaddr 0x!XL freeaddr 0x!XL qiocnt 0x!XL now_writer 0x!XL fsync_pid 0x!XL!/filesize 0x!XL cycle 0x!XL errcnt 0x!XL wrtsize 0x!XL fsync_dskaddr 0x!XL", 16, "UNUSEDMSG989", "JNLQIOLOCKED : Last used in V4.4-000", 0, "UNUSEDMSG990", "JNLEOFPREZERO : Last used in V4.4-000", 0, "TPNOTACID", "!AD at !AD in a final TP retry violates ACID properties of a TRANSACTION; indefinite RESTARTs may occur !AD !AD", 8, "JNLSETDATA2LONG", "SET journal record has data of length !UL. Target system cannot handle data more than !UL bytes.", 2, "JNLNEWREC", "Target system cannot recognize journal record of type !UL, last recognized type is !UL", 2, "REPLFTOKSEM", "Error with replication semaphores for instance file !AD", 2, "UNUSEDMSG995", "GETCWD : Last used before V4.0-001E", 0, "EXTRIOERR", "Error writing extract file !AD", 2, "EXTRCLOSEERR", "Error closing extract file !AD", 2, "UNUSEDMSG998", "TRUNCATE : Last used in V4.3-001F", 0, "REPLEXITERR", "Replication process encountered an error while exiting", 0, "MUDESTROYSUC", "Global section (!AD) corresponding to file !AD successfully destroyed", 4, "DBRNDWN", "Error during global database rundown for region !AD.!/Notify those responsible for proper database operation.", 2, "MUDESTROYFAIL", "Global section (!AD) corresponding to file !AD failed to be destroyed", 4, "NOTALLDBOPN", "Not all required database files were opened", 0, "MUSELFBKUP", "Database file !AD can not be backed upon itself", 2, "DBDANGER", "Process !UL [0x!XL] killed while committing update for database file !AD. Possibility of damage to block 0x!XL.", 5, "TRUNCATEFAIL", "Truncating !AD from 0x!XL VMS blocks to 0x!XL blocks failed", 4, "TCGETATTR", "Error while getting terminal attributes on file descriptor !UL", 1, "TCSETATTR", "Error while setting terminal attributes on file descriptor !UL", 1, "IOWRITERR", "IO Write by pid 0x!XL to blk 0x!XL of database file !AD failed. Pid 0x!XL retrying the IO.", 5, "REPLINSTWRITE", "Error writing [0x!XL] bytes at offset [0x!16@XQ] in replication instance file !AD", 4, "DBBADFREEBLKCTR", "Database !AD free blocks counter in file header: 0x!XL appears incorrect, should be 0x!XL. Auto-corrected.", 4, "REQ2RESUME", "Request to resume suspended processing received from process !UL owned by userid !UL", 2, "TIMERHANDLER", "Incorrect SIGALRM handler (0x!XJ) found by !AD", 3, "FREEMEMORY", "Error occurred freeing memory from 0x!XJ", 1, "MUREPLSECDEL", "Replication section !AD deleted", 2, "MUREPLSECNOTDEL", "Replication section !AD not deleted", 2, "MUJPOOLRNDWNSUC", "Jnlpool section (id = !AD) belonging to the replication instance !AD successfully rundown", 4, "MURPOOLRNDWNSUC", "Recvpool section (id = !AD) belonging to the replication instance !AD successfully rundown", 4, "MUJPOOLRNDWNFL", "Jnlpool section (id = !AD) belonging to the replication instance !AD rundown failed", 4, "MURPOOLRNDWNFL", "Recvpool section (id = !AD) belonging to the replication instance !AD rundown failed", 4, "MUREPLPOOL", "Error with replpool section !AD", 2, "REPLACCSEM", "Error with replication access semaphore (id = !UL) for instance file !AD", 3, "JNLFLUSHNOPROG", "No progress while attempting to flush journal file !AD", 2, "REPLINSTCREATE", "Error creating replication instance file !AD", 2, "SUSPENDING", "Process Received Signal !UL. Suspending processing on user request or attempt to do terminal I/O while running in the background", 1, "SOCKBFNOTEMPTY", "Socket buffer size cannot be set to 0x!XL due to 0x!XL bytes of buffered data. Read first.", 2, "ILLESOCKBFSIZE", "The specified socket buffer size is 0x!XL, which is either 0 or too big", 1, "NOSOCKETINDEV", "There is no socket in the current socket device", 0, "SETSOCKOPTERR", "Setting the socket attribute !AD failed: (errno == !UL) !AD", 5, "GETSOCKOPTERR", "Getting the socket attribute !AD failed: (errno == !UL) !AD", 5, "NOSUCHPROC", "Process !UL does not exist - no need to !AD it", 3, "DSENOFINISH", "DSE unable to finish all requested actions", 0, "LKENOFINISH", "LKE unable to finish all requested actions", 0, "NOCHLEFT", "Unhandled condition exception (all handlers exhausted) - process terminating", 0, "MULOGNAMEDEF", "Logical name !AD, needed to start replication server is already defined for this job. !/Check for an existing or improperly terminated server.", 2, "BUFOWNERSTUCK", "Pid !UL waiting for Pid !UL to finish disk-read of block !UL [0x!XL].!/Been waiting for !UL minutes. read_in_progress=!UL : rip_latch = !UL.", 7, "ACTIVATEFAIL", "Failed to activate passive source server for secondary instance !AD", 2, "DBRNDWNWRN", "Global section of database file !AD not rundown successfully by pid !UL [0x!XL]. Global section was not removed.", 4, "DLLNOOPEN", "Failed to load external dynamic library !AD", 2, "DLLNORTN", "Failed to look up the location of the symbol !AD", 2, "DLLNOCLOSE", "Failed to unload external dynamic library", 0, "FILTERNOTALIVE", "Replication server detected that the filter is not alive while attempting to send seqno !16@XQ", 1, "FILTERCOMM", "Error communicating seqno !16@XQ with the filter", 1, "FILTERBADCONV", "Bad conversion of seqno !16@XQ by filter", 1, "PRIMARYISROOT", "Attempted operation not valid on root primary instance !AD", 2, "GVQUERYGETFAIL", "Global variable QUERY and GET failed. Failure code: !AD.", 2, "DBCREC2BIGINBLK", "A Record in block 0x!XL has a length greater than the maximum (!UL) in database !AD", 4, "MERGEDESC", "Merge operation not possible. !AD is descendent of !AD.", 4, "MERGEINCOMPL", "Error encountered during MERGE; operation may be incomplete", 0, "DBNAMEMISMATCH", "Database file !AD points to shared memory (id = !UL) which in turn points to an inaccessible database file !AZ", 4, "DBIDMISMATCH", "Database file !AZ (region !AD) id does not match file id in shared memory (id = !UL).", 4, "DEVOPENFAIL", "Error opening !AD", 2, "IPCNOTDEL", "!AD : !AD did not delete IPC resources for region !AD", 6, "XCVOIDRET", "Attempt to return a value from function !AD, which is declared void in external call table !AD", 4, "MURAIMGFAIL", "Mupip recover or rollback failed while processing an after-image journal record. Failure code: !AD.", 2, "REPLINSTUNDEF", "Replication instance environment variable $gtm_repl_instance is undefined", 0, "REPLINSTACC", "Error accessing replication instance file !AD", 2, "NOJNLPOOL", "No journal pool info found in the replication instance of !AD", 2, "NORECVPOOL", "No receiver pool info found in the replication instance of !AD", 2, "FTOKERR", "Error getting ftok of the file !AD", 2, "REPLREQRUNDOWN", "Error accessing replication instance !AD. Must be rundown on cluster node !AD.", 4, "BLKCNTEDITFAIL", "Mupip recover or rollback failed to correct the block count field in the file header for file !AD", 2, "SEMREMOVED", "Semaphore id !UL removed from the system", 1, "REPLINSTFMT", "Format error encountered while reading replication instance file !AD. Expected !AD. Found !AD.", 6, "SEMKEYINUSE", "Semaphore key 0x!XL is already in use (possibly by an older version)", 1, "XTRNTRANSERR", "Error attempting to generate an environment using an external algorithm", 0, "XTRNTRANSDLL", "Error during extended reference environment translation. Check the above message.", 0, "XTRNRETVAL", "Length of return value (!SL) from extended reference translation algorithm is not in the range [0,!UL]", 2, "XTRNRETSTR", "Return string from extended reference translation algorithm is NULL", 0, "INVECODEVAL", "Invalid value for $ECODE (!AD)", 2, "SETECODE", "Non-empty value assigned to $ECODE (user-defined error trap)", 0, "INVSTACODE", "Invalid value for second parameter of $STACK (!AD)", 2, "REPEATERROR", "Repeat previous error", 0, "NOCANONICNAME", "Value is not a canonic name (!AD)", 2, "NOSUBSCRIPT", "No such subscript found (!SL)", 1, "SYSTEMVALUE", "Invalid value for $SYSTEM (!AD)", 2, "SIZENOTVALID4", "Size (in bytes) must be either 1, 2, or 4", 0, "STRNOTVALID", "Error: cannot convert !AD value to valid value", 2, "UNUSEDMSG1079", "RECNOCREJNL : Last used in V4.3-001F", 0, "ERRWETRAP", "Error while processing $ETRAP", 0, "TRACINGON", "Tracing already turned on", 0, "CITABENV", "Environment variable for call-in table !AD not set", 2, "CITABOPN", "Unable to open call-in table: !AD", 2, "CIENTNAME", "No label reference found for this entry in call-in table", 0, "CIRTNTYP", "Invalid return type", 0, "CIRCALLNAME", "Call-in routine name expected but not found", 0, "CIRPARMNAME", "Invalid parameter specification for call-in table", 0, "CIDIRECTIVE", "Invalid directive parameter passing. Expected I, O or IO.", 0, "CIPARTYPE", "Invalid type specification for O/IO directive - expected pointer type", 0, "CIUNTYPE", "Unknown parameter type encountered", 0, "CINOENTRY", "No entry specified for !AD in the call-in table", 2, "JNLINVSWITCHLMT", "Journal AUTOSWITCHLIMIT [!UL] falls outside of allowed limits [!UL] and [!UL]", 3, "SETZDIR", "Cannot change working directory to !AD", 2, "JOBACTREF", "Actual parameter in job command passed by reference", 0, "ECLOSTMID", "$ECODE overflow, the first and last ecodes are retained, but some intervening ecodes have been lost", 0, "ZFF2MANY", "Number of characters specified for ZFF deviceparameter (!UL) is more than the maximum allowed (!UL)", 2, "JNLFSYNCLSTCK", "Journaling fsync lock is stuck in journal file !AD", 2, "DELIMWIDTH", "Delimiter length !UL exceeds device width !UL", 2, "DBBMLCORRUPT", "Database !AD : Bitmap blk [0x!XL] is corrupt (size = [0x!XL], levl = [0x!XL], tn = [0x!16@XQ]) : Dbtn = [0x!16@XQ] : Database integrity errors likely", 7, "DLCKAVOIDANCE", "Possible deadlock detected: Database !AD : Dbtn [0x!16@XQ] : t_tries [0x!XL] : dollar_trestart [0x!XL] : now_crit [0x!XL] : TP transaction restarted", 6, "WRITERSTUCK", "Buffer flush stuck waiting for [0x!XL] concurrent writers to finish writing to database file !AD", 3, "PATNOTFOUND", "Current pattern table has no characters with pattern code !AD", 2, "INVZDIRFORM", "Invalid value (!UL) specified for ZDIR_FORM", 1, "ZDIROUTOFSYNC", "$ZDIRECTORY !AD is not the same as its cached value !AD", 4, "GBLNOEXIST", "Global !AD no longer exists", 2, "MAXBTLEVEL", "Global !AD reached maximum level", 2, "UNUSEDMSG1107", "JNLSTRESTFL : found no evidence it ever was used in a production release", 0, "JNLALIGNSZCHG", "Journal ALIGNSIZE is rounded up to !UL blocks (closest next higher power of two)", 1, "UNUSEDMSG1109", "MAXTRACELEVEL : last used in V5.4-002B", 0, "GVFAILCORE", "A core file is being created for later analysis if necessary", 0, "DBCDBNOCERTIFY", "Database !AD HAS NOT been certified due to the preceding errors - rerun DBCERTIFY SCAN", 2, "DBFRZRESETSUC", "Freeze released successfully on database file !AD", 2, "JNLFILEXTERR", "Error during extension of journal file !AD", 2, "JOBEXAMDONE", "GT.M process !UL completed job examine to !AD", 3, "JOBEXAMFAIL", "GT.M process !UL executing $ZJOBEXAM function failed with the preceding error message", 1, "JOBINTRRQST", "Job interrupt requested", 0, "ERRWZINTR", "Error while processing $ZINTERRUPT", 0, "CLIERR", "!AD", 2, "REPLNOBEFORE", "NOBEFORE option cannot be used when the current replication state is ON for database file !AD", 2, "REPLJNLCNFLCT", "Journaling cannot be turned !AD on database file !AD as the replication state is !AD and must also be turned !AD in the same command", 8, "JNLDISABLE", "Specified journal option(s) cannot take effect as journaling is DISABLED on database file !AD", 2, "FILEEXISTS", "File !AD already exists", 2, "JNLSTATE", "Journaling state for !AD !AD is now !AD", 6, "REPLSTATE", "Replication state for !AD !AD is now !AD", 6, "JNLCREATE", "Journal file !AD created for !AD !AD with !AD", 8, "JNLNOCREATE", "Journal file !AD not created", 2, "JNLFNF", "Journal file !AD not found", 2, "PREVJNLLINKCUT", "Previous journal file name link set to NULL in new journal file !AD created for database file !AD", 4, "PREVJNLLINKSET", "Previous generation journal file name is changed from !AD to !AD", 4, "FILENAMETOOLONG", "File name too long", 0, "REQRECOV", "Error accessing database !AD. Must be recovered on cluster node !AD.", 4, "JNLTRANS2BIG", "Transaction needs an estimated [!UL blocks] in journal file !AD which exceeds the AUTOSWITCHLIMIT of !UL blocks", 4, "JNLSWITCHTOOSM", "Journal AUTOSWITCHLIMIT [!UL blocks] is less than Journal ALLOCATION [!UL blocks] for database file !AD", 4, "JNLSWITCHSZCHG", "Journal AUTOSWITCHLIMIT [!UL blocks] is rounded down to [!UL blocks] to equal the sum of Journal ALLOCATION [!UL blocks] and a multiple of Journal EXTENSION [!UL blocks] for database file !AD", 6, "NOTRNDMACC", "Only random access files are supported as backup files for non-incremental backup", 0, "TMPFILENOCRE", "Error in MUPIP BACKUP while trying to create temporary file !AD", 2, "SHRMEMEXHAUSTED", "Attempt by process to use more shared memory than currently permitted by VMS", 0, "JNLSENDOPER", "pid = 0x!XL : status = 0x!XL : jpc_status = 0x!XL : jpc_status2 = 0x!XL : iosb.cond = 0x!XW", 5, "DDPSUBSNUL", "NUL characters in subscripts are not supported by DDP", 0, "DDPNOCONNECT", "Named volume set, !AD, is not connected", 2, "DDPCONGEST", "Agent congestion", 0, "DDPSHUTDOWN", "Server has shut down", 0, "DDPTOOMANYPROCS", "Maximum process limit of !UL exceeded", 1, "DDPBADRESPONSE", "DDP invalid response code: !XB; message text follows", 1, "DDPINVCKT", "Invalid format for CIRCUIT", 0, "DDPVOLSETCONFIG", "Volume Set Configuration file error", 0, "DDPCONFGOOD", "Volume Set Configuration entry accepted", 0, "DDPCONFIGNORE", "Volume Set Configuration line ignored", 0, "DDPCONFINCOMPL", "Volume Set Configuration entry incomplete", 0, "DDPCONFBADVOL", "Volume Set Configuration entry : invalid volume", 0, "DDPCONFBADUCI", "Volume Set Configuration entry : invalid uci", 0, "DDPCONFBADGLD", "Volume Set Configuration entry : invalid global directory", 0, "DDPRECSIZNOTNUM", "Maximum record size is not numeric", 0, "DDPOUTMSG2BIG", "DDP message too big to be accommodated in outbound buffer", 0, "DDPNOSERVER", "DDP Server not running on local node", 0, "MUTEXRELEASED", "Process !UL [0x!XL] has released the critical section for database !AD to avoid deadlock. $TLEVEL: !UL t_tries: !UL", 6, "JNLCRESTATUS", "!AD at line !UL for journal file !AD, database file !AD encountered error", 7, "ZBREAKFAIL", "Could not set breakpoint at !AD due to insufficient memory", 2, "DLLVERSION", "Routine !AD in library !AD was compiled with an incompatible version of GT.M. Recompile with the current version and re-link.", 4, "INVZROENT", "!AD is neither a directory nor an object library(DLL)", 2, "DDPLOGERR", "!AD: !AD", 4, "GETSOCKNAMERR", "Getting the socket name failed from getsockname(): (errno==!UL) !AD", 3, "INVGTMEXIT", "Inappropriate invocation of gtm_exit. gtm_exit cannot be invoked from external calls.", 0, "CIMAXPARAM", "Exceeded maximum number of parameters in the call-in table entry. An M routine cannot accept more than 32 parameters.", 0, "CITPNESTED", "Call-ins can not be used inside a TP transaction", 0, "CIMAXLEVELS", "Too many nested Call-ins. Nested resources exhausted at level !UL.", 1, "JOBINTRRETHROW", "Job interrupt redelivered", 0, "STARFILE", "Star(*) argument cannot be specified with !AD", 2, "NOSTARFILE", "Only star(*) argument can be specified with !AD", 2, "MUJNLSTAT", "!AD at !AD", 4, "JNLTPNEST", "Mupip journal command found nested TP transactions for journal file !AD at offset 0x!XL at transaction number 0x!16@XQ", 4, "REPLOFFJNLON", "Replication state for database file !AD is OFF but journaling state is enabled", 2, "FILEDELFAIL", "Deletion of file !AD failed", 2, "INVQUALTIME", "Invalid time qualifier value. Specify as !AD=delta_or_absolute_time.", 2, "NOTPOSITIVE", "!AD qualifier must be given a value greater than zero", 2, "INVREDIRQUAL", "Invalid REDIRECT qualifier value. !AD", 2, "INVERRORLIM", "Invalid ERROR_LIMIT qualifier value. Must be at least zero", 0, "INVIDQUAL", "Invalid ID qualifier value !AD", 2, "INVTRNSQUAL", "Invalid TRANSACTION qualifier. Specify only one of TRANSACTION=[NO]SET or TRANSACTION=[NO]KILL.", 0, "JNLNOBIJBACK", "MUPIP JOURNAL BACKWARD cannot continue as journal file !AD does not have before image journaling", 2, "SETREG2RESYNC", "Setting resync sequence number 0x!16@XQ to region sequence number 0x!16@XQ for database !AD", 4, "JNLALIGNTOOSM", "Alignsize !UL (bytes) is too small for a block size of !UL (bytes) for !AD !AD. Using alignsize of !UL (bytes) instead.", 7, "JNLFILEOPNERR", "Error opening journal file !AD", 2, "JNLFILECLOSERR", "Error closing journal file !AD", 2, "REPLSTATEOFF", "ROLLBACK cannot proceed as database !AD does not have replication ON", 2, "MUJNLPREVGEN", "Previous generation journal file !AD included for database file !AD", 4, "MUPJNLINTERRUPT", "Database file !AD indicates interrupted MUPIP JOURNAL command. Restore from backup for forward recovery.", 2, "ROLLBKINTERRUPT", "Database file !AD indicates interrupted ROLLBACK. Reissue the MUPIP JOURNAL ROLLBACK command.", 2, "RLBKJNSEQ", "Journal seqno of the instance after rollback is !@ZQ [0x!16@XQ]", 2, "REPLRECFMT", "Replication journal record format error encountered", 0, "PRIMARYNOTROOT", "Attempted operation not valid on non-root primary instance !AD", 2, "DBFRZRESETFL", "Freeze release failed on database file !AD", 2, "JNLCYCLE", "Journal file !AD causes cycle in the journal file generations of database file !AD", 4, "JNLPREVRECOV", "Journal file has nonzero value in prev_recov_end_of_data field", 0, "RESOLVESEQNO", "Resolving until sequence number !@ZQ [0x!16@XQ]", 2, "BOVTNGTEOVTN", "Journal file !AD has beginning transaction [0x!16@XQ] which is greater than end transaction [0x!16@XQ]", 4, "BOVTMGTEOVTM", "Journal file !AD has beginning timestamp [0x!16@XQ] greater than end timestamp [0x!16@XQ]", 4, "BEGSEQGTENDSEQ", "Journal file !AD has beginning sequence number [0x!16@XQ] greater than end sequence number [0x!16@XQ]", 4, "DBADDRALIGN", "Database file !AD, element location 0x!XJ: blk = 0x!XL: [!AD] control 0x!XJ was unaligned relative to base 0x!XJ and element size 0x!XL", 9, "DBWCVERIFYSTART", "Database file !AD, write cache verification started by pid !UL [0x!XL] at transaction number 0x!16@XQ", 5, "DBWCVERIFYEND", "Database file !AD, write cache verification finished by pid !UL [0x!XL] at transaction number 0x!16@XQ", 5, "MUPIPSIG", "!AD (signal !UL) issued from process !UL [0x!XL] to process !UL [0x!XL]", 7, "HTSHRINKFAIL", "Hash table compaction failed to allocate new smaller table due to lack of memory", 0, "STPEXPFAIL", "Stringpool expansion failed. It could not expand to !UL bytes.", 1, "DBBTUWRNG", "The blocks-to-upgrade file-header field is incorrect. Expected 0x!XL, found 0x!XL", 2, "DBBTUFIXED", "The blocks-to-upgrade file-header field has been changed to the correct value", 0, "DBMAXREC2BIG", "Maximum record size (!UL) is too large for this block size (!UL) - Maximum is !UL", 3, "DBCSCNNOTCMPLT", "Specified DBCERTIFY SCAN output file is not complete - Rerun scan", 0, "DBCBADFILE", "Source file !AD does not appear to have been generated by DBCERTIFY SCAN - rerun SCAN or specify correct file", 2, "DBCNOEXTND", "Unable to extend database !AD", 2, "DBCINTEGERR", "Encountered integrity error in database !AD", 2, "DBMINRESBYTES", "Minimum RESERVED BYTES value required for certification/upgrade is !UL - Currently is !UL", 2, "DBCNOTSAMEDB", "Database has been moved or restored since DBCERTIFY SCAN - Rerun scan", 0, "DBCDBCERTIFIED", "Database !AD has been certified for use with !AD", 4, "DBCMODBLK2BIG", "Block 0x!XL has been modified since DBCERTIFY SCAN but is still too large or now has an earlier TN than in the scan phase - Rerun scan phase", 1, "DBCREC2BIG", "Record with key !AD is length !UL in block 0x!XL which is greater than the maximum length !UL in database !AD", 7, "DBCCMDFAIL", "Executed command failed with return code !SL: !AD which executed !AD !AD", 7, "DBCKILLIP", "Cannot proceed with kill in progress indicator set for database !AD -- Run MUPIP INTEG first", 2, "DBCNOFINISH", "DBCERTIFY unable to finish all requested actions", 0, "DYNUPGRDFAIL", "Unable to dynamically upgrade block 0x!XL in database !AD due to lack of free space in block", 3, "MMNODYNDWNGRD", "Unable to use dynamic downgrade with MM access method for region !AD. Use BG access method for downgrade", 2, "MMNODYNUPGRD", "Unable to use MM access method for region !AD until all database blocks are upgraded", 2, "MUDWNGRDNRDY", "Database !AD is not ready to downgrade - still !UL database blocks to downgrade", 3, "MUDWNGRDTN", "Transaction number 0x!16@XQ in database !AD is too big for MUPIP [REORG] DOWNGRADE. Renew database with MUPIP INTEG TN_RESET", 3, "MUDWNGRDNOTPOS", "Start VBN value is [!UL] while downgraded GT.M version can support only [!UL]. Downgrade not possible", 2, "MUUPGRDNRDY", "Database !AD has not been certified as being ready to upgrade to !AD format", 4, "TNWARN", "Database file !AD has 0x!16@XQ more transactions to go before reaching the transaction number limit (0x!16@XQ). Renew database with MUPIP INTEG TN_RESET", 4, "TNTOOLARGE", "Database file !AD has reached the transaction number limit (0x!16@XQ). Renew database with MUPIP INTEG TN_RESET", 3, "SHMPLRECOV", "Shared memory pool block recovery invoked for region !AD", 2, "MUNOSTRMBKUP", "Database !AD has a block size larger than !UL and thus cannot use stream (incremental) backup", 3, "EPOCHTNHI", "At the EPOCH record at offset !UL of !AD transaction number [0x!16@XQ] is higher than database transaction number [0x!16@XQ]", 5, "CHNGTPRSLVTM", "Mupip will change tp_resolve_time from !UL to !UL because expected EPOCH or EOF record was not found in Journal File !AD", 4, "JNLUNXPCTERR", "Unexpected error encountered for Journal !AD at disk address 0x!XL", 3, "OMISERVHANG", "GTCM OMI server is hung", 0, "RSVDBYTE2HIGH", "Record size (!UL) is greater than the maximum allowed for region !AD with Block size (!UL) and Reserved bytes (!UL)", 5, "BKUPTMPFILOPEN", "Open of backup temporary file !AD failed", 2, "BKUPTMPFILWRITE", "Write to backup temporary file !AD failed", 2, "VMSMEMORY2", "Central storage exhausted during allocation of dynamic file descriptor with !UL bytes - check page file quota and page file size", 1, "LOADBGSZ2", "Load error: BEGIN too large. No records loaded.", 0, "LOADEDSZ2", "Load error: END too large. No records loaded.", 0, "REPLINSTMISMTCH", "Process has replication instance file !AD (jnlpool shmid = !UL) open but database !AD is bound to instance file !AD (jnlpool shmid = !UL)", 8, "REPLINSTREAD", "Error reading [0x!XL] bytes at offset [0x!16@XQ] from replication instance file !AD", 4, "REPLINSTDBMATCH", "Replication instance file !AD has seqno [0x!16@XQ] while database has a different seqno [0x!16@XQ]", 4, "REPLINSTNMSAME", "Primary and Secondary instances have the same replication instance name !AD", 2, "REPLINSTNMUNDEF", "Replication instance name not defined", 0, "REPLINSTNMLEN", "Replication instance name !AD should be 1 to 15 characters long", 2, "REPLINSTNOHIST", "History information for !AD not found in replication instance file !AD", 4, "REPLINSTSECLEN", "Secondary replication instance name !AD should be 1 to 15 characters long", 2, "REPLINSTSECMTCH", "Secondary replication instance name !AD sent by receiver does not match !AD specified at source server startup", 4, "REPLINSTSECNONE", "No information found for secondary instance !AD in instance file !AD", 4, "REPLINSTSECUNDF", "Secondary replication instance name not defined", 0, "REPLINSTSEQORD", "!AD has seqno [0x!16@XQ] which is less than last record seqno [0x!16@XQ] in replication instance file !AD", 6, "REPLINSTSTNDALN", "Could not get exclusive access to replication instance file !AD", 2, "REPLREQROLLBACK", "Replication instance file !AD indicates abnormal shutdown or an incomplete ROLLBACK. Run MUPIP JOURNAL ROLLBACK first", 2, "REQROLLBACK", "Error accessing database !AD. Run MUPIP JOURNAL ROLLBACK on cluster node !AD.", 4, "UNUSEDMSG1256", "REPLUPGRADESEC : Last used in V5.4-002B", 0, "SRCSRVEXISTS", "Source server for secondary instance !AD is already running with pid !UL", 3, "SRCSRVNOTEXIST", "Source server for secondary instance !AD is not alive", 2, "SRCSRVTOOMANY", "Cannot start more than !UL source servers in replication instance !AD", 3, "JNLPOOLBADSLOT", "Source server slot for secondary instance !AD is in an inconsistent state. Pid = [!UL], State = [!UL], SlotIndex = [!UL]", 5, "NOENDIANCVT", "Unable to convert the endian format of file !AD due to !AD", 4, "ENDIANCVT", "Converted database file !AD from !AZ endian to !AZ endian on a !AZ endian system", 5, "DBENDIAN", "Database file !AD is !AZ endian on a !AZ endian system", 4, "BADCHSET", "!AD is not a valid character mapping in this context", 2, "BADCASECODE", "!AD is not a valid case conversion code", 2, "BADCHAR", "$ZCHAR(!AD) is not a valid character in the !AD encoding form", 4, "DLRCILLEGAL", "!_!AD!/!_!_!_Illegal $CHAR() value !UL", 3, "NONUTF8LOCALE", "Locale has character encoding (!AD) which is not compatible with UTF-8 character set", 2, "INVDLRCVAL", "Invalid $CHAR() value !UL", 1, "DBMISALIGN", "Database file !AD has !UL blocks which does not match alignment rules. Reconstruct the database from a backup or extend it by at least !UL blocks.", 4, "LOADINVCHSET", "Extract file CHSET (!AD) is incompatible with gtm_chset", 2, "DLLCHSETM", "Routine !AD in library !AD was compiled with CHSET=M which is different from $ZCHSET. Recompile with CHSET=UTF-8 and re-link.", 4, "DLLCHSETUTF8", "Routine !AD in library !AD was compiled with CHSET=UTF-8 which is different from $ZCHSET. Recompile with CHSET=M and re-link.", 4, "BOMMISMATCH", "!AD Byte Order Marker found when !AD character set specified", 4, "WIDTHTOOSMALL", "WIDTH should be at least 2 when device ICHSET or OCHSET is UTF-8 or UTF-16", 0, "SOCKMAX", "Attempt to exceed maximum sockets (!UL) for the SOCKET device", 1, "PADCHARINVALID", "PAD deviceparameter cannot be greater than 127", 0, "ZCNOPREALLOUTPAR", "Parameter !UL in external call !AD.!AD is an output only parameter requiring pre-allocation", 5, "SVNEXPECTED", "Special variable expected in this context", 0, "SVNONEW", "Cannot NEW this special variable", 0, "ZINTDIRECT", "Attempt to enter direct mode from $ZINTERRUPT", 0, "ZINTRECURSEIO", "Attempt to do IO to the active device in $ZINTERRUPT", 0, "MRTMAXEXCEEDED", "Maximum value of !UL for SOCKET device parameter MOREREADTIME exceeded", 1, "JNLCLOSED", "Journaling closed for database file !AD at transaction number 0x!16@XQ", 3, "RLBKNOBIMG", "ROLLBACK cannot proceed as database !AD has NOBEFORE_IMAGE journaling", 2, "RLBKJNLNOBIMG", "Journal file !AD has NOBEFORE_IMAGE journaling", 2, "RLBKLOSTTNONLY", "ROLLBACK will only create a lost transaction file (database and journal files will not be modified)", 0, "KILLBYSIGSINFO3", "!AD process !UL has been killed by a signal !UL accessing vaddress 0x!XJ", 5, "GTMSECSHRTMPPATH", "gtmsecshr path is !AD", 2, "GTMERREXIT", "GTM image has exited with errors", 0, "INVMEMRESRV", "Could not allocate GT.M memory reserve (!AD)", 2, "OPCOMMISSED", "!UL errors and !UL MBFULLs sending prior operator messages", 2, "COMMITWAITSTUCK", "Pid !UL timed out after waiting !UL minute(s) for !UL concurrent GT.M process(es) to finish commits in database file !AD", 5, "COMMITWAITPID", "Pid !UL waited !UL minute(s) for pid !UL to finish commits to block 0x!XL in database file !AD", 6, "UPDREPLSTATEOFF", "Error replicating global ^!AD as it maps to database !AD which has replication turned OFF", 4, "LITNONGRAPH", "M standard requires graphics in string literals", 0, "DBFHEADERR8", "Database file !AD: control problem: !AD was 0x!16@XQ expecting 0x!16@XQ", 6, "MMBEFOREJNL", "BEFORE image journaling cannot be set with MM access method in database file !AD", 2, "MMNOBFORRPL", "Replication cannot be used in database file !AD which uses MM access method and NOBEFORE image journaling", 2, "KILLABANDONED", "Abandoned kills counter is greater than zero for file !AD, !AD", 4, "BACKUPKILLIP", "Kill in progress indicator is set for file !AD, backup database could have incorrectly marked busy integrity errors", 2, "LOGTOOLONG", "Environment variable !AD is too long. Maximum length allowed is !UL bytes.", 3, "NOALIASLIST", "Parenthetical lists of multiple arguments cannot have a preceding alias introducer or include alias (*) forms", 0, "ALIASEXPECTED", "Alias or alias container variable expected in this context", 0, "VIEWLVN", "Invalid local variable name used with VIEW/$VIEW(): !AD", 2, "DZWRNOPAREN", "$ZWRTACxxx is not allowed inside a parenthesized SET target", 0, "DZWRNOALIAS", "$ZWRTAC cannot be aliased", 0, "FREEZEERR", "Error while trying to !AD region !AD", 4, "CLOSEFAIL", "Error while closing file descriptor !SL", 1, "CRYPTINIT", "Could not initialize encryption library while opening encrypted file !AD. !AD", 4, "CRYPTOPFAILED", "Encrypt/Decrypt operation failed for file !AD. !AD", 4, "CRYPTDLNOOPEN", "Could not load encryption library while opening encrypted file !AD. !AD", 4, "CRYPTNOV4", "!AD is an encrypted database. Cannot downgrade(to V4) with Encryption option enabled.", 2, "CRYPTNOMM", "!AD is an encrypted database. Cannot support MM access method.", 2, "CRYPTJNLWRONGHASH", "Encryption key hash mismatch between journal file !AD and corresponding database file !AD", 4, "CRYPTKEYFETCHFAILED", "Could not retrieve encryption key corresponding to file !AD. !AD", 4, "CRYPTKEYFETCHFAILEDNF", "Could not retrieve encryption key during !AD operation key. !AD", 4, "CRYPTHASHGENFAILED", "Could not generate cryptographic hash for symmetric key corresponding to file !AD. !AD", 4, "CRYPTNOPSWDINTP", "Cannot prompt for password inside a TP transaction.", 0, "BADTAG", "Unable to use file !AD (CCSID !UL) with CCSID !UL", 4, "ICUVERLT36", "!AD !UL.!UL. ICU version greater than or equal to 3.6 should be used", 4, "ICUSYMNOTFOUND", "Symbol !AD not found in the ICU libraries. ICU needs to be built with symbol-renaming disabled or gtm_icu_version environment variable needs to be properly specified", 2, "STUCKACT", "Process stuck script invoked: !AD : !AD", 4, "CALLINAFTERXIT", "After a gtm_exit, a process can never create a valid GT.M context", 0, "LOCKSPACEFULL", "No more room for LOCK slots on database file !AD", 2, "IOERROR", "Error occured while doing !AD in !AD operation -- called from module !AD at line !UL", 7, "MAXSSREACHED", "Maximum snapshots - !UL - for region !AD reached. Please wait for the existing snapshots to complete before starting a new one.", 3, "SNAPSHOTNOV4", "Cannot downgrade (to V4) while snapshots are in progress. Currently !UL snapshots are in progress for region !AD.", 3, "SSV4NOALLOW", "Database snapshots are supported only on fully upgraded V5 databases. !AD has V4 format blocks.", 2, "SSTMPDIRSTAT", "Cannot access temporary directory !AD", 2, "SSTMPCREATE", "Cannot create the temporary file in directory !AD for the requested snapshot", 2, "JNLFILEDUP", "Journal files !AD and !AD are the same", 4, "SSPREMATEOF", "Premature end of file while reading block !UL of size: !UL bytes at offset: !UL from !AD", 5, "SSFILOPERR", "Error while doing !AD operation on file !AD", 4, "REGSSFAIL", "Process !UL encountered error contributing to the snapshot for region !AD - the snapshot is no longer valid", 3, "SSSHMCLNUPFAIL", "Error while doing snapshot shared memory cleanup. Operation -- !AD. Identifier -- !UL", 3, "SSFILCLNUPFAIL", "Error while unlinking snapshot file -- !AD", 2, "SETINTRIGONLY", "ISV !AD cannot be modified outside of the trigger environment", 2, "MAXTRIGNEST", "Maximum trigger nesting level (!UL) exceeded", 1, "TRIGCOMPFAIL", "Compilation of database trigger named !AD failed", 2, "NOZTRAPINTRIG", "Use of $ZTRAP in a database trigger environment ($ZTLEVEL greater than 0) is not supported", 0, "ZTWORMHOLE2BIG", "String length of !UL bytes exceeds maximum length of !UL bytes for $ZTWORMHOLE", 2, "JNLENDIANLITTLE", "Journal file !AD is LITTLE endian on a BIG endian system", 2, "JNLENDIANBIG", "Journal file !AD is BIG endian on a LITTLE endian system", 2, "TRIGINVCHSET", "Trigger !AD for global ^!AD was created with CHSET=!AD which is different from the current $ZCHSET of this process", 6, "TRIGREPLSTATE", "Trigger cannot update replicated database file !AD since triggering update was not replicated", 2, "GVDATAGETFAIL", "Global variable DATAGET sub-operation (in KILL function) failed. Failure code: !AD.", 2, "TRIG2NOTRIG", "Sending transaction sequence number 0x!16@XQ which used triggers to a replicator that does not support triggers", 1, "ZGOTOINVLVL", "ZGOTO in a trigger running in !AD cannot ZGOTO level !UL", 3, "TRIGTCOMMIT", "TCOMMIT at $ZTLEVEL=!UL not allowed as corresponding TSTART was done at lower $ZTLEVEL=!UL", 2, "TRIGTLVLCHNG", "Detected a net transaction level ($TLEVEL) change during trigger !AD. Transaction level must be the same at exit as when the trigger started", 2, "TRIGNAMEUNIQ", "Unable to make trigger name !AD unique beyond !UL versions already loaded", 3, "ZTRIGINVACT", "Missing or invalid parameter in position !UL given to $ZTRIGGER()", 1, "INDRCOMPFAIL", "Compilation of indirection failed", 0, "QUITALSINV", "QUIT * return when the extrinsic was not invoked with SET *", 0, "PROCTERM", "!AD process termination due to !AD (return code !UL) from !AD", 7, "SRCLNNTDSP", "Source lines exceeding !UL character width are not displayed", 1, "ARROWNTDSP", "Unable to display ^----- due to length of source line", 0, "TRIGDEFBAD", "Trigger initialization failed for global ^!AD. Error while processing ^#t(\"!AD\",!AD)", 6, "TRIGSUBSCRANGE", "Trigger definition for global ^!AD has one or more invalid subscript range(s) : !AD", 4, "TRIGDATAIGNORE", "Ignoring trigger data !AD. Use MUPIP TRIGGER to load trigger definitions", 2, "TRIGIS", "!_!_Trigger name: !AD", 2, "TCOMMITDISALLOW", "TROLLBACK required after an unhandled error in trigger context", 0, "SSATTACHSHM", "Error while attaching to shared memory identifier !UL", 1, "TRIGDEFNOSYNC", "Global ^!AD has triggers defined on the !AD instance but none on the !AD instance. Current journal sequence number is 0x!16@XQ", 7, "TRESTMAX", "TRESTART not allowed in a final TP retry more than once", 0, "UNUSEDMSG1367", "TPLOCKRESTMAX : Last used in V5.5-000", 0, "GBLEXPECTED", "Global variable reference expected in this context", 0, "GVZTRIGFAIL", "ZTRIGGER of a global variable failed. Failure code: !AD.", 2, "MUUSERLBK", "Abnormal shutdown of replication-enabled database !AD detected", 2, "SETINSETTRIGONLY", "ISV !AD can only be modified in a 'SET' type trigger", 2, "DZTRIGINTRIG", "$ZTRIGGER() is not allowed inside trigger context. Trigger name: !AD", 2, "SECNODZTRIGINTP", "Sequence number 0x!16@XQ contains $ZTRIGGER() updates made inside a transaction which the current replicating instance does not support. The replicating instance must be upgraded to at least V5.4-002 to support this type of transaction. Cannot continue", 1, "BOOLSIDEFFECT", "Extrinsic ($$), External call ($&) or $INCREMENT() with potential side effects in Boolean expression", 0, "DBBADUPGRDSTATE", "Correcting conflicting values for fields describing database version upgrade state in the file header for region !AD (!AD) - make fresh backups with new journal files immediately.", 4, "WRITEWAITPID", "PID !UL waited !UL minute(s) for PID !UL to finish writing block 0x!XL in database file !AD", 6, "ZGOCALLOUTIN", "ZGOTO level 0 with entry ref not valid when using call-ins", 0, "REPLNOXENDIAN", "!AD side is running on a GT.M version that does not support cross-endian replication. Upgrade the !AD side to at least V5.3-003 to support cross-endian replication. Cannot continue", 4, "REPLXENDIANFAIL", "!AD side encountered error while doing endian conversion at journal sequence number 0x!16@XQ", 3, "ZGOTOINVLVL2", "ZGOTO 0:entryref is not valid on VMS (UNLINK is a UNIX only feature)", 0, "GTMSECSHRCHDIRF", "gtmsecshr unable to chdir to its temporary directory (!AD)", 2, "JNLORDBFLU", "Error flushing database blocks to !AD. See related messages in the operator log", 2, "ZCCLNUPRTNMISNG", "External call: Cleanup routine name missing. Cannot continue", 0, "ZCINVALIDKEYWORD", "External call: Invalid keyword found. Cannot continue", 0, "REPLNOMULTILINETRG", "Sequence number 0x!16@XQ contains a trigger definition too large for transmission to the current replicating instance, which does not support multi-line triggers - stopping replication", 1, "DBSHMNAMEDIFF", "Database file !AD points to shared memory (id = !UL) which points to a different database file !AZ", 4, "SHMREMOVED", "Removed Shared Memory id !UL corresponding to file !AD", 3, "DEVICEWRITEONLY", "Cannot read from a write-only device", 0, "ICUERROR", "ICU returned status !UL which is either unrecognized or inconsistent with the operating context", 1, "ZDATEBADDATE", "$ZDATE() date argument !AD is less than -365 (the $HOROLOG value for 01-JAN-1840) or greater than 364570088 (the $HOROLOG value for 31-DEC-999999)", 2, "ZDATEBADTIME", "$ZDATE() time argument !AD is less than 0 or greater than 86399 (the $HOROLOG value for a second before midnight)", 2, "COREINPROGRESS", "Previous core attempt failed; core generation bypassed", 0, "MAXSEMGETRETRY", "Failed to get ftok semaphore after !UL tries because it is being continually deleted", 1, "JNLNOREPL", "Replication not enabled for journal file !AD (database file !AD)", 4, "JNLRECINCMPL", "Incomplete journal record at disk address 0x!XL for file !AD while attempting to read seqno 0x!16@XQ", 4, "JNLALLOCGROW", "Increased Journal ALLOCATION from [!UL blocks] to [!UL blocks] to match AUTOSWITCHLIMIT for !AZ !AD", 5, "INVTRCGRP", "Invalid trace group specified in $gtm_trace_groups: !AD", 2, "MUINFOUINT6", "!AD : !UL [0x!XL] ; $H=!UL,!UL", 6, "NOLOCKMATCH", "No matching locks were found in !AD", 2, "BADREGION", "Region is not BG, MM, or CM", 0, "LOCKSPACEUSE", "Estimated free lock space: !UL% of !UL pages", 2, "JIUNHNDINT", "An error during $ZINTERRUPT processing was not handled: !AD", 2, "GTMASSERT2", "!AD - Assert failed !AD line !UL for expression (!AD)", 7, "ZTRIGNOTRW", "ZTRIGGER cannot operate on read-only region !AD", 2, "TRIGMODREGNOTRW", "Trigger(s) cannot be added/changed/deleted because region !AD is read-only", 2, "INSNOTJOINED", "Replicating Instance !AD is not a member of the same Group as Instance !AD", 4, "INSROLECHANGE", "Supplementary Instance !AD and non-Supplementary Instance !AD belong to the same Group", 4, "INSUNKNOWN", "Supplementary Instance !AD has no instance definition for non-Supplementary Instance !AD", 4, "NORESYNCSUPPLONLY", "NORESYNC only supported for Supplementary Instances", 0, "NORESYNCUPDATERONLY", "NORESYNC qualifier only allowed on a Supplementary Instance which allows local updates", 0, "NOSUPPLSUPPL", "Instance !AD is configured to perform local updates so it cannot receive from Supplementary Instance !AD", 4, "REPL2OLD", "Instance !AD uses a GT.M version that does not support connection with the current version on instance !AD", 4, "EXTRFILEXISTS", "Error opening output file: !AD -- File exists", 2, "MUUSERECOV", "Abnormal shutdown of journaled database !AD detected", 2, "SECNOTSUPPLEMENTARY", "!AD is a Supplementary Instance and so cannot act as a source to non-Supplementary Instance !AD ", 4, "SUPRCVRNEEDSSUPSRC", "Instance !AD is not configured to perform local updates so it cannot act as a receiver for non-Supplementary Instance !AD", 4, "UNUSEDMSG1417", "SYNCTOSAMETYPE: Never used before so slot free for reuse", 0, "UNUSEDMSG1418", "TARGINSRUNNING: Never used before so slot free for reuse", 0, "UPDSYNC2MTINS", "Can only UPDATERESYNC with an empty instance file", 0, "UPDSYNCINSTFILE", "Error with instance file name specified in UPDATERESYNC qualifier", 0, "REUSEINSTNAME", "Error with instance name specified in REUSE qualifier", 0, "RCVRMANYSTRMS", "Receiver server now connecting to source stream [!2UL] but had previously connected to a different stream [!2UL]", 2, "RSYNCSTRMVAL", "RSYNC_STRM qualifier can only take on a value from 0 to 15", 0, "RLBKSTRMSEQ", "Stream journal seqno of the instance after rollback is Stream !2UL : Seqno !@ZQ [0x!16@XQ]", 3, "RESOLVESEQSTRM", "Resolving until stream sequence number Stream !2UL : Seqno !@ZQ [0x!16@XQ]", 3, "REPLINSTDBSTRM", "Replication instance file !AD has seqno [0x!16@XQ] for Stream !2UL while database has a different seqno [0x!16@XQ]", 5, "RESUMESTRMNUM", "Error with stream number specified in RESUME qualifier", 0, "ORLBKSTART", "ONLINE ROLLBACK started on instance !AD corresponding to !AD", 4, "ORLBKTERMNTD", "ONLINE ROLLBACK terminated on instance !AD corresponding to !AD with the above errors", 4, "ORLBKCMPLT", "ONLINE ROLLBACK completed successfully on instance !AD corresponding to !AD", 4, "ORLBKNOSTP", "ONLINE ROLLBACK proceeding with database updates. MUPIP STOP will no longer be allowed", 0, "ORLBKFRZPROG", "!AD : waiting for FREEZE on region !AD (!AD) to clear", 6, "ORLBKFRZOVER", "!AD : FREEZE on region !AD (!AD) cleared", 6, "ORLBKNOV4BLK", "Region !AD (!AD) has V4 format blocks. Database upgrade required. ONLINE ROLLBACK cannot continue", 4, "DBROLLEDBACK", "Concurrent ONLINE ROLLBACK detected on one or more regions. The current operation is no longer valid", 0, "DSEWCREINIT", "Database cache reinitialized by DSE for region !AD", 2, "MURNDWNOVRD", "OVERRIDE qualifier used with MUPIP RUNDOWN on database file !AD", 2, "REPLONLNRLBK", "ONLINE ROLLBACK detected. Starting afresh", 0, "SRVLCKWT2LNG", "PID !UL is holding the source server lock. Waited for !UL minute(s). Now exiting", 2, "IGNBMPMRKFREE", "Ignoring bitmap free-up operation for region !AD (!AD) due to concurrent ONLINE ROLLBACK", 4, "PERMGENFAIL", "Failed to determine access permissions to use for creation of !AD for file !AD", 4, "PERMGENDIAG", "Permissions: Proc(uid:!UL,gid:!UL), DB File(uid:!UL,gid:!UL,perm:!AD), Lib File(gid:!UL,perm:!AD), Group Mem(opener:!UL,owner:!UL)", 11, "MUTRUNC1ATIME", "Process with PID !UL already performing truncate in region !AD", 3, "MUTRUNCBACKINPROG", "Truncate detected concurrent backup in progress for region !AD", 2, "MUTRUNCERROR", "Truncate of region !AD encountered service error !AD", 4, "MUTRUNCFAIL", "Truncate failed after reorg", 0, "MUTRUNCNOSPACE", "Region !AD has insufficient space to meet truncate target percentage of !UL", 3, "MUTRUNCNOTBG", "Region !AD does not have access method BG ", 2, "MUTRUNCNOV4", "Region !AD is not fully upgraded from V4 format.", 2, "MUTRUNCPERCENT", "Truncate threshold percentage should be from 0 to 99", 0, "MUTRUNCSSINPROG", "Truncate detected concurrent snapshot in progress for region !AD", 2, "MUTRUNCSUCCESS", "Database file !AD truncated from 0x!XL blocks to 0x!XL at transaction 0x!16@XQ", 5, "RSYNCSTRMSUPPLONLY", "RSYNC_STRM qualifier only supported for Supplementary Instances", 0, "STRMNUMIS", "Stream # is !2UL", 1, "STRMNUMMISMTCH1", "Stream !2UL exists on the receiver instance file but is unknown on the source instance", 1, "STRMNUMMISMTCH2", "Stream !2UL exists on the source instance file but is unknown on the receiver instance", 1, "STRMSEQMISMTCH", "Unable to play update on Stream !2UL with seqno [0x!16@XQ] as receiving instance has a different stream seqno [0x!16@XQ]", 3, "LOCKSPACEINFO", "Region: !AD: processes on queue: !UL/!UL; LOCK slots in use: !UL/!UL; name space!ADfull", 8, "JRTNULLFAIL", "Applying NULL journal record failed. Failure code: !AD.", 2, "LOCKSUB2LONG", "Following subscript is !UL bytes long which exceeds 255 byte limit.", 1, "RESRCWAIT", "Waiting briefly for the !AD semaphore for region !AD (!AD) was held by PID !UL (Sem. ID: !UL).", 8, "RESRCINTRLCKBYPAS", "!AD with PID !UL bypassing the !AD semaphore for region !AD (!AD) was held by PID !UL.", 10, "DBFHEADERRANY", "Database file !AD: control problem: !AD was 0x!XJ expecting 0x!XJ", 6, "REPLINSTFROZEN", "Instance !AZ is now Frozen", 1, "REPLINSTFREEZECOMMENT", "Freeze Comment: !AZ", 1, "REPLINSTUNFROZEN", "Instance !AZ is now Unfrozen", 1, "DSKNOSPCAVAIL", "Attempted write to file !AD failed due to lack of disk space. Retrying indefinitely.", 2, "DSKNOSPCBLOCKED", "Retry of write to file !AD suspended due to new instance freeze. Waiting for instance to be unfrozen.", 2, "DSKSPCAVAILABLE", "Write to file !AD succeeded after out-of-space condition cleared", 2, "ENOSPCQIODEFER", "Write to file !AD deferred due to lack of disk space", 2, "CUSTOMFILOPERR", "Error while doing !AD operation on file !AD", 4, "CUSTERRNOTFND", "Error mnemonic !AD specified in custom errors file is not valid for this version of GT.M", 2, "CUSTERRSYNTAX", "Syntax error in file !AD at line number !UL", 3, "ORLBKINPROG", "Online ROLLBACK in progress by PID !UL in region !AD", 3, "DBSPANGLOINCMP", "!AD Spanning node is missing. Block no !UL of spanning node is missing", 3, "DBSPANCHUNKORD", "!AD Chunk of !UL blocks is out of order", 3, "DBDATAMX", "!AD Record too large", 2, "DBIOERR", "Error while doing write operation on region !AD (!AD)", 4, "INITORRESUME", "UPDATERESYNC on a Supplementary Instance must additionally specify INITIALIZE or RESUME", 0, "GTMSECSHRNOARG0", "gtmsecshr cannot identify its origin - argv[0] is null", 0, "GTMSECSHRISNOT", "gtmsecshr is not running as gtmsecshr but !AD - must be gtmsecshr", 2, "GTMSECSHRBADDIR", "gtmsecshr is not running from $gtm_dist/gtmsecshrdir or $gtm_dist cannot be determined", 0, "JNLBUFFREGUPD", "Journal file buffer size for region !AD has been adjusted from !UL to !UL.", 4, "JNLBUFFDBUPD", "Journal file buffer size for database file !AD has been adjusted from !UL to !UL.", 4, "LOCKINCR2HIGH", "Attempt to increment a LOCK more than !UL times", 1, "LOCKIS", "!_!_Resource name: !AD", 2, "LDSPANGLOINCMP", "Incomplete spanning node found during load", 0, "MUFILRNDWNFL2", "Database section (id = !UL) belonging to database file !AD rundown failed", 3, "MUINSTFROZEN", "!AD : Instance !AZ is frozen. Waiting for instance to be unfrozen before proceeding with writes to database file !AD", 5, "MUINSTUNFROZEN", "!AD : Instance !AZ is now Unfrozen. Continuing with writes to database file !AD", 5, "GTMEISDIR", "!AD : Is a directory", 2, "SPCLZMSG", "The following error message cannot be driven through ZMESSAGE", 0, "MUNOTALLINTEG", "At least one region skipped. See the earlier messages", 0, "BKUPRUNNING", "Process !UL is currently backing up region !AD. Cannot start another backup.", 3, "MUSIZEINVARG", "MUPIP SIZE : Invalid parameter value for: !AD", 2, "MUSIZEFAIL", "MUPIP SIZE : failed. Failure code: !AD.", 2, "SIDEEFFECTEVAL", "Extrinsic ($$), External call ($&) or $INCREMENT() with potential side effects in actuallist, function arguments, non-Boolean binary operands or subscripts", 0, "CRYPTINIT2", "Could not initialize encryption library !AD. !AD", 4, "CRYPTDLNOOPEN2", "Could not load encryption library !AD. !AD", 4, "CRYPTBADCONFIG", "Could not retrieve data from encrypted file !AD due to bad encryption configuration. !AD", 4, "DBCOLLREQ", "JOURNAL EXTRACT proceeding without collation information for globals in database. !AD !AD", 4, "SETEXTRENV", "Database files are missing or Instance is frozen; supply the database files, wait for the freeze to lift or define gtm_extract_nocol to extract possibly incorrect collation", 0, "NOTALLDBRNDWN", "Not all regions were successfully rundown", 0, "TPRESTNESTERR", "TP restart signaled while handing error - treated as nested error - Use TROLLBACK in error handler to avoid this", 0, "JNLFILRDOPN", "Error opening journal file !AD for read for database file !AD", 4, "SEQNUMSEARCHTIMEOUT", "Timed out trying to find sequence number !@ZQ [0x!16@XQ] in Journal File(s). See above messages for details. Source server exiting", 2, "FTOKKEY", "FTOK key 0x!XL", 1, "SEMID", "Semaphore id !UL", 1, "JNLQIOSALVAGE", "Journal IO lock salvaged", 0, "FAKENOSPCLEARED", "DEBUG: All fake ENOSPC flags were cleared !UL heartbeats ago", 1, "MMFILETOOLARGE", "Size of !AD region (!AD) is larger than maximum size supported for memory mapped I/O on this platform", 4, "BADZPEEKARG", "Missing, invalid or surplus !AD parameter for $ZPEEK()", 2, "BADZPEEKRANGE", "Access exception raised in memory range given to $ZPEEK()", 0, "BADZPEEKFMT", "$ZPEEK() value length inappropriate for selected format", 0, "DBMBMINCFREFIXED", "Master bitmap incorrectly marks local bitmap 0x!XL as free. Auto-corrected", 1, "NULLENTRYREF", "JOB command did not specify entryref", 0, "ZPEEKNORPLINFO", "$ZPEEK() unable to access requested replication structure", 0, "MMREGNOACCESS", "Region !AD (!AD) is no longer accessible. See prior error messages in the operator and application error logs", 4, "MALLOCMAXUNIX", "Exceeded maximum allocation defined by $gtm_max_storalloc", 0, "MALLOCMAXVMS", "Exceeded maximum allocation defined by GTM_MAX_STORALLOC", 0, "HOSTCONFLICT", "Host !AD could not open database file !AD because it is marked as already open on node !AD", 6, "GETADDRINFO", "Error in getting address info", 0, "GETNAMEINFO", "Error in getting name info", 0, "SOCKBIND", "Error in binding TCP socket", 0, "INSTFRZDEFER", "Instance Freeze initiated by !AD error on region !AD deferred due to critical resource conflict", 4, "REGOPENRETRY", "Attempt to open region !AD (!AD) using startup shortcut failed due to conflicting database shutdown. Retrying...", 4, "REGOPENFAIL", "Failed to open region !AD (!AD) due to conflicting database shutdown activity", 4, }; LITDEF int ERR_ACK = 150372361; LITDEF int ERR_BREAKZST = 150372371; LITDEF int ERR_BADACCMTHD = 150372379; LITDEF int ERR_BADJPIPARAM = 150372386; LITDEF int ERR_BADSYIPARAM = 150372394; LITDEF int ERR_BITMAPSBAD = 150372402; LITDEF int ERR_BREAK = 150372411; LITDEF int ERR_BREAKDEA = 150372419; LITDEF int ERR_BREAKZBA = 150372427; LITDEF int ERR_STATCNT = 150372435; LITDEF int ERR_BTFAIL = 150372442; LITDEF int ERR_MUPRECFLLCK = 150372450; LITDEF int ERR_CMD = 150372458; LITDEF int ERR_COLON = 150372466; LITDEF int ERR_COMMA = 150372474; LITDEF int ERR_COMMAORRPAREXP = 150372482; LITDEF int ERR_COMMENT = 150372491; LITDEF int ERR_CTRAP = 150372498; LITDEF int ERR_CTRLC = 150372507; LITDEF int ERR_CTRLY = 150372515; LITDEF int ERR_DBCCERR = 150372522; LITDEF int ERR_DUPTOKEN = 150372530; LITDEF int ERR_DBJNLNOTMATCH = 150372538; LITDEF int ERR_DBFILERR = 150372546; LITDEF int ERR_DBNOTGDS = 150372554; LITDEF int ERR_DBOPNERR = 150372562; LITDEF int ERR_DBRDERR = 150372570; LITDEF int ERR_CCEDUMPNOW = 150372580; LITDEF int ERR_DEVPARINAP = 150372586; LITDEF int ERR_RECORDSTAT = 150372595; LITDEF int ERR_NOTGBL = 150372602; LITDEF int ERR_DEVPARPROT = 150372610; LITDEF int ERR_PREMATEOF = 150372618; LITDEF int ERR_GVINVALID = 150372626; LITDEF int ERR_DEVPARTOOBIG = 150372634; LITDEF int ERR_DEVPARUNK = 150372642; LITDEF int ERR_DEVPARVALREQ = 150372650; LITDEF int ERR_DEVPARMNEG = 150372658; LITDEF int ERR_DSEBLKRDFAIL = 150372666; LITDEF int ERR_DSEFAIL = 150372674; LITDEF int ERR_NOTALLREPLON = 150372680; LITDEF int ERR_BADLKIPARAM = 150372690; LITDEF int ERR_JNLREADBOF = 150372698; LITDEF int ERR_DVIKEYBAD = 150372706; LITDEF int ERR_ENQ = 150372713; LITDEF int ERR_EQUAL = 150372722; LITDEF int ERR_ERRORSUMMARY = 150372730; LITDEF int ERR_ERRWEXC = 150372738; LITDEF int ERR_ERRWIOEXC = 150372746; LITDEF int ERR_ERRWZBRK = 150372754; LITDEF int ERR_ERRWZTRAP = 150372762; LITDEF int ERR_NUMUNXEOR = 150372770; LITDEF int ERR_EXPR = 150372778; LITDEF int ERR_STRUNXEOR = 150372786; LITDEF int ERR_JNLEXTEND = 150372794; LITDEF int ERR_FCHARMAXARGS = 150372802; LITDEF int ERR_FCNSVNEXPECTED = 150372810; LITDEF int ERR_FNARGINC = 150372818; LITDEF int ERR_JNLACCESS = 150372826; LITDEF int ERR_TRANSNOSTART = 150372834; LITDEF int ERR_FNUMARG = 150372842; LITDEF int ERR_FOROFLOW = 150372850; LITDEF int ERR_YDIRTSZ = 150372858; LITDEF int ERR_JNLSUCCESS = 150372865; LITDEF int ERR_GBLNAME = 150372874; LITDEF int ERR_GBLOFLOW = 150372882; LITDEF int ERR_CORRUPT = 150372890; LITDEF int ERR_GTMCHECK = 150372900; LITDEF int ERR_GVDATAFAIL = 150372906; LITDEF int ERR_EORNOTFND = 150372914; LITDEF int ERR_GVGETFAIL = 150372922; LITDEF int ERR_GVIS = 150372931; LITDEF int ERR_GVKILLFAIL = 150372938; LITDEF int ERR_GVNAKED = 150372946; LITDEF int ERR_GVNEXTARG = 150372954; LITDEF int ERR_GVORDERFAIL = 150372962; LITDEF int ERR_GVPUTFAIL = 150372970; LITDEF int ERR_PATTABSYNTAX = 150372978; LITDEF int ERR_GVSUBOFLOW = 150372986; LITDEF int ERR_GVUNDEF = 150372994; LITDEF int ERR_TRANSNEST = 150373002; LITDEF int ERR_INDEXTRACHARS = 150373010; LITDEF int ERR_UNUSEDMSG260 = 150373018; LITDEF int ERR_INDRMAXLEN = 150373026; LITDEF int ERR_INSFFBCNT = 150373034; LITDEF int ERR_INTEGERRS = 150373042; LITDEF int ERR_INVCMD = 150373048; LITDEF int ERR_INVFCN = 150373058; LITDEF int ERR_INVOBJ = 150373066; LITDEF int ERR_INVSVN = 150373074; LITDEF int ERR_IOEOF = 150373082; LITDEF int ERR_IONOTOPEN = 150373090; LITDEF int ERR_MUPIPINFO = 150373099; LITDEF int ERR_IVTIME = 150373106; LITDEF int ERR_JOBFAIL = 150373114; LITDEF int ERR_JOBLABOFF = 150373122; LITDEF int ERR_JOBPARNOVAL = 150373130; LITDEF int ERR_JOBPARNUM = 150373138; LITDEF int ERR_JOBPARSTR = 150373146; LITDEF int ERR_JOBPARUNK = 150373154; LITDEF int ERR_JOBPARVALREQ = 150373162; LITDEF int ERR_JUSTFRACT = 150373170; LITDEF int ERR_KEY2BIG = 150373178; LITDEF int ERR_LABELEXPECTED = 150373186; LITDEF int ERR_LABELMISSING = 150373194; LITDEF int ERR_LABELUNKNOWN = 150373202; LITDEF int ERR_DIVZERO = 150373210; LITDEF int ERR_LKNAMEXPECTED = 150373218; LITDEF int ERR_JNLRDERR = 150373226; LITDEF int ERR_LOADRUNNING = 150373234; LITDEF int ERR_LPARENMISSING = 150373242; LITDEF int ERR_LSEXPECTED = 150373250; LITDEF int ERR_LVORDERARG = 150373258; LITDEF int ERR_MAXFORARGS = 150373266; LITDEF int ERR_TRANSMINUS = 150373274; LITDEF int ERR_MAXNRSUBSCRIPTS = 150373282; LITDEF int ERR_MAXSTRLEN = 150373290; LITDEF int ERR_JNLDBERR = 150373298; LITDEF int ERR_JNLFILOPN = 150373306; LITDEF int ERR_MBXRDONLY = 150373314; LITDEF int ERR_JNLINVALID = 150373322; LITDEF int ERR_MBXWRTONLY = 150373330; LITDEF int ERR_MEMORY = 150373340; LITDEF int ERR_MTBLKTOOBIG = 150373346; LITDEF int ERR_MTBLKTOOSM = 150373354; LITDEF int ERR_MTFIXRECSZ = 150373362; LITDEF int ERR_MTIS = 150373371; LITDEF int ERR_MTRDBADBLK = 150373378; LITDEF int ERR_MTRDONLY = 150373386; LITDEF int ERR_MTRDTHENWRT = 150373394; LITDEF int ERR_MTRECGTRBLK = 150373402; LITDEF int ERR_MTRECTOOBIG = 150373410; LITDEF int ERR_MTRECTOOSM = 150373418; LITDEF int ERR_JNLTMQUAL3 = 150373426; LITDEF int ERR_MULTLAB = 150373434; LITDEF int ERR_BLKCNT = 150373443; LITDEF int ERR_CCEDUMPOFF = 150373452; LITDEF int ERR_NOPLACE = 150373458; LITDEF int ERR_JNLCLOSE = 150373466; LITDEF int ERR_NOTPRINCIO = 150373472; LITDEF int ERR_NOTTOEOFONPUT = 150373482; LITDEF int ERR_NOZBRK = 150373491; LITDEF int ERR_NULSUBSC = 150373498; LITDEF int ERR_NUMOFLOW = 150373506; LITDEF int ERR_PARFILSPC = 150373514; LITDEF int ERR_PATCLASS = 150373522; LITDEF int ERR_PATCODE = 150373530; LITDEF int ERR_PATLIT = 150373538; LITDEF int ERR_PATMAXLEN = 150373546; LITDEF int ERR_LPARENREQD = 150373554; LITDEF int ERR_PATUPPERLIM = 150373562; LITDEF int ERR_PCONDEXPECTED = 150373570; LITDEF int ERR_PRCNAMLEN = 150373578; LITDEF int ERR_RANDARGNEG = 150373586; LITDEF int ERR_DBPRIVERR = 150373594; LITDEF int ERR_REC2BIG = 150373602; LITDEF int ERR_RHMISSING = 150373610; LITDEF int ERR_DEVICEREADONLY = 150373618; LITDEF int ERR_COLLDATAEXISTS = 150373626; LITDEF int ERR_ROUTINEUNKNOWN = 150373634; LITDEF int ERR_RPARENMISSING = 150373642; LITDEF int ERR_RTNNAME = 150373650; LITDEF int ERR_VIEWGVN = 150373658; LITDEF int ERR_RTSLOC = 150373667; LITDEF int ERR_RWARG = 150373674; LITDEF int ERR_RWFORMAT = 150373682; LITDEF int ERR_JNLWRTDEFER = 150373691; LITDEF int ERR_SELECTFALSE = 150373698; LITDEF int ERR_SPOREOL = 150373706; LITDEF int ERR_SRCLIN = 150373715; LITDEF int ERR_SRCLOC = 150373723; LITDEF int ERR_SRCLOCUNKNOWN = 150373731; LITDEF int ERR_STACKCRIT = 150373738; LITDEF int ERR_STACKOFLOW = 150373748; LITDEF int ERR_STACKUNDERFLO = 150373754; LITDEF int ERR_STRINGOFLOW = 150373762; LITDEF int ERR_SVNOSET = 150373770; LITDEF int ERR_VIEWFN = 150373778; LITDEF int ERR_TERMASTQUOTA = 150373786; LITDEF int ERR_TEXTARG = 150373794; LITDEF int ERR_TMPSTOREMAX = 150373802; LITDEF int ERR_VIEWCMD = 150373810; LITDEF int ERR_JNI = 150373818; LITDEF int ERR_TXTSRCFMT = 150373826; LITDEF int ERR_UIDMSG = 150373834; LITDEF int ERR_UIDSND = 150373842; LITDEF int ERR_UNDEF = 150373850; LITDEF int ERR_UNIMPLOP = 150373858; LITDEF int ERR_VAREXPECTED = 150373866; LITDEF int ERR_VARRECBLKSZ = 150373874; LITDEF int ERR_MAXARGCNT = 150373882; LITDEF int ERR_GTMSECSHRSEMGET = 150373890; LITDEF int ERR_VIEWARGCNT = 150373898; LITDEF int ERR_GTMSECSHRDMNSTARTED = 150373907; LITDEF int ERR_ZATTACHERR = 150373914; LITDEF int ERR_ZDATEFMT = 150373922; LITDEF int ERR_ZEDFILSPEC = 150373930; LITDEF int ERR_ZFILENMTOOLONG = 150373938; LITDEF int ERR_ZFILKEYBAD = 150373946; LITDEF int ERR_ZFILNMBAD = 150373954; LITDEF int ERR_ZGOTOLTZERO = 150373962; LITDEF int ERR_ZGOTOTOOBIG = 150373970; LITDEF int ERR_ZLINKFILE = 150373978; LITDEF int ERR_ZPARSETYPE = 150373986; LITDEF int ERR_ZPARSFLDBAD = 150373994; LITDEF int ERR_ZPIDBADARG = 150374002; LITDEF int ERR_ZPRIVARGBAD = 150374010; LITDEF int ERR_ZPRIVSYNTAXERR = 150374018; LITDEF int ERR_ZPRTLABNOTFND = 150374026; LITDEF int ERR_VIEWAMBIG = 150374034; LITDEF int ERR_VIEWNOTFOUND = 150374042; LITDEF int ERR_ZSETPRVARGBAD = 150374050; LITDEF int ERR_INVSPECREC = 150374058; LITDEF int ERR_ZSETPRVSYNTAX = 150374066; LITDEF int ERR_ZSRCHSTRMCT = 150374074; LITDEF int ERR_VERSION = 150374082; LITDEF int ERR_MUNOTALLSEC = 150374088; LITDEF int ERR_MUSECDEL = 150374099; LITDEF int ERR_MUSECNOTDEL = 150374107; LITDEF int ERR_RPARENREQD = 150374114; LITDEF int ERR_ZGBLDIRACC = 150374122; LITDEF int ERR_GVNAKEDEXTNM = 150374130; LITDEF int ERR_EXTGBLDEL = 150374138; LITDEF int ERR_DSEWCINITCON = 150374147; LITDEF int ERR_LASTFILCMPLD = 150374155; LITDEF int ERR_NOEXCNOZTRAP = 150374163; LITDEF int ERR_UNSDCLASS = 150374170; LITDEF int ERR_UNSDDTYPE = 150374178; LITDEF int ERR_ZCUNKTYPE = 150374186; LITDEF int ERR_ZCUNKMECH = 150374194; LITDEF int ERR_ZCUNKQUAL = 150374202; LITDEF int ERR_JNLDBTNNOMATCH = 150374210; LITDEF int ERR_ZCALLTABLE = 150374218; LITDEF int ERR_ZCARGMSMTCH = 150374226; LITDEF int ERR_ZCCONMSMTCH = 150374234; LITDEF int ERR_ZCOPT0 = 150374242; LITDEF int ERR_ZCSTATUS = 150374250; LITDEF int ERR_ZCUSRRTN = 150374258; LITDEF int ERR_ZCPOSOVR = 150374266; LITDEF int ERR_ZCINPUTREQ = 150374274; LITDEF int ERR_JNLTNOUTOFSEQ = 150374282; LITDEF int ERR_ACTRANGE = 150374290; LITDEF int ERR_ZCCONVERT = 150374298; LITDEF int ERR_ZCRTENOTF = 150374306; LITDEF int ERR_GVRUNDOWN = 150374314; LITDEF int ERR_LKRUNDOWN = 150374322; LITDEF int ERR_IORUNDOWN = 150374330; LITDEF int ERR_FILENOTFND = 150374338; LITDEF int ERR_MUFILRNDWNFL = 150374346; LITDEF int ERR_JNLTMQUAL1 = 150374354; LITDEF int ERR_FORCEDHALT = 150374364; LITDEF int ERR_LOADEOF = 150374370; LITDEF int ERR_WILLEXPIRE = 150374379; LITDEF int ERR_LOADEDBG = 150374386; LITDEF int ERR_LABELONLY = 150374394; LITDEF int ERR_MUREORGFAIL = 150374402; LITDEF int ERR_GVZPREVFAIL = 150374410; LITDEF int ERR_MULTFORMPARM = 150374418; LITDEF int ERR_QUITARGUSE = 150374426; LITDEF int ERR_NAMEEXPECTED = 150374434; LITDEF int ERR_FALLINTOFLST = 150374442; LITDEF int ERR_NOTEXTRINSIC = 150374450; LITDEF int ERR_GTMSECSHRREMSEMFAIL = 150374458; LITDEF int ERR_FMLLSTMISSING = 150374466; LITDEF int ERR_ACTLSTTOOLONG = 150374474; LITDEF int ERR_ACTOFFSET = 150374482; LITDEF int ERR_MAXACTARG = 150374490; LITDEF int ERR_GTMSECSHRREMSEM = 150374498; LITDEF int ERR_JNLTMQUAL2 = 150374506; LITDEF int ERR_GDINVALID = 150374514; LITDEF int ERR_ASSERT = 150374524; LITDEF int ERR_MUFILRNDWNSUC = 150374531; LITDEF int ERR_LOADEDSZ = 150374538; LITDEF int ERR_QUITARGLST = 150374546; LITDEF int ERR_QUITARGREQD = 150374554; LITDEF int ERR_CRITRESET = 150374562; LITDEF int ERR_UNKNOWNFOREX = 150374572; LITDEF int ERR_FSEXP = 150374578; LITDEF int ERR_WILDCARD = 150374586; LITDEF int ERR_DIRONLY = 150374594; LITDEF int ERR_FILEPARSE = 150374602; LITDEF int ERR_QUALEXP = 150374610; LITDEF int ERR_BADQUAL = 150374618; LITDEF int ERR_QUALVAL = 150374626; LITDEF int ERR_ZROSYNTAX = 150374634; LITDEF int ERR_COMPILEQUALS = 150374642; LITDEF int ERR_ZLNOOBJECT = 150374650; LITDEF int ERR_ZLMODULE = 150374658; LITDEF int ERR_DBBLEVMX = 150374667; LITDEF int ERR_DBBLEVMN = 150374675; LITDEF int ERR_DBBSIZMN = 150374682; LITDEF int ERR_DBBSIZMX = 150374690; LITDEF int ERR_DBRSIZMN = 150374698; LITDEF int ERR_DBRSIZMX = 150374706; LITDEF int ERR_DBCMPNZRO = 150374714; LITDEF int ERR_DBSTARSIZ = 150374723; LITDEF int ERR_DBSTARCMP = 150374731; LITDEF int ERR_DBCMPMX = 150374739; LITDEF int ERR_DBKEYMX = 150374746; LITDEF int ERR_DBKEYMN = 150374754; LITDEF int ERR_DBCMPBAD = 150374760; LITDEF int ERR_DBKEYORD = 150374770; LITDEF int ERR_DBPTRNOTPOS = 150374778; LITDEF int ERR_DBPTRMX = 150374786; LITDEF int ERR_DBPTRMAP = 150374795; LITDEF int ERR_IFBADPARM = 150374802; LITDEF int ERR_IFNOTINIT = 150374810; LITDEF int ERR_GTMSECSHRSOCKET = 150374818; LITDEF int ERR_LOADBGSZ = 150374826; LITDEF int ERR_LOADFMT = 150374834; LITDEF int ERR_LOADFILERR = 150374842; LITDEF int ERR_NOREGION = 150374850; LITDEF int ERR_PATLOAD = 150374858; LITDEF int ERR_EXTRACTFILERR = 150374866; LITDEF int ERR_FREEZE = 150374875; LITDEF int ERR_NOSELECT = 150374880; LITDEF int ERR_EXTRFAIL = 150374890; LITDEF int ERR_LDBINFMT = 150374898; LITDEF int ERR_NOPREVLINK = 150374906; LITDEF int ERR_CCEDUMPON = 150374916; LITDEF int ERR_CCEDMPQUALREQ = 150374922; LITDEF int ERR_CCEDBDUMP = 150374931; LITDEF int ERR_CCEDBNODUMP = 150374939; LITDEF int ERR_CCPMBX = 150374946; LITDEF int ERR_REQRUNDOWN = 150374954; LITDEF int ERR_CCPINTQUE = 150374962; LITDEF int ERR_CCPBADMSG = 150374970; LITDEF int ERR_CNOTONSYS = 150374978; LITDEF int ERR_CCPNAME = 150374988; LITDEF int ERR_CCPNOTFND = 150374994; LITDEF int ERR_OPRCCPSTOP = 150375003; LITDEF int ERR_SELECTSYNTAX = 150375012; LITDEF int ERR_LOADABORT = 150375018; LITDEF int ERR_FNOTONSYS = 150375026; LITDEF int ERR_AMBISYIPARAM = 150375034; LITDEF int ERR_PREVJNLNOEOF = 150375042; LITDEF int ERR_LKSECINIT = 150375050; LITDEF int ERR_MTDOSLAB = 150375058; LITDEF int ERR_MTDOSFOR = 150375066; LITDEF int ERR_MTINVLAB = 150375074; LITDEF int ERR_TXTSRCMAT = 150375082; LITDEF int ERR_CCENOGROUP = 150375088; LITDEF int ERR_BADDBVER = 150375098; LITDEF int ERR_LINKVERSION = 150375108; LITDEF int ERR_TOTALBLKMAX = 150375114; LITDEF int ERR_LOADCTRLY = 150375123; LITDEF int ERR_CLSTCONFLICT = 150375130; LITDEF int ERR_SRCNAM = 150375139; LITDEF int ERR_LCKGONE = 150375145; LITDEF int ERR_SUB2LONG = 150375154; LITDEF int ERR_EXTRACTCTRLY = 150375163; LITDEF int ERR_CCENOWORLD = 150375168; LITDEF int ERR_GVQUERYFAIL = 150375178; LITDEF int ERR_LCKSCANCELLED = 150375186; LITDEF int ERR_INVNETFILNM = 150375194; LITDEF int ERR_NETDBOPNERR = 150375202; LITDEF int ERR_BADSRVRNETMSG = 150375210; LITDEF int ERR_BADGTMNETMSG = 150375218; LITDEF int ERR_SERVERERR = 150375226; LITDEF int ERR_NETFAIL = 150375234; LITDEF int ERR_NETLCKFAIL = 150375242; LITDEF int ERR_TTINVFILTER = 150375251; LITDEF int ERR_MTANSILAB = 150375258; LITDEF int ERR_MTANSIFOR = 150375266; LITDEF int ERR_BADTRNPARAM = 150375274; LITDEF int ERR_DSEONLYBGMM = 150375280; LITDEF int ERR_DSEINVLCLUSFN = 150375288; LITDEF int ERR_RDFLTOOSHORT = 150375298; LITDEF int ERR_TIMRBADVAL = 150375307; LITDEF int ERR_CCENOSYSLCK = 150375312; LITDEF int ERR_CCPGRP = 150375324; LITDEF int ERR_UNSOLCNTERR = 150375330; LITDEF int ERR_BACKUPCTRL = 150375339; LITDEF int ERR_NOCCPPID = 150375346; LITDEF int ERR_CCPJNLOPNERR = 150375354; LITDEF int ERR_LCKSGONE = 150375361; LITDEF int ERR_ZLKIDBADARG = 150375370; LITDEF int ERR_DBFILOPERR = 150375378; LITDEF int ERR_CCERDERR = 150375386; LITDEF int ERR_CCEDBCL = 150375395; LITDEF int ERR_CCEDBNTCL = 150375403; LITDEF int ERR_CCEWRTERR = 150375410; LITDEF int ERR_CCEBADFN = 150375418; LITDEF int ERR_CCERDTIMOUT = 150375426; LITDEF int ERR_CCPSIGCONT = 150375435; LITDEF int ERR_CCEBGONLY = 150375442; LITDEF int ERR_CCENOCCP = 150375451; LITDEF int ERR_CCECCPPID = 150375459; LITDEF int ERR_CCECLSTPRCS = 150375467; LITDEF int ERR_ZSHOWBADFUNC = 150375474; LITDEF int ERR_NOTALLJNLEN = 150375480; LITDEF int ERR_ZSHOWGLOSMALL = 150375490; LITDEF int ERR_NOLBRSRC = 150375498; LITDEF int ERR_INVZSTEP = 150375506; LITDEF int ERR_ZSTEPARG = 150375514; LITDEF int ERR_INVSTRLEN = 150375522; LITDEF int ERR_RECCNT = 150375531; LITDEF int ERR_TEXT = 150375539; LITDEF int ERR_ZWRSPONE = 150375546; LITDEF int ERR_FILEDEL = 150375555; LITDEF int ERR_JNLBADLABEL = 150375562; LITDEF int ERR_JNLREADEOF = 150375570; LITDEF int ERR_JNLRECFMT = 150375578; LITDEF int ERR_BLKTOODEEP = 150375586; LITDEF int ERR_NESTFORMP = 150375594; LITDEF int ERR_BINHDR = 150375603; LITDEF int ERR_GOQPREC = 150375611; LITDEF int ERR_LDGOQFMT = 150375618; LITDEF int ERR_BEGINST = 150375627; LITDEF int ERR_INVMVXSZ = 150375636; LITDEF int ERR_JNLWRTNOWWRTR = 150375642; LITDEF int ERR_GTMSECSHRSHMCONCPROC = 150375650; LITDEF int ERR_JNLINVALLOC = 150375656; LITDEF int ERR_JNLINVEXT = 150375664; LITDEF int ERR_MUPCLIERR = 150375674; LITDEF int ERR_JNLTMQUAL4 = 150375682; LITDEF int ERR_GTMSECSHRREMSHM = 150375691; LITDEF int ERR_GTMSECSHRREMFILE = 150375699; LITDEF int ERR_MUNODBNAME = 150375706; LITDEF int ERR_FILECREATE = 150375715; LITDEF int ERR_FILENOTCREATE = 150375723; LITDEF int ERR_JNLPROCSTUCK = 150375728; LITDEF int ERR_INVGLOBALQUAL = 150375738; LITDEF int ERR_COLLARGLONG = 150375746; LITDEF int ERR_NOPINI = 150375754; LITDEF int ERR_DBNOCRE = 150375762; LITDEF int ERR_JNLSPACELOW = 150375771; LITDEF int ERR_DBCOMMITCLNUP = 150375779; LITDEF int ERR_BFRQUALREQ = 150375786; LITDEF int ERR_REQDVIEWPARM = 150375794; LITDEF int ERR_COLLFNMISSING = 150375802; LITDEF int ERR_JNLACTINCMPLT = 150375808; LITDEF int ERR_NCTCOLLDIFF = 150375818; LITDEF int ERR_DLRCUNXEOR = 150375826; LITDEF int ERR_DLRCTOOBIG = 150375834; LITDEF int ERR_WCERRNOTCHG = 150375842; LITDEF int ERR_WCWRNNOTCHG = 150375848; LITDEF int ERR_ZCWRONGDESC = 150375858; LITDEF int ERR_MUTNWARN = 150375864; LITDEF int ERR_GTMSECSHRUPDDBHDR = 150375875; LITDEF int ERR_LCKSTIMOUT = 150375880; LITDEF int ERR_CTLMNEMAXLEN = 150375890; LITDEF int ERR_CTLMNEXPECTED = 150375898; LITDEF int ERR_USRIOINIT = 150375906; LITDEF int ERR_CRITSEMFAIL = 150375914; LITDEF int ERR_TERMWRITE = 150375922; LITDEF int ERR_COLLTYPVERSION = 150375930; LITDEF int ERR_LVNULLSUBS = 150375938; LITDEF int ERR_GVREPLERR = 150375946; LITDEF int ERR_MTIOERR = 150375954; LITDEF int ERR_RMWIDTHPOS = 150375962; LITDEF int ERR_OFFSETINV = 150375970; LITDEF int ERR_JOBPARTOOLONG = 150375978; LITDEF int ERR_JOBARGMISSING = 150375986; LITDEF int ERR_RUNPARAMERR = 150375994; LITDEF int ERR_FNNAMENEG = 150376002; LITDEF int ERR_ORDER2 = 150376010; LITDEF int ERR_MUNOUPGRD = 150376018; LITDEF int ERR_REORGCTRLY = 150376027; LITDEF int ERR_TSTRTPARM = 150376034; LITDEF int ERR_TRIGNAMENF = 150376042; LITDEF int ERR_TRIGZBREAKREM = 150376048; LITDEF int ERR_TLVLZERO = 150376058; LITDEF int ERR_TRESTNOT = 150376066; LITDEF int ERR_TPLOCK = 150376074; LITDEF int ERR_TPQUIT = 150376082; LITDEF int ERR_TPFAIL = 150376090; LITDEF int ERR_TPRETRY = 150376098; LITDEF int ERR_TPTOODEEP = 150376106; LITDEF int ERR_ZDEFACTIVE = 150376114; LITDEF int ERR_ZDEFOFLOW = 150376122; LITDEF int ERR_MUPRESTERR = 150376130; LITDEF int ERR_MUBCKNODIR = 150376138; LITDEF int ERR_TRANS2BIG = 150376146; LITDEF int ERR_INVBITLEN = 150376154; LITDEF int ERR_INVBITSTR = 150376162; LITDEF int ERR_INVBITPOS = 150376170; LITDEF int ERR_PARNORMAL = 150376177; LITDEF int ERR_PARBUFSM = 150376186; LITDEF int ERR_RMWIDTHTOOBIG = 150376194; LITDEF int ERR_PATTABNOTFND = 150376202; LITDEF int ERR_OBJFILERR = 150376210; LITDEF int ERR_SRCFILERR = 150376218; LITDEF int ERR_NEGFRACPWR = 150376226; LITDEF int ERR_MTNOSKIP = 150376234; LITDEF int ERR_CETOOMANY = 150376242; LITDEF int ERR_CEUSRERROR = 150376250; LITDEF int ERR_CEBIGSKIP = 150376258; LITDEF int ERR_CETOOLONG = 150376266; LITDEF int ERR_CENOINDIR = 150376274; LITDEF int ERR_COLLATIONUNDEF = 150376282; LITDEF int ERR_RBWRNNOTCHG = 150376288; LITDEF int ERR_GTMSECSHRSRVF = 150376298; LITDEF int ERR_FREEZECTRL = 150376307; LITDEF int ERR_JNLFLUSH = 150376315; LITDEF int ERR_CCPSIGDMP = 150376323; LITDEF int ERR_NOPRINCIO = 150376332; LITDEF int ERR_INVPORTSPEC = 150376338; LITDEF int ERR_INVADDRSPEC = 150376346; LITDEF int ERR_SOCKPARMREQ = 150376354; LITDEF int ERR_IPADDRREQ = 150376362; LITDEF int ERR_SOCKWAIT = 150376370; LITDEF int ERR_SOCKACPT = 150376378; LITDEF int ERR_SOCKINIT = 150376386; LITDEF int ERR_OPENCONN = 150376394; LITDEF int ERR_DEVNOTIMP = 150376402; LITDEF int ERR_JNLEXTR = 150376410; LITDEF int ERR_DBREMOTE = 150376418; LITDEF int ERR_JNLREQUIRED = 150376426; LITDEF int ERR_TPMIXUP = 150376434; LITDEF int ERR_HTOFLOW = 150376442; LITDEF int ERR_RMNOBIGRECORD = 150376450; LITDEF int ERR_DBBMSIZE = 150376459; LITDEF int ERR_DBBMBARE = 150376467; LITDEF int ERR_DBBMINV = 150376475; LITDEF int ERR_DBBMMSTR = 150376483; LITDEF int ERR_DBROOTBURN = 150376491; LITDEF int ERR_REPLSTATEERR = 150376498; LITDEF int ERR_VMSMEMORY = 150376508; LITDEF int ERR_DBDIRTSUBSC = 150376515; LITDEF int ERR_TIMEROVFL = 150376522; LITDEF int ERR_GTMASSERT = 150376532; LITDEF int ERR_DBFHEADERR4 = 150376539; LITDEF int ERR_DBADDRANGE = 150376547; LITDEF int ERR_DBQUELINK = 150376555; LITDEF int ERR_DBCRERR = 150376563; LITDEF int ERR_MUSTANDALONE = 150376571; LITDEF int ERR_MUNOACTION = 150376578; LITDEF int ERR_RMBIGSHARE = 150376586; LITDEF int ERR_TPRESTART = 150376595; LITDEF int ERR_SOCKWRITE = 150376602; LITDEF int ERR_DBCNTRLERR = 150376611; LITDEF int ERR_NOTERMENV = 150376619; LITDEF int ERR_NOTERMENTRY = 150376627; LITDEF int ERR_NOTERMINFODB = 150376635; LITDEF int ERR_INVACCMETHOD = 150376642; LITDEF int ERR_JNLOPNERR = 150376650; LITDEF int ERR_JNLRECTYPE = 150376658; LITDEF int ERR_JNLTRANSGTR = 150376666; LITDEF int ERR_JNLTRANSLSS = 150376674; LITDEF int ERR_JNLWRERR = 150376682; LITDEF int ERR_FILEIDMATCH = 150376690; LITDEF int ERR_EXTSRCLIN = 150376699; LITDEF int ERR_EXTSRCLOC = 150376707; LITDEF int ERR_BIGNOACL = 150376714; LITDEF int ERR_ERRCALL = 150376722; LITDEF int ERR_ZCCTENV = 150376730; LITDEF int ERR_ZCCTOPN = 150376738; LITDEF int ERR_ZCCTNULLF = 150376746; LITDEF int ERR_ZCUNAVAIL = 150376754; LITDEF int ERR_ZCENTNAME = 150376762; LITDEF int ERR_ZCCOLON = 150376770; LITDEF int ERR_ZCRTNTYP = 150376778; LITDEF int ERR_ZCRCALLNAME = 150376786; LITDEF int ERR_ZCRPARMNAME = 150376794; LITDEF int ERR_ZCUNTYPE = 150376802; LITDEF int ERR_ZCMLTSTATUS = 150376810; LITDEF int ERR_ZCSTATUSRET = 150376818; LITDEF int ERR_ZCMAXPARAM = 150376826; LITDEF int ERR_ZCCSQRBR = 150376834; LITDEF int ERR_ZCPREALLNUMEX = 150376842; LITDEF int ERR_ZCPREALLVALPAR = 150376850; LITDEF int ERR_VERMISMATCH = 150376858; LITDEF int ERR_JNLCNTRL = 150376866; LITDEF int ERR_TRIGNAMBAD = 150376874; LITDEF int ERR_BUFRDTIMEOUT = 150376882; LITDEF int ERR_INVALIDRIP = 150376890; LITDEF int ERR_BLKSIZ512 = 150376899; LITDEF int ERR_MUTEXERR = 150376906; LITDEF int ERR_JNLVSIZE = 150376914; LITDEF int ERR_MUTEXLCKALERT = 150376920; LITDEF int ERR_MUTEXFRCDTERM = 150376928; LITDEF int ERR_GTMSECSHR = 150376938; LITDEF int ERR_GTMSECSHRSRVFID = 150376944; LITDEF int ERR_GTMSECSHRSRVFIL = 150376952; LITDEF int ERR_FREEBLKSLOW = 150376960; LITDEF int ERR_PROTNOTSUP = 150376970; LITDEF int ERR_DELIMSIZNA = 150376978; LITDEF int ERR_INVCTLMNE = 150376986; LITDEF int ERR_SOCKLISTEN = 150376994; LITDEF int ERR_LQLENGTHNA = 150377002; LITDEF int ERR_ADDRTOOLONG = 150377010; LITDEF int ERR_GTMSECSHRGETSEMFAIL = 150377018; LITDEF int ERR_CPBEYALLOC = 150377026; LITDEF int ERR_DBRDONLY = 150377034; LITDEF int ERR_DUPTN = 150377040; LITDEF int ERR_TRESTLOC = 150377050; LITDEF int ERR_REPLPOOLINST = 150377058; LITDEF int ERR_ZCVECTORINDX = 150377064; LITDEF int ERR_REPLNOTON = 150377074; LITDEF int ERR_JNLMOVED = 150377082; LITDEF int ERR_EXTRFMT = 150377091; LITDEF int ERR_CALLERID = 150377099; LITDEF int ERR_KRNLKILL = 150377108; LITDEF int ERR_MEMORYRECURSIVE = 150377116; LITDEF int ERR_FREEZEID = 150377123; LITDEF int ERR_BLKWRITERR = 150377131; LITDEF int ERR_STOPTIMEOUT = 150377138; LITDEF int ERR_TRIGMODINTP = 150377146; LITDEF int ERR_BCKUPBUFLUSH = 150377154; LITDEF int ERR_NOFORKCORE = 150377160; LITDEF int ERR_JNLREAD = 150377170; LITDEF int ERR_JNLMINALIGN = 150377176; LITDEF int ERR_UNUSEDMSG781 = 150377186; LITDEF int ERR_JNLPOOLSETUP = 150377194; LITDEF int ERR_JNLSTATEOFF = 150377202; LITDEF int ERR_RECVPOOLSETUP = 150377210; LITDEF int ERR_REPLCOMM = 150377218; LITDEF int ERR_NOREPLCTDREG = 150377224; LITDEF int ERR_REPLINFO = 150377235; LITDEF int ERR_REPLWARN = 150377240; LITDEF int ERR_REPLERR = 150377250; LITDEF int ERR_JNLNMBKNOTPRCD = 150377258; LITDEF int ERR_REPLFILIOERR = 150377266; LITDEF int ERR_REPLBRKNTRANS = 150377274; LITDEF int ERR_TTWIDTHTOOBIG = 150377282; LITDEF int ERR_REPLLOGOPN = 150377290; LITDEF int ERR_REPLFILTER = 150377298; LITDEF int ERR_GBLMODFAIL = 150377306; LITDEF int ERR_TTLENGTHTOOBIG = 150377314; LITDEF int ERR_TPTIMEOUT = 150377322; LITDEF int ERR_DEFEREVENT = 150377331; LITDEF int ERR_JNLFILNOTCHG = 150377338; LITDEF int ERR_EVENTLOGERR = 150377346; LITDEF int ERR_UPDATEFILEOPEN = 150377354; LITDEF int ERR_JNLBADRECFMT = 150377362; LITDEF int ERR_NULLCOLLDIFF = 150377370; LITDEF int ERR_MUKILLIP = 150377376; LITDEF int ERR_JNLRDONLY = 150377386; LITDEF int ERR_ANCOMPTINC = 150377394; LITDEF int ERR_ABNCOMPTINC = 150377402; LITDEF int ERR_UNUSEDMSG809 = 150377410; LITDEF int ERR_SOCKNOTFND = 150377418; LITDEF int ERR_CURRSOCKOFR = 150377426; LITDEF int ERR_SOCKETEXIST = 150377434; LITDEF int ERR_LISTENPASSBND = 150377442; LITDEF int ERR_DBCLNUPINFO = 150377451; LITDEF int ERR_MUNODWNGRD = 150377458; LITDEF int ERR_REPLTRANS2BIG = 150377466; LITDEF int ERR_RDFLTOOLONG = 150377474; LITDEF int ERR_MUNOFINISH = 150377482; LITDEF int ERR_DBFILEXT = 150377491; LITDEF int ERR_JNLFSYNCERR = 150377498; LITDEF int ERR_FSYNCTIMOUT = 150377506; LITDEF int ERR_ZCPREALLVALINV = 150377514; LITDEF int ERR_NEWJNLFILECREAT = 150377523; LITDEF int ERR_DSKSPACEFLOW = 150377531; LITDEF int ERR_GVINCRFAIL = 150377538; LITDEF int ERR_ISOLATIONSTSCHN = 150377546; LITDEF int ERR_REPLGBL2LONG = 150377554; LITDEF int ERR_TRACEON = 150377562; LITDEF int ERR_TOOMANYCLIENTS = 150377570; LITDEF int ERR_NOEXCLUDE = 150377579; LITDEF int ERR_GVINCRISOLATION = 150377586; LITDEF int ERR_EXCLUDEREORG = 150377592; LITDEF int ERR_REORGINC = 150377602; LITDEF int ERR_ASC2EBCDICCONV = 150377610; LITDEF int ERR_GTMSECSHRSTART = 150377618; LITDEF int ERR_DBVERPERFWARN1 = 150377624; LITDEF int ERR_FILEIDGBLSEC = 150377634; LITDEF int ERR_GBLSECNOTGDS = 150377642; LITDEF int ERR_BADGBLSECVER = 150377650; LITDEF int ERR_RECSIZENOTEVEN = 150377658; LITDEF int ERR_BUFFLUFAILED = 150377666; LITDEF int ERR_MUQUALINCOMP = 150377674; LITDEF int ERR_DISTPATHMAX = 150377682; LITDEF int ERR_UNUSEDMSG844 = 150377690; LITDEF int ERR_IMAGENAME = 150377698; LITDEF int ERR_GTMSECSHRPERM = 150377706; LITDEF int ERR_GTMDISTUNDEF = 150377714; LITDEF int ERR_SYSCALL = 150377722; LITDEF int ERR_MAXGTMPATH = 150377730; LITDEF int ERR_TROLLBK2DEEP = 150377738; LITDEF int ERR_INVROLLBKLVL = 150377746; LITDEF int ERR_OLDBINEXTRACT = 150377752; LITDEF int ERR_ACOMPTBINC = 150377762; LITDEF int ERR_NOTREPLICATED = 150377768; LITDEF int ERR_DBPREMATEOF = 150377778; LITDEF int ERR_KILLBYSIG = 150377788; LITDEF int ERR_KILLBYSIGUINFO = 150377796; LITDEF int ERR_KILLBYSIGSINFO1 = 150377804; LITDEF int ERR_KILLBYSIGSINFO2 = 150377812; LITDEF int ERR_SIGILLOPC = 150377820; LITDEF int ERR_SIGILLOPN = 150377828; LITDEF int ERR_SIGILLADR = 150377836; LITDEF int ERR_SIGILLTRP = 150377844; LITDEF int ERR_SIGPRVOPC = 150377852; LITDEF int ERR_SIGPRVREG = 150377860; LITDEF int ERR_SIGCOPROC = 150377868; LITDEF int ERR_SIGBADSTK = 150377876; LITDEF int ERR_SIGADRALN = 150377884; LITDEF int ERR_SIGADRERR = 150377892; LITDEF int ERR_SIGOBJERR = 150377900; LITDEF int ERR_SIGINTDIV = 150377908; LITDEF int ERR_SIGINTOVF = 150377916; LITDEF int ERR_SIGFLTDIV = 150377924; LITDEF int ERR_SIGFLTOVF = 150377932; LITDEF int ERR_SIGFLTUND = 150377940; LITDEF int ERR_SIGFLTRES = 150377948; LITDEF int ERR_SIGFLTINV = 150377956; LITDEF int ERR_SIGMAPERR = 150377964; LITDEF int ERR_SIGACCERR = 150377972; LITDEF int ERR_TRNLOGFAIL = 150377978; LITDEF int ERR_INVDBGLVL = 150377986; LITDEF int ERR_DBMAXNRSUBS = 150377995; LITDEF int ERR_GTMSECSHRSCKSEL = 150378002; LITDEF int ERR_GTMSECSHRTMOUT = 150378011; LITDEF int ERR_GTMSECSHRRECVF = 150378018; LITDEF int ERR_GTMSECSHRSENDF = 150378026; LITDEF int ERR_SIZENOTVALID8 = 150378034; LITDEF int ERR_GTMSECSHROPCMP = 150378040; LITDEF int ERR_GTMSECSHRSUIDF = 150378048; LITDEF int ERR_GTMSECSHRSGIDF = 150378056; LITDEF int ERR_GTMSECSHRSSIDF = 150378064; LITDEF int ERR_GTMSECSHRFORKF = 150378074; LITDEF int ERR_DBFSYNCERR = 150378082; LITDEF int ERR_SECONDAHEAD = 150378090; LITDEF int ERR_SCNDDBNOUPD = 150378098; LITDEF int ERR_MUINFOUINT4 = 150378107; LITDEF int ERR_NLMISMATCHCALC = 150378114; LITDEF int ERR_UNUSEDMSG898 = 150378122; LITDEF int ERR_UNUSEDMSG899 = 150378131; LITDEF int ERR_DBBADNSUB = 150378138; LITDEF int ERR_DBBADKYNM = 150378146; LITDEF int ERR_DBBADPNTR = 150378154; LITDEF int ERR_DBBNPNTR = 150378162; LITDEF int ERR_DBINCLVL = 150378170; LITDEF int ERR_DBBFSTAT = 150378178; LITDEF int ERR_DBBDBALLOC = 150378186; LITDEF int ERR_DBMRKFREE = 150378194; LITDEF int ERR_DBMRKBUSY = 150378200; LITDEF int ERR_DBBSIZZRO = 150378210; LITDEF int ERR_DBSZGT64K = 150378218; LITDEF int ERR_DBNOTMLTP = 150378226; LITDEF int ERR_DBTNTOOLG = 150378235; LITDEF int ERR_DBBPLMLT512 = 150378242; LITDEF int ERR_DBBPLMGT2K = 150378250; LITDEF int ERR_MUINFOUINT8 = 150378259; LITDEF int ERR_DBBPLNOT512 = 150378266; LITDEF int ERR_MUINFOSTR = 150378275; LITDEF int ERR_DBUNDACCMT = 150378283; LITDEF int ERR_DBTNNEQ = 150378291; LITDEF int ERR_MUPGRDSUCC = 150378297; LITDEF int ERR_DBDSRDFMTCHNG = 150378307; LITDEF int ERR_DBFGTBC = 150378312; LITDEF int ERR_DBFSTBC = 150378322; LITDEF int ERR_DBFSTHEAD = 150378330; LITDEF int ERR_DBCREINCOMP = 150378338; LITDEF int ERR_DBFLCORRP = 150378346; LITDEF int ERR_DBHEADINV = 150378354; LITDEF int ERR_DBINCRVER = 150378362; LITDEF int ERR_DBINVGBL = 150378370; LITDEF int ERR_DBKEYGTIND = 150378378; LITDEF int ERR_DBGTDBMAX = 150378386; LITDEF int ERR_DBKGTALLW = 150378394; LITDEF int ERR_DBLTSIBL = 150378402; LITDEF int ERR_DBLRCINVSZ = 150378410; LITDEF int ERR_MUREUPDWNGRDEND = 150378419; LITDEF int ERR_DBLOCMBINC = 150378424; LITDEF int ERR_DBLVLINC = 150378432; LITDEF int ERR_DBMBSIZMX = 150378440; LITDEF int ERR_DBMBSIZMN = 150378450; LITDEF int ERR_DBMBTNSIZMX = 150378459; LITDEF int ERR_DBMBMINCFRE = 150378464; LITDEF int ERR_DBMBPINCFL = 150378472; LITDEF int ERR_DBMBPFLDLBM = 150378480; LITDEF int ERR_DBMBPFLINT = 150378488; LITDEF int ERR_DBMBPFLDIS = 150378496; LITDEF int ERR_DBMBPFRDLBM = 150378504; LITDEF int ERR_DBMBPFRINT = 150378512; LITDEF int ERR_DBMAXKEYEXC = 150378522; LITDEF int ERR_DBMXRSEXCMIN = 150378530; LITDEF int ERR_UNUSEDMSG950 = 150378538; LITDEF int ERR_DBREADBM = 150378546; LITDEF int ERR_DBCOMPTOOLRG = 150378554; LITDEF int ERR_DBVERPERFWARN2 = 150378560; LITDEF int ERR_DBRBNTOOLRG = 150378570; LITDEF int ERR_DBRBNLBMN = 150378578; LITDEF int ERR_DBRBNNEG = 150378586; LITDEF int ERR_DBRLEVTOOHI = 150378594; LITDEF int ERR_DBRLEVLTONE = 150378602; LITDEF int ERR_DBSVBNMIN = 150378610; LITDEF int ERR_DBTTLBLK0 = 150378618; LITDEF int ERR_DBNOTDB = 150378626; LITDEF int ERR_DBTOTBLK = 150378634; LITDEF int ERR_DBTN = 150378643; LITDEF int ERR_DBNOREGION = 150378650; LITDEF int ERR_DBTNRESETINC = 150378656; LITDEF int ERR_DBTNLTCTN = 150378666; LITDEF int ERR_DBTNRESET = 150378674; LITDEF int ERR_MUTEXRSRCCLNUP = 150378683; LITDEF int ERR_SEMWT2LONG = 150378690; LITDEF int ERR_REPLINSTOPEN = 150378698; LITDEF int ERR_REPLINSTCLOSE = 150378706; LITDEF int ERR_UNUSEDMSG972 = 150378714; LITDEF int ERR_DBCRERR8 = 150378723; LITDEF int ERR_NUMPROCESSORS = 150378728; LITDEF int ERR_DBADDRANGE8 = 150378739; LITDEF int ERR_RNDWNSEMFAIL = 150378747; LITDEF int ERR_GTMSECSHRSHUTDN = 150378755; LITDEF int ERR_NOSPACECRE = 150378762; LITDEF int ERR_LOWSPACECRE = 150378768; LITDEF int ERR_WAITDSKSPACE = 150378779; LITDEF int ERR_OUTOFSPACE = 150378788; LITDEF int ERR_JNLPVTINFO = 150378795; LITDEF int ERR_NOSPACEEXT = 150378802; LITDEF int ERR_WCBLOCKED = 150378808; LITDEF int ERR_REPLJNLCLOSED = 150378818; LITDEF int ERR_RENAMEFAIL = 150378824; LITDEF int ERR_FILERENAME = 150378835; LITDEF int ERR_JNLBUFINFO = 150378843; LITDEF int ERR_UNUSEDMSG989 = 150378850; LITDEF int ERR_UNUSEDMSG990 = 150378858; LITDEF int ERR_TPNOTACID = 150378867; LITDEF int ERR_JNLSETDATA2LONG = 150378874; LITDEF int ERR_JNLNEWREC = 150378882; LITDEF int ERR_REPLFTOKSEM = 150378890; LITDEF int ERR_UNUSEDMSG995 = 150378898; LITDEF int ERR_EXTRIOERR = 150378906; LITDEF int ERR_EXTRCLOSEERR = 150378914; LITDEF int ERR_UNUSEDMSG998 = 150378922; LITDEF int ERR_REPLEXITERR = 150378930; LITDEF int ERR_MUDESTROYSUC = 150378939; LITDEF int ERR_DBRNDWN = 150378946; LITDEF int ERR_MUDESTROYFAIL = 150378955; LITDEF int ERR_NOTALLDBOPN = 150378964; LITDEF int ERR_MUSELFBKUP = 150378970; LITDEF int ERR_DBDANGER = 150378976; LITDEF int ERR_TRUNCATEFAIL = 150378986; LITDEF int ERR_TCGETATTR = 150378994; LITDEF int ERR_TCSETATTR = 150379002; LITDEF int ERR_IOWRITERR = 150379010; LITDEF int ERR_REPLINSTWRITE = 150379018; LITDEF int ERR_DBBADFREEBLKCTR = 150379024; LITDEF int ERR_REQ2RESUME = 150379035; LITDEF int ERR_TIMERHANDLER = 150379040; LITDEF int ERR_FREEMEMORY = 150379050; LITDEF int ERR_MUREPLSECDEL = 150379059; LITDEF int ERR_MUREPLSECNOTDEL = 150379067; LITDEF int ERR_MUJPOOLRNDWNSUC = 150379075; LITDEF int ERR_MURPOOLRNDWNSUC = 150379083; LITDEF int ERR_MUJPOOLRNDWNFL = 150379090; LITDEF int ERR_MURPOOLRNDWNFL = 150379098; LITDEF int ERR_MUREPLPOOL = 150379107; LITDEF int ERR_REPLACCSEM = 150379114; LITDEF int ERR_JNLFLUSHNOPROG = 150379120; LITDEF int ERR_REPLINSTCREATE = 150379130; LITDEF int ERR_SUSPENDING = 150379139; LITDEF int ERR_SOCKBFNOTEMPTY = 150379146; LITDEF int ERR_ILLESOCKBFSIZE = 150379154; LITDEF int ERR_NOSOCKETINDEV = 150379162; LITDEF int ERR_SETSOCKOPTERR = 150379170; LITDEF int ERR_GETSOCKOPTERR = 150379178; LITDEF int ERR_NOSUCHPROC = 150379187; LITDEF int ERR_DSENOFINISH = 150379194; LITDEF int ERR_LKENOFINISH = 150379202; LITDEF int ERR_NOCHLEFT = 150379212; LITDEF int ERR_MULOGNAMEDEF = 150379218; LITDEF int ERR_BUFOWNERSTUCK = 150379226; LITDEF int ERR_ACTIVATEFAIL = 150379234; LITDEF int ERR_DBRNDWNWRN = 150379240; LITDEF int ERR_DLLNOOPEN = 150379250; LITDEF int ERR_DLLNORTN = 150379258; LITDEF int ERR_DLLNOCLOSE = 150379266; LITDEF int ERR_FILTERNOTALIVE = 150379274; LITDEF int ERR_FILTERCOMM = 150379282; LITDEF int ERR_FILTERBADCONV = 150379290; LITDEF int ERR_PRIMARYISROOT = 150379298; LITDEF int ERR_GVQUERYGETFAIL = 150379306; LITDEF int ERR_DBCREC2BIGINBLK = 150379314; LITDEF int ERR_MERGEDESC = 150379322; LITDEF int ERR_MERGEINCOMPL = 150379328; LITDEF int ERR_DBNAMEMISMATCH = 150379338; LITDEF int ERR_DBIDMISMATCH = 150379346; LITDEF int ERR_DEVOPENFAIL = 150379354; LITDEF int ERR_IPCNOTDEL = 150379363; LITDEF int ERR_XCVOIDRET = 150379370; LITDEF int ERR_MURAIMGFAIL = 150379378; LITDEF int ERR_REPLINSTUNDEF = 150379386; LITDEF int ERR_REPLINSTACC = 150379394; LITDEF int ERR_NOJNLPOOL = 150379402; LITDEF int ERR_NORECVPOOL = 150379410; LITDEF int ERR_FTOKERR = 150379418; LITDEF int ERR_REPLREQRUNDOWN = 150379426; LITDEF int ERR_BLKCNTEDITFAIL = 150379435; LITDEF int ERR_SEMREMOVED = 150379443; LITDEF int ERR_REPLINSTFMT = 150379450; LITDEF int ERR_SEMKEYINUSE = 150379458; LITDEF int ERR_XTRNTRANSERR = 150379466; LITDEF int ERR_XTRNTRANSDLL = 150379474; LITDEF int ERR_XTRNRETVAL = 150379482; LITDEF int ERR_XTRNRETSTR = 150379490; LITDEF int ERR_INVECODEVAL = 150379498; LITDEF int ERR_SETECODE = 150379506; LITDEF int ERR_INVSTACODE = 150379514; LITDEF int ERR_REPEATERROR = 150379522; LITDEF int ERR_NOCANONICNAME = 150379530; LITDEF int ERR_NOSUBSCRIPT = 150379538; LITDEF int ERR_SYSTEMVALUE = 150379546; LITDEF int ERR_SIZENOTVALID4 = 150379554; LITDEF int ERR_STRNOTVALID = 150379562; LITDEF int ERR_UNUSEDMSG1079 = 150379570; LITDEF int ERR_ERRWETRAP = 150379578; LITDEF int ERR_TRACINGON = 150379587; LITDEF int ERR_CITABENV = 150379594; LITDEF int ERR_CITABOPN = 150379602; LITDEF int ERR_CIENTNAME = 150379610; LITDEF int ERR_CIRTNTYP = 150379618; LITDEF int ERR_CIRCALLNAME = 150379626; LITDEF int ERR_CIRPARMNAME = 150379634; LITDEF int ERR_CIDIRECTIVE = 150379642; LITDEF int ERR_CIPARTYPE = 150379650; LITDEF int ERR_CIUNTYPE = 150379658; LITDEF int ERR_CINOENTRY = 150379666; LITDEF int ERR_JNLINVSWITCHLMT = 150379674; LITDEF int ERR_SETZDIR = 150379682; LITDEF int ERR_JOBACTREF = 150379690; LITDEF int ERR_ECLOSTMID = 150379696; LITDEF int ERR_ZFF2MANY = 150379706; LITDEF int ERR_JNLFSYNCLSTCK = 150379712; LITDEF int ERR_DELIMWIDTH = 150379722; LITDEF int ERR_DBBMLCORRUPT = 150379730; LITDEF int ERR_DLCKAVOIDANCE = 150379738; LITDEF int ERR_WRITERSTUCK = 150379746; LITDEF int ERR_PATNOTFOUND = 150379754; LITDEF int ERR_INVZDIRFORM = 150379762; LITDEF int ERR_ZDIROUTOFSYNC = 150379768; LITDEF int ERR_GBLNOEXIST = 150379779; LITDEF int ERR_MAXBTLEVEL = 150379786; LITDEF int ERR_UNUSEDMSG1107 = 150379794; LITDEF int ERR_JNLALIGNSZCHG = 150379803; LITDEF int ERR_UNUSEDMSG1109 = 150379810; LITDEF int ERR_GVFAILCORE = 150379818; LITDEF int ERR_DBCDBNOCERTIFY = 150379826; LITDEF int ERR_DBFRZRESETSUC = 150379835; LITDEF int ERR_JNLFILEXTERR = 150379842; LITDEF int ERR_JOBEXAMDONE = 150379851; LITDEF int ERR_JOBEXAMFAIL = 150379858; LITDEF int ERR_JOBINTRRQST = 150379866; LITDEF int ERR_ERRWZINTR = 150379874; LITDEF int ERR_CLIERR = 150379882; LITDEF int ERR_REPLNOBEFORE = 150379888; LITDEF int ERR_REPLJNLCNFLCT = 150379896; LITDEF int ERR_JNLDISABLE = 150379904; LITDEF int ERR_FILEEXISTS = 150379914; LITDEF int ERR_JNLSTATE = 150379923; LITDEF int ERR_REPLSTATE = 150379931; LITDEF int ERR_JNLCREATE = 150379939; LITDEF int ERR_JNLNOCREATE = 150379946; LITDEF int ERR_JNLFNF = 150379955; LITDEF int ERR_PREVJNLLINKCUT = 150379963; LITDEF int ERR_PREVJNLLINKSET = 150379971; LITDEF int ERR_FILENAMETOOLONG = 150379978; LITDEF int ERR_REQRECOV = 150379986; LITDEF int ERR_JNLTRANS2BIG = 150379994; LITDEF int ERR_JNLSWITCHTOOSM = 150380002; LITDEF int ERR_JNLSWITCHSZCHG = 150380011; LITDEF int ERR_NOTRNDMACC = 150380018; LITDEF int ERR_TMPFILENOCRE = 150380026; LITDEF int ERR_SHRMEMEXHAUSTED = 150380034; LITDEF int ERR_JNLSENDOPER = 150380043; LITDEF int ERR_DDPSUBSNUL = 150380050; LITDEF int ERR_DDPNOCONNECT = 150380058; LITDEF int ERR_DDPCONGEST = 150380066; LITDEF int ERR_DDPSHUTDOWN = 150380074; LITDEF int ERR_DDPTOOMANYPROCS = 150380082; LITDEF int ERR_DDPBADRESPONSE = 150380090; LITDEF int ERR_DDPINVCKT = 150380098; LITDEF int ERR_DDPVOLSETCONFIG = 150380106; LITDEF int ERR_DDPCONFGOOD = 150380113; LITDEF int ERR_DDPCONFIGNORE = 150380121; LITDEF int ERR_DDPCONFINCOMPL = 150380128; LITDEF int ERR_DDPCONFBADVOL = 150380138; LITDEF int ERR_DDPCONFBADUCI = 150380146; LITDEF int ERR_DDPCONFBADGLD = 150380154; LITDEF int ERR_DDPRECSIZNOTNUM = 150380162; LITDEF int ERR_DDPOUTMSG2BIG = 150380170; LITDEF int ERR_DDPNOSERVER = 150380178; LITDEF int ERR_MUTEXRELEASED = 150380186; LITDEF int ERR_JNLCRESTATUS = 150380192; LITDEF int ERR_ZBREAKFAIL = 150380203; LITDEF int ERR_DLLVERSION = 150380210; LITDEF int ERR_INVZROENT = 150380218; LITDEF int ERR_DDPLOGERR = 150380226; LITDEF int ERR_GETSOCKNAMERR = 150380234; LITDEF int ERR_INVGTMEXIT = 150380242; LITDEF int ERR_CIMAXPARAM = 150380250; LITDEF int ERR_CITPNESTED = 150380258; LITDEF int ERR_CIMAXLEVELS = 150380266; LITDEF int ERR_JOBINTRRETHROW = 150380274; LITDEF int ERR_STARFILE = 150380282; LITDEF int ERR_NOSTARFILE = 150380290; LITDEF int ERR_MUJNLSTAT = 150380299; LITDEF int ERR_JNLTPNEST = 150380304; LITDEF int ERR_REPLOFFJNLON = 150380314; LITDEF int ERR_FILEDELFAIL = 150380320; LITDEF int ERR_INVQUALTIME = 150380330; LITDEF int ERR_NOTPOSITIVE = 150380338; LITDEF int ERR_INVREDIRQUAL = 150380346; LITDEF int ERR_INVERRORLIM = 150380354; LITDEF int ERR_INVIDQUAL = 150380362; LITDEF int ERR_INVTRNSQUAL = 150380370; LITDEF int ERR_JNLNOBIJBACK = 150380378; LITDEF int ERR_SETREG2RESYNC = 150380387; LITDEF int ERR_JNLALIGNTOOSM = 150380392; LITDEF int ERR_JNLFILEOPNERR = 150380402; LITDEF int ERR_JNLFILECLOSERR = 150380410; LITDEF int ERR_REPLSTATEOFF = 150380418; LITDEF int ERR_MUJNLPREVGEN = 150380427; LITDEF int ERR_MUPJNLINTERRUPT = 150380434; LITDEF int ERR_ROLLBKINTERRUPT = 150380442; LITDEF int ERR_RLBKJNSEQ = 150380451; LITDEF int ERR_REPLRECFMT = 150380460; LITDEF int ERR_PRIMARYNOTROOT = 150380466; LITDEF int ERR_DBFRZRESETFL = 150380474; LITDEF int ERR_JNLCYCLE = 150380482; LITDEF int ERR_JNLPREVRECOV = 150380490; LITDEF int ERR_RESOLVESEQNO = 150380499; LITDEF int ERR_BOVTNGTEOVTN = 150380506; LITDEF int ERR_BOVTMGTEOVTM = 150380514; LITDEF int ERR_BEGSEQGTENDSEQ = 150380522; LITDEF int ERR_DBADDRALIGN = 150380531; LITDEF int ERR_DBWCVERIFYSTART = 150380539; LITDEF int ERR_DBWCVERIFYEND = 150380547; LITDEF int ERR_MUPIPSIG = 150380555; LITDEF int ERR_HTSHRINKFAIL = 150380560; LITDEF int ERR_STPEXPFAIL = 150380570; LITDEF int ERR_DBBTUWRNG = 150380576; LITDEF int ERR_DBBTUFIXED = 150380587; LITDEF int ERR_DBMAXREC2BIG = 150380594; LITDEF int ERR_DBCSCNNOTCMPLT = 150380602; LITDEF int ERR_DBCBADFILE = 150380610; LITDEF int ERR_DBCNOEXTND = 150380618; LITDEF int ERR_DBCINTEGERR = 150380626; LITDEF int ERR_DBMINRESBYTES = 150380634; LITDEF int ERR_DBCNOTSAMEDB = 150380642; LITDEF int ERR_DBCDBCERTIFIED = 150380651; LITDEF int ERR_DBCMODBLK2BIG = 150380658; LITDEF int ERR_DBCREC2BIG = 150380666; LITDEF int ERR_DBCCMDFAIL = 150380674; LITDEF int ERR_DBCKILLIP = 150380682; LITDEF int ERR_DBCNOFINISH = 150380690; LITDEF int ERR_DYNUPGRDFAIL = 150380698; LITDEF int ERR_MMNODYNDWNGRD = 150380706; LITDEF int ERR_MMNODYNUPGRD = 150380714; LITDEF int ERR_MUDWNGRDNRDY = 150380722; LITDEF int ERR_MUDWNGRDTN = 150380730; LITDEF int ERR_MUDWNGRDNOTPOS = 150380738; LITDEF int ERR_MUUPGRDNRDY = 150380746; LITDEF int ERR_TNWARN = 150380752; LITDEF int ERR_TNTOOLARGE = 150380762; LITDEF int ERR_SHMPLRECOV = 150380771; LITDEF int ERR_MUNOSTRMBKUP = 150380776; LITDEF int ERR_EPOCHTNHI = 150380786; LITDEF int ERR_CHNGTPRSLVTM = 150380795; LITDEF int ERR_JNLUNXPCTERR = 150380802; LITDEF int ERR_OMISERVHANG = 150380811; LITDEF int ERR_RSVDBYTE2HIGH = 150380818; LITDEF int ERR_BKUPTMPFILOPEN = 150380826; LITDEF int ERR_BKUPTMPFILWRITE = 150380834; LITDEF int ERR_VMSMEMORY2 = 150380842; LITDEF int ERR_LOADBGSZ2 = 150380850; LITDEF int ERR_LOADEDSZ2 = 150380858; LITDEF int ERR_REPLINSTMISMTCH = 150380866; LITDEF int ERR_REPLINSTREAD = 150380874; LITDEF int ERR_REPLINSTDBMATCH = 150380882; LITDEF int ERR_REPLINSTNMSAME = 150380890; LITDEF int ERR_REPLINSTNMUNDEF = 150380898; LITDEF int ERR_REPLINSTNMLEN = 150380906; LITDEF int ERR_REPLINSTNOHIST = 150380914; LITDEF int ERR_REPLINSTSECLEN = 150380922; LITDEF int ERR_REPLINSTSECMTCH = 150380930; LITDEF int ERR_REPLINSTSECNONE = 150380938; LITDEF int ERR_REPLINSTSECUNDF = 150380946; LITDEF int ERR_REPLINSTSEQORD = 150380954; LITDEF int ERR_REPLINSTSTNDALN = 150380962; LITDEF int ERR_REPLREQROLLBACK = 150380970; LITDEF int ERR_REQROLLBACK = 150380978; LITDEF int ERR_UNUSEDMSG1256 = 150380986; LITDEF int ERR_SRCSRVEXISTS = 150380994; LITDEF int ERR_SRCSRVNOTEXIST = 150381002; LITDEF int ERR_SRCSRVTOOMANY = 150381010; LITDEF int ERR_JNLPOOLBADSLOT = 150381016; LITDEF int ERR_NOENDIANCVT = 150381026; LITDEF int ERR_ENDIANCVT = 150381035; LITDEF int ERR_DBENDIAN = 150381042; LITDEF int ERR_BADCHSET = 150381050; LITDEF int ERR_BADCASECODE = 150381058; LITDEF int ERR_BADCHAR = 150381066; LITDEF int ERR_DLRCILLEGAL = 150381074; LITDEF int ERR_NONUTF8LOCALE = 150381082; LITDEF int ERR_INVDLRCVAL = 150381090; LITDEF int ERR_DBMISALIGN = 150381098; LITDEF int ERR_LOADINVCHSET = 150381106; LITDEF int ERR_DLLCHSETM = 150381114; LITDEF int ERR_DLLCHSETUTF8 = 150381122; LITDEF int ERR_BOMMISMATCH = 150381130; LITDEF int ERR_WIDTHTOOSMALL = 150381138; LITDEF int ERR_SOCKMAX = 150381146; LITDEF int ERR_PADCHARINVALID = 150381154; LITDEF int ERR_ZCNOPREALLOUTPAR = 150381162; LITDEF int ERR_SVNEXPECTED = 150381170; LITDEF int ERR_SVNONEW = 150381178; LITDEF int ERR_ZINTDIRECT = 150381186; LITDEF int ERR_ZINTRECURSEIO = 150381194; LITDEF int ERR_MRTMAXEXCEEDED = 150381202; LITDEF int ERR_JNLCLOSED = 150381210; LITDEF int ERR_RLBKNOBIMG = 150381218; LITDEF int ERR_RLBKJNLNOBIMG = 150381227; LITDEF int ERR_RLBKLOSTTNONLY = 150381235; LITDEF int ERR_KILLBYSIGSINFO3 = 150381244; LITDEF int ERR_GTMSECSHRTMPPATH = 150381251; LITDEF int ERR_GTMERREXIT = 150381258; LITDEF int ERR_INVMEMRESRV = 150381264; LITDEF int ERR_OPCOMMISSED = 150381275; LITDEF int ERR_COMMITWAITSTUCK = 150381282; LITDEF int ERR_COMMITWAITPID = 150381290; LITDEF int ERR_UPDREPLSTATEOFF = 150381298; LITDEF int ERR_LITNONGRAPH = 150381304; LITDEF int ERR_DBFHEADERR8 = 150381315; LITDEF int ERR_MMBEFOREJNL = 150381320; LITDEF int ERR_MMNOBFORRPL = 150381328; LITDEF int ERR_KILLABANDONED = 150381336; LITDEF int ERR_BACKUPKILLIP = 150381344; LITDEF int ERR_LOGTOOLONG = 150381354; LITDEF int ERR_NOALIASLIST = 150381362; LITDEF int ERR_ALIASEXPECTED = 150381370; LITDEF int ERR_VIEWLVN = 150381378; LITDEF int ERR_DZWRNOPAREN = 150381386; LITDEF int ERR_DZWRNOALIAS = 150381394; LITDEF int ERR_FREEZEERR = 150381402; LITDEF int ERR_CLOSEFAIL = 150381410; LITDEF int ERR_CRYPTINIT = 150381418; LITDEF int ERR_CRYPTOPFAILED = 150381426; LITDEF int ERR_CRYPTDLNOOPEN = 150381434; LITDEF int ERR_CRYPTNOV4 = 150381442; LITDEF int ERR_CRYPTNOMM = 150381450; LITDEF int ERR_CRYPTJNLWRONGHASH = 150381458; LITDEF int ERR_CRYPTKEYFETCHFAILED = 150381466; LITDEF int ERR_CRYPTKEYFETCHFAILEDNF = 150381474; LITDEF int ERR_CRYPTHASHGENFAILED = 150381482; LITDEF int ERR_CRYPTNOPSWDINTP = 150381490; LITDEF int ERR_BADTAG = 150381498; LITDEF int ERR_ICUVERLT36 = 150381506; LITDEF int ERR_ICUSYMNOTFOUND = 150381514; LITDEF int ERR_STUCKACT = 150381523; LITDEF int ERR_CALLINAFTERXIT = 150381530; LITDEF int ERR_LOCKSPACEFULL = 150381538; LITDEF int ERR_IOERROR = 150381546; LITDEF int ERR_MAXSSREACHED = 150381554; LITDEF int ERR_SNAPSHOTNOV4 = 150381562; LITDEF int ERR_SSV4NOALLOW = 150381570; LITDEF int ERR_SSTMPDIRSTAT = 150381578; LITDEF int ERR_SSTMPCREATE = 150381586; LITDEF int ERR_JNLFILEDUP = 150381594; LITDEF int ERR_SSPREMATEOF = 150381602; LITDEF int ERR_SSFILOPERR = 150381610; LITDEF int ERR_REGSSFAIL = 150381618; LITDEF int ERR_SSSHMCLNUPFAIL = 150381626; LITDEF int ERR_SSFILCLNUPFAIL = 150381634; LITDEF int ERR_SETINTRIGONLY = 150381642; LITDEF int ERR_MAXTRIGNEST = 150381650; LITDEF int ERR_TRIGCOMPFAIL = 150381658; LITDEF int ERR_NOZTRAPINTRIG = 150381666; LITDEF int ERR_ZTWORMHOLE2BIG = 150381674; LITDEF int ERR_JNLENDIANLITTLE = 150381682; LITDEF int ERR_JNLENDIANBIG = 150381690; LITDEF int ERR_TRIGINVCHSET = 150381698; LITDEF int ERR_TRIGREPLSTATE = 150381706; LITDEF int ERR_GVDATAGETFAIL = 150381714; LITDEF int ERR_TRIG2NOTRIG = 150381720; LITDEF int ERR_ZGOTOINVLVL = 150381730; LITDEF int ERR_TRIGTCOMMIT = 150381738; LITDEF int ERR_TRIGTLVLCHNG = 150381746; LITDEF int ERR_TRIGNAMEUNIQ = 150381754; LITDEF int ERR_ZTRIGINVACT = 150381762; LITDEF int ERR_INDRCOMPFAIL = 150381770; LITDEF int ERR_QUITALSINV = 150381778; LITDEF int ERR_PROCTERM = 150381784; LITDEF int ERR_SRCLNNTDSP = 150381795; LITDEF int ERR_ARROWNTDSP = 150381803; LITDEF int ERR_TRIGDEFBAD = 150381810; LITDEF int ERR_TRIGSUBSCRANGE = 150381818; LITDEF int ERR_TRIGDATAIGNORE = 150381827; LITDEF int ERR_TRIGIS = 150381835; LITDEF int ERR_TCOMMITDISALLOW = 150381842; LITDEF int ERR_SSATTACHSHM = 150381850; LITDEF int ERR_TRIGDEFNOSYNC = 150381856; LITDEF int ERR_TRESTMAX = 150381866; LITDEF int ERR_UNUSEDMSG1367 = 150381874; LITDEF int ERR_GBLEXPECTED = 150381882; LITDEF int ERR_GVZTRIGFAIL = 150381890; LITDEF int ERR_MUUSERLBK = 150381898; LITDEF int ERR_SETINSETTRIGONLY = 150381906; LITDEF int ERR_DZTRIGINTRIG = 150381914; LITDEF int ERR_SECNODZTRIGINTP = 150381922; LITDEF int ERR_BOOLSIDEFFECT = 150381928; LITDEF int ERR_DBBADUPGRDSTATE = 150381936; LITDEF int ERR_WRITEWAITPID = 150381946; LITDEF int ERR_ZGOCALLOUTIN = 150381954; LITDEF int ERR_REPLNOXENDIAN = 150381962; LITDEF int ERR_REPLXENDIANFAIL = 150381970; LITDEF int ERR_ZGOTOINVLVL2 = 150381978; LITDEF int ERR_GTMSECSHRCHDIRF = 150381986; LITDEF int ERR_JNLORDBFLU = 150381994; LITDEF int ERR_ZCCLNUPRTNMISNG = 150382002; LITDEF int ERR_ZCINVALIDKEYWORD = 150382010; LITDEF int ERR_REPLNOMULTILINETRG = 150382018; LITDEF int ERR_DBSHMNAMEDIFF = 150382026; LITDEF int ERR_SHMREMOVED = 150382035; LITDEF int ERR_DEVICEWRITEONLY = 150382042; LITDEF int ERR_ICUERROR = 150382050; LITDEF int ERR_ZDATEBADDATE = 150382058; LITDEF int ERR_ZDATEBADTIME = 150382066; LITDEF int ERR_COREINPROGRESS = 150382074; LITDEF int ERR_MAXSEMGETRETRY = 150382082; LITDEF int ERR_JNLNOREPL = 150382090; LITDEF int ERR_JNLRECINCMPL = 150382098; LITDEF int ERR_JNLALLOCGROW = 150382107; LITDEF int ERR_INVTRCGRP = 150382114; LITDEF int ERR_MUINFOUINT6 = 150382123; LITDEF int ERR_NOLOCKMATCH = 150382131; LITDEF int ERR_BADREGION = 150382138; LITDEF int ERR_LOCKSPACEUSE = 150382147; LITDEF int ERR_JIUNHNDINT = 150382154; LITDEF int ERR_GTMASSERT2 = 150382164; LITDEF int ERR_ZTRIGNOTRW = 150382170; LITDEF int ERR_TRIGMODREGNOTRW = 150382178; LITDEF int ERR_INSNOTJOINED = 150382186; LITDEF int ERR_INSROLECHANGE = 150382194; LITDEF int ERR_INSUNKNOWN = 150382202; LITDEF int ERR_NORESYNCSUPPLONLY = 150382210; LITDEF int ERR_NORESYNCUPDATERONLY = 150382218; LITDEF int ERR_NOSUPPLSUPPL = 150382226; LITDEF int ERR_REPL2OLD = 150382234; LITDEF int ERR_EXTRFILEXISTS = 150382242; LITDEF int ERR_MUUSERECOV = 150382250; LITDEF int ERR_SECNOTSUPPLEMENTARY = 150382258; LITDEF int ERR_SUPRCVRNEEDSSUPSRC = 150382266; LITDEF int ERR_UNUSEDMSG1417 = 150382275; LITDEF int ERR_UNUSEDMSG1418 = 150382283; LITDEF int ERR_UPDSYNC2MTINS = 150382290; LITDEF int ERR_UPDSYNCINSTFILE = 150382298; LITDEF int ERR_REUSEINSTNAME = 150382306; LITDEF int ERR_RCVRMANYSTRMS = 150382314; LITDEF int ERR_RSYNCSTRMVAL = 150382322; LITDEF int ERR_RLBKSTRMSEQ = 150382331; LITDEF int ERR_RESOLVESEQSTRM = 150382339; LITDEF int ERR_REPLINSTDBSTRM = 150382346; LITDEF int ERR_RESUMESTRMNUM = 150382354; LITDEF int ERR_ORLBKSTART = 150382363; LITDEF int ERR_ORLBKTERMNTD = 150382370; LITDEF int ERR_ORLBKCMPLT = 150382379; LITDEF int ERR_ORLBKNOSTP = 150382387; LITDEF int ERR_ORLBKFRZPROG = 150382395; LITDEF int ERR_ORLBKFRZOVER = 150382403; LITDEF int ERR_ORLBKNOV4BLK = 150382410; LITDEF int ERR_DBROLLEDBACK = 150382418; LITDEF int ERR_DSEWCREINIT = 150382427; LITDEF int ERR_MURNDWNOVRD = 150382435; LITDEF int ERR_REPLONLNRLBK = 150382442; LITDEF int ERR_SRVLCKWT2LNG = 150382450; LITDEF int ERR_IGNBMPMRKFREE = 150382459; LITDEF int ERR_PERMGENFAIL = 150382466; LITDEF int ERR_PERMGENDIAG = 150382475; LITDEF int ERR_MUTRUNC1ATIME = 150382483; LITDEF int ERR_MUTRUNCBACKINPROG = 150382491; LITDEF int ERR_MUTRUNCERROR = 150382498; LITDEF int ERR_MUTRUNCFAIL = 150382506; LITDEF int ERR_MUTRUNCNOSPACE = 150382515; LITDEF int ERR_MUTRUNCNOTBG = 150382522; LITDEF int ERR_MUTRUNCNOV4 = 150382530; LITDEF int ERR_MUTRUNCPERCENT = 150382538; LITDEF int ERR_MUTRUNCSSINPROG = 150382547; LITDEF int ERR_MUTRUNCSUCCESS = 150382555; LITDEF int ERR_RSYNCSTRMSUPPLONLY = 150382562; LITDEF int ERR_STRMNUMIS = 150382571; LITDEF int ERR_STRMNUMMISMTCH1 = 150382578; LITDEF int ERR_STRMNUMMISMTCH2 = 150382586; LITDEF int ERR_STRMSEQMISMTCH = 150382594; LITDEF int ERR_LOCKSPACEINFO = 150382603; LITDEF int ERR_JRTNULLFAIL = 150382610; LITDEF int ERR_LOCKSUB2LONG = 150382618; LITDEF int ERR_RESRCWAIT = 150382627; LITDEF int ERR_RESRCINTRLCKBYPAS = 150382635; LITDEF int ERR_DBFHEADERRANY = 150382643; LITDEF int ERR_REPLINSTFROZEN = 150382650; LITDEF int ERR_REPLINSTFREEZECOMMENT = 150382659; LITDEF int ERR_REPLINSTUNFROZEN = 150382667; LITDEF int ERR_DSKNOSPCAVAIL = 150382675; LITDEF int ERR_DSKNOSPCBLOCKED = 150382682; LITDEF int ERR_DSKSPCAVAILABLE = 150382691; LITDEF int ERR_ENOSPCQIODEFER = 150382699; LITDEF int ERR_CUSTOMFILOPERR = 150382706; LITDEF int ERR_CUSTERRNOTFND = 150382714; LITDEF int ERR_CUSTERRSYNTAX = 150382722; LITDEF int ERR_ORLBKINPROG = 150382731; LITDEF int ERR_DBSPANGLOINCMP = 150382738; LITDEF int ERR_DBSPANCHUNKORD = 150382746; LITDEF int ERR_DBDATAMX = 150382754; LITDEF int ERR_DBIOERR = 150382762; LITDEF int ERR_INITORRESUME = 150382770; LITDEF int ERR_GTMSECSHRNOARG0 = 150382778; LITDEF int ERR_GTMSECSHRISNOT = 150382786; LITDEF int ERR_GTMSECSHRBADDIR = 150382794; LITDEF int ERR_JNLBUFFREGUPD = 150382800; LITDEF int ERR_JNLBUFFDBUPD = 150382808; LITDEF int ERR_LOCKINCR2HIGH = 150382818; LITDEF int ERR_LOCKIS = 150382827; LITDEF int ERR_LDSPANGLOINCMP = 150382834; LITDEF int ERR_MUFILRNDWNFL2 = 150382842; LITDEF int ERR_MUINSTFROZEN = 150382851; LITDEF int ERR_MUINSTUNFROZEN = 150382859; LITDEF int ERR_GTMEISDIR = 150382866; LITDEF int ERR_SPCLZMSG = 150382874; LITDEF int ERR_MUNOTALLINTEG = 150382880; LITDEF int ERR_BKUPRUNNING = 150382890; LITDEF int ERR_MUSIZEINVARG = 150382898; LITDEF int ERR_MUSIZEFAIL = 150382906; LITDEF int ERR_SIDEEFFECTEVAL = 150382912; LITDEF int ERR_CRYPTINIT2 = 150382922; LITDEF int ERR_CRYPTDLNOOPEN2 = 150382930; LITDEF int ERR_CRYPTBADCONFIG = 150382938; LITDEF int ERR_DBCOLLREQ = 150382944; LITDEF int ERR_SETEXTRENV = 150382954; LITDEF int ERR_NOTALLDBRNDWN = 150382962; LITDEF int ERR_TPRESTNESTERR = 150382970; LITDEF int ERR_JNLFILRDOPN = 150382978; LITDEF int ERR_SEQNUMSEARCHTIMEOUT = 150382986; LITDEF int ERR_FTOKKEY = 150382995; LITDEF int ERR_SEMID = 150383003; LITDEF int ERR_JNLQIOSALVAGE = 150383011; LITDEF int ERR_FAKENOSPCLEARED = 150383019; LITDEF int ERR_MMFILETOOLARGE = 150383026; LITDEF int ERR_BADZPEEKARG = 150383034; LITDEF int ERR_BADZPEEKRANGE = 150383042; LITDEF int ERR_BADZPEEKFMT = 150383050; LITDEF int ERR_DBMBMINCFREFIXED = 150383056; LITDEF int ERR_NULLENTRYREF = 150383066; LITDEF int ERR_ZPEEKNORPLINFO = 150383074; LITDEF int ERR_MMREGNOACCESS = 150383082; LITDEF int ERR_MALLOCMAXUNIX = 150383090; LITDEF int ERR_MALLOCMAXVMS = 150383098; LITDEF int ERR_HOSTCONFLICT = 150383106; LITDEF int ERR_GETADDRINFO = 150383114; LITDEF int ERR_GETNAMEINFO = 150383122; LITDEF int ERR_SOCKBIND = 150383130; LITDEF int ERR_INSTFRZDEFER = 150383139; LITDEF int ERR_REGOPENRETRY = 150383147; LITDEF int ERR_REGOPENFAIL = 150383154; GBLDEF err_ctl merrors_ctl = { 246, "GTM", &merrors[0], 1350}; fis-gtm-V6.0-003/sr_i386/mint2mval.s0000644000032200000250000000150112201176146015631 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title mint2mval.s # .386 # .MODEL FLAT, C .include "linkage.si" .include "mval_def.si" .sbttl mint2mval # PAGE + .text # -------------------------------- # mint2mval.s # Convert int to mval # -------------------------------- .extern i2mval # PUBLIC mint2mval ENTRY mint2mval pushl %edx leal (%eax),%eax pushl %eax call i2mval addl $8,%esp ret # mint2mval ENDP # END fis-gtm-V6.0-003/sr_i386/mum_tstart.s0000644000032200000250000000151112201176146016120 0ustar librarygtc################################################################# # # # Copyright 2001, 2002 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# .TITLE mum_tstart.s .include "linkage.si" .include "g_msf.si" #comment perhaps .sbttl mum_tstart .data .extern frame_pointer .extern proc_act_type .text .extern trans_code .extern inst_flush ENTRY mum_tstart addl $4,%esp # back up over return address cmpw $0,proc_act_type je l1 call trans_code l1: getframe leal xfer_table,%ebx call inst_flush # smw 99/11/24 is this needed ret fis-gtm-V6.0-003/sr_i386/mval2bool.s0000644000032200000250000000161212201176146015620 0ustar librarygtc################################################################# # # # Copyright 2001, 2008 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title mval2bool.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "mval_def.si" .sbttl mval2bool # PAGE + # -------------------------------- # mval2bool.s # Convert mval to bool # -------------------------------- # edx - src. mval .text .extern s2n .extern underr # PUBLIC mval2bool ENTRY mval2bool mv_force_defined %edx, l1 pushl %edx mv_force_num %edx, skip_conv popl %edx cmpl $0,mval_l_m1(%edx) ret # mval2bool ENDP # END fis-gtm-V6.0-003/sr_i386/mval2mint.s0000644000032200000250000000171412201176146015637 0ustar librarygtc################################################################# # # # Copyright 2001, 2008 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title mval2mint.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "mval_def.si" .sbttl mval2mint # PAGE + # -------------------------------- # mval2mint.s # Convert mval to int # -------------------------------- # edx - source mval # eax - destination mval .text .extern mval2i .extern s2n .extern underr # PUBLIC mval2mint ENTRY mval2mint mv_force_defined %edx, l1 pushl %edx # preserve src + push it as arg mv_force_num %edx, skip_conv call mval2i addl $4,%esp ret # mval2mint ENDP # END fis-gtm-V6.0-003/sr_i386/mval2num.s0000644000032200000250000000146412201176146015471 0ustar librarygtc################################################################# # # # Copyright 2001, 2008 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title mval2num.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "mval_def.si" .sbttl mval2num # PAGE + .text .extern n2s .extern s2n .extern underr # PUBLIC mval2num ENTRY mval2num mv_force_defined %edx, l0 pushl %edx # save in case call s2n mv_force_num %edx, l1 popl %edx mv_force_str_if_num_approx %edx, l2 ret # mval2num ENDP # END fis-gtm-V6.0-003/sr_i386/mval_def.si0000644000032200000250000001550112201176146015653 0ustar librarygtc################################################################# # # # Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# .sbttl mval_def.si # PAGE + # ------------------------------------------- # mval_def.si # # This is an include file for # SCO Unix 80386 masm assembler containing # the macros for mval-related assembly routines. # ------------------------------------------- mval_v_nm = 0 mval_v_int = 1 mval_v_str = 2 mval_v_num_approx = 3 mval_v_canonical = 4 mval_v_sym = 5 mval_v_sublit = 6 mval_v_retarg = 7 mval_v_utflen = 8 mval_v_aliascont = 9 mval_m_nm = 0x001 mval_m_int_without_nm = 0x002 mval_m_int = 0x003 mval_m_str = 0x004 mval_m_num_approx = 0x008 mval_m_canonical = 0x010 mval_m_sym = 0x020 mval_m_sublit = 0x040 mval_m_retarg = 0x080 mval_m_utflen = 0x100 mval_m_aliascont = 0x200 #smw 99/7/12 Now using MS VC 5.0 so the following paragraph should # be replaced. # NOTE: The SCO C compiler pads out bit fields to the length of # the underlying type. For example, a series of "unsigned int" # bit fields will be padded out to a multiple of 4 bytes, even if # they require less than one byte total, because the underlying # type is "int". Similarly, a series of "unsigned short" bit # fields will be padded out to a multiple of 2 bytes, and a # series of "unsigned char" will be padded out to a byte boundary. # Also note the padding is not related to alignment, only to # total length. # #smw 99/10/19 gcc on Linux doesn't do the above # # Length of mval in bytes mval_byte_len = 24 # Offsets of type, exp, strlen, stradd, num in mval structure mval_w_mvtype = 0 mval_b_exp = 2 mval_l_strlen = 16 mval_a_straddr = 20 # Address offset of number in mval mvalnm_offs = 4 mval_l_m0 = 4 mval_l_m1 = 8 mval_esign_mask = 0x080 MV_BIAS = 1000 # 10**3 MANT_LO = 100000000 # 10**8 MANT_HI = 1000000000 # 10**9 INT_HI = 1000000 # 10**6 # Stringpool structure offsets base = 0 free = 4 top = 8 # mvals passed to these macros must be registers .sbttl mval_def.si mv_force_defined # --------------------------------------- # mv_force_defined(mval, label) # --------------------------------------- .macro mv_force_defined mval, label testw $(mval_m_str+mval_m_nm),mval_w_mvtype(\mval) jne \label pushl \mval call underr addl $4,%esp movl %eax, \mval \label: .endm .sbttl mval_def.si mv_force_defined_strict # --------------------------------------- # mv_force_defined_strict(mval, label) # --------------------------------------- .macro mv_force_defined_strict mval, label testw $(mval_m_str+mval_m_nm),mval_w_mvtype(\mval) jne \label pushl \mval call underr_strict addl $4,%esp \label: .endm .sbttl mval_def.si mv_force_str # --------------------------------------- # mv_force_str(mval, label) # --------------------------------------- .macro mv_force_str mval, label testw $mval_m_str,mval_w_mvtype(\mval) jne \label pushl \mval call n2s addl $4,%esp \label: .endm .sbttl mval_def.si mv_force_num # --------------------------------------- # mv_force_num(mval, label) # --------------------------------------- .macro mv_force_num mval, label testw $mval_m_nm,mval_w_mvtype(\mval) jne \label pushl \mval call s2n addl $4,%esp \label: .endm .sbttl mval_def.si mv_force_str_if_num_approx # --------------------------------------- # mv_force_str_if_num_approx(mval, label) # --------------------------------------- .macro mv_force_str_if_num_approx mval, label testw $mval_m_num_approx,mval_w_mvtype(\mval) je \label pushl \mval call n2s addl $4,%esp \label: .endm .sbttl mval_def.si mv_i2mval # --------------------------------------- # mv_i2mval(int, mval) # --------------------------------------- .macro mv_i2mval int, mval movw $mval_m_int,mval_w_mvtype(\mval) movl \int,%eax imull $MV_BIAS,%eax,%eax movl %eax,mval_l_m1(\mval) .endm .sbttl mval_def.si mv_if_string # --------------------------------------- # mv_if_string(mval,label) # --------------------------------------- .macro mv_if_string mval, label testw $mval_m_str,mval_w_mvtype(\mval) jne \label .endm .sbttl mval_def.si mv_if_number # --------------------------------------- # mv_if_number(mval,label) # --------------------------------------- .macro mv_if_number mval, label testw $mval_m_nm,mval_w_mvtype(\mval) jne \label .endm .sbttl mval_def.si mv_if_int # --------------------------------------- # mv_if_int(mval,label) # --------------------------------------- .macro mv_if_int mval, label testw $mval_m_int_without_nm,mval_w_mvtype(\mval) jne \label .endm .sbttl mval_def.si mv_if_notstring # --------------------------------------- # mv_if_notstring(mval,label) # --------------------------------------- .macro mv_if_notstring mval, label testw $mval_m_str,mval_w_mvtype(\mval) je \label .endm .sbttl mval_def.si mv_if_notnumber # --------------------------------------- # mv_if_notnumber(mval,label) # --------------------------------------- .macro mv_if_notnumber mval, label testw $mval_m_nm,mval_w_mvtype(\mval) je \label .endm .sbttl mval_def.si mv_if_notint # --------------------------------------- # mv_if_notint(mval,label) # --------------------------------------- .macro mv_if_notint mval, label testw $mval_m_int_without_nm,mval_w_mvtype(\mval) je \label .endm .sbttl mval_def.si mv_if_defined # --------------------------------------- # mv_if_defined(mval,label) # --------------------------------------- .macro mv_if_defined mval, label testw $(mval_m_str+mval_m_nm),mval_w_mvtype(\mval) jne \label .endm .sbttl mval_def.si mv_if_notdefined # --------------------------------------- # mv_if_notdefined(mval,label) # --------------------------------------- .macro mv_if_notdefined mval, label testw $(mval_m_str+mval_m_nm),mval_w_mvtype(\mval) je \label .endm .sbttl mval_def.si mv_if_canonical # ------------------------------------------------------------- # WARNING: # Following macro needs to be supplied with 2 extra labels that # are used by local branch instructions, tmp_label1 and tmp_label2 # ------------------------------------------------------------- # mv_if_canonical(mval,mainlabel, tmp_label1, tmp_label2) # ------------------------------------------------------------- .macro mv_if_canonical mval, mainlabel, tmp_label1, tmp_label2 testw $mval_m_nm,mval_w_mvtype(\mval) je \tmp_label1 testw $mval_m_num_approx,mval_w_mvtype(\mval) jne \tmp_label2 jmp \mainlabel \tmp_label1: pushl \mval call val_iscan addl $4,%esp cmpl $0,%eax jne \mainlabel \tmp_label2: .endm fis-gtm-V6.0-003/sr_i386/obj_file.c0000644000032200000250000002603312201176176015463 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include #include "compiler.h" #include #include "obj_gen.h" #include "cgp.h" #include "mdq.h" #include "cmd_qlf.h" #include "objlabel.h" /* needed for masscomp.h */ #include "masscomp.h" #include "stringpool.h" #include "parse_file.h" #include "gtm_fcntl.h" #include "gtm_unistd.h" #include "gtmio.h" #include "mmemory.h" #include "obj_file.h" LITREF char gtm_release_name[]; LITREF int4 gtm_release_name_len; GBLREF mliteral literal_chain; GBLREF char source_file_name[]; GBLREF unsigned short source_name_len; GBLREF command_qualifier cmd_qlf; GBLREF mident routine_name; GBLREF mident module_name; GBLREF boolean_t run_time; GBLREF int4 mlmax, mvmax; GBLREF int4 code_size, lit_addrs, lits_size; GBLDEF int4 psect_use_tab[GTM_LASTPSECT]; /* bytes of each psect in this module */ GBLREF char object_file_name[]; GBLREF short object_name_len; GBLREF int object_file_des; static short int current_psect; static char emit_buff[OBJ_EMIT_BUF_SIZE]; /* buffer for emit output */ static short int emit_buff_used; /* number of chars in emit_buff */ GBLREF uint4 txtrel_cnt; static uint4 cdlits; static struct rel_table *data_rel, *data_rel_end; static struct rel_table *text_rel, *text_rel_end; DEBUG_ONLY(static uint4 txtrel_cnt_in_hdr;) error_def(ERR_OBJFILERR); void create_object_file(rhdtyp *rhead) { int status; unsigned char rout_len; uint4 stat; char obj_name[SIZEOF(mident_fixed) + 5]; mstr fstr; parse_blk pblk; struct exec hdr; error_def(ERR_FILEPARSE); assert(!run_time); memset(&pblk, 0, SIZEOF(pblk)); pblk.buffer = object_file_name; pblk.buff_size = MAX_FBUFF; /* create the object file */ fstr.len = (MV_DEFINED(&cmd_qlf.object_file) ? cmd_qlf.object_file.str.len : 0); fstr.addr = cmd_qlf.object_file.str.addr; rout_len = module_name.len; memcpy(&obj_name[0], module_name.addr, rout_len); obj_name[rout_len] = '.'; obj_name[rout_len + 1] = 'o'; obj_name[rout_len + 2] = 0; pblk.def1_size = rout_len + 2; pblk.def1_buf = obj_name; status = parse_file(&fstr, &pblk); if (!(status & 1)) rts_error(VARLSTCNT(5) ERR_FILEPARSE, 2, fstr.len, fstr.addr, status); object_name_len = pblk.b_esl; object_file_name[object_name_len] = 0; OPEN_OBJECT_FILE(object_file_name, O_CREAT | O_RDWR, object_file_des); if (FD_INVALID == object_file_des) rts_error(VARLSTCNT(5) ERR_OBJFILERR, 2, object_name_len, object_file_name, errno); memcpy(&rhead->jsb[0], "GTM_CODE", SIZEOF(rhead->jsb)); emit_addr((char *)&rhead->src_full_name.addr - (char *)rhead, (int4)rhead->src_full_name.addr, (int4 *)&rhead->src_full_name.addr); emit_addr((char *)&rhead->routine_name.addr - (char *)rhead, (int4)rhead->routine_name.addr, (int4 *)&rhead->routine_name.addr); txtrel_cnt += 2; DEBUG_ONLY(txtrel_cnt_in_hdr = txtrel_cnt;) set_psect(GTM_CODE, 0); hdr.a_magic = OMAGIC; hdr.a_stamp = OBJ_LABEL; hdr.a_entry = 0; hdr.a_bss = 0; hdr.a_text = code_size; assert(0 == PADLEN(lits_size, NATIVE_WSIZE)); hdr.a_data = lits_size; /* and pad to even # */ hdr.a_syms = (mlmax + cdlits) * SIZEOF(struct nlist); hdr.a_trsize = txtrel_cnt * SIZEOF(struct relocation_info); hdr.a_drsize = lit_addrs * SIZEOF(struct relocation_info); emit_immed((char *)&hdr, SIZEOF(hdr)); memset(psect_use_tab, 0, SIZEOF(psect_use_tab)); emit_immed((char *)rhead, SIZEOF(*rhead)); } void close_object_file(void) { assert(0 == PADLEN(lits_size, NATIVE_WSIZE)); resolve_sym(); output_relocation(); output_symbol(); if (emit_buff_used) buff_emit(); if ((off_t)-1 == lseek(object_file_des, (off_t)0, SEEK_SET)) rts_error(VARLSTCNT(5) ERR_OBJFILERR, 2, object_name_len, object_file_name, errno); } void drop_object_file(void) { int rc; if (FD_INVALID != object_file_des) { UNLINK(object_file_name); CLOSEFILE_RESET(object_file_des, rc); /* resets "object_file_des" to FD_INVALID */ } } GBLREF spdesc stringpool; void emit_addr(int4 refaddr, int4 offset, int4 *result) { struct rel_table *newrel; if (run_time) { unsigned char *ptr; ptr = stringpool.free; *result = offset - (int4) ptr; } else { *result = offset + code_size; newrel = (struct rel_table *) mcalloc(SIZEOF(struct rel_table)); newrel->next = (struct rel_table *) 0; newrel->resolve = 0; newrel->r.r_address = refaddr; newrel->r.r_symbolnum = N_DATA; newrel->r.r_pcrel = 0; newrel->r.r_length = 2; newrel->r.r_extern = 0; newrel->r.r_pad = 0; if (!text_rel) text_rel = text_rel_end = newrel; else { text_rel_end->next = newrel; text_rel_end = newrel; } } return; } void emit_pidr(int4 refoffset, int4 data_offset, int4 *result) { struct rel_table *newrel; assert(!run_time); refoffset += code_size; data_offset += code_size; *result = data_offset; newrel = (struct rel_table *) mcalloc(SIZEOF(struct rel_table)); newrel->next = (struct rel_table *)0; newrel->resolve = 0; newrel->r.r_address = refoffset; newrel->r.r_symbolnum = N_DATA; newrel->r.r_pcrel = 0; newrel->r.r_length = 2; newrel->r.r_extern = 0; newrel->r.r_pad = 0; if (!data_rel) data_rel = data_rel_end = newrel; else { data_rel_end->next = newrel; data_rel_end = newrel; } } void emit_reference(uint4 refaddr, mstr *name, uint4 *result) { struct sym_table *sym; struct rel_table *newrel; sym = define_symbol(0, name, 0); assert(sym); if (sym->n.n_type == (N_TEXT | N_EXT)) *result = sym->n.n_value; else { newrel = (struct rel_table *) mcalloc(SIZEOF(struct rel_table)); newrel->next = (struct rel_table *)0; newrel->resolve = 0; newrel->r.r_address = refaddr; newrel->r.r_symbolnum = 0; newrel->r.r_pcrel = 0; newrel->r.r_length = 2; newrel->r.r_extern = 1; newrel->r.r_pad = 0; if (!text_rel) text_rel = text_rel_end = newrel; else { text_rel_end->next = newrel; text_rel_end = newrel; } if (sym->resolve) newrel->resolve = sym->resolve; sym->resolve = newrel; *result = 0; } } /* * emit_immed * * Args: buffer of executable code, and byte count to be output. */ error_def(ERR_STRINGOFLOW); void emit_immed(char *source, uint4 size) { short int write; if (run_time) { if (stringpool.free + size > stringpool.top) rts_error(VARLSTCNT(1) ERR_STRINGOFLOW); memcpy(stringpool.free, source, size); stringpool.free += size; } else { while(size > 0) { write = SIZEOF(emit_buff) - emit_buff_used; write = size < write ? size : write; memcpy(emit_buff + emit_buff_used, source, write); size -= write; source += write; emit_buff_used += write; psect_use_tab[current_psect] += write; if (size) buff_emit(); } } } /* * buff_emit * * Args: buffer pointer, number of bytes to emit */ void buff_emit(void) { uint4 stat; if (-1 == write(object_file_des, emit_buff, emit_buff_used)) rts_error(VARLSTCNT(5) ERR_OBJFILERR, 2, object_name_len, object_file_name, errno); emit_buff_used = 0; } void set_psect(unsigned char psect,unsigned char offset) { current_psect = psect; return; } /* * define_symbol * * Args: psect index, symbol name, symbol value. * * Description: Buffers a definition of a global symbol with the * given name and value in the given psect. */ static struct sym_table *symbols; struct sym_table *define_symbol(unsigned char psect, mstr *name, int4 value) { int cmp; struct sym_table *sym, *sym1, *newsym; sym = symbols; sym1 = 0; while(sym) { if ((cmp = memvcmp(name->addr, name->len, &sym->name[0], sym->name_len - 1)) <= 0) break; sym1 = sym; sym = sym->next; } if (cmp || !sym) { newsym = (struct sym_table *) mcalloc(SIZEOF(struct sym_table) + name->len); newsym->name_len = name->len + 1; memcpy(&newsym->name[0], name->addr, name->len); newsym->name[ name->len ] = 0; newsym->n.n_strx = 0; newsym->n.n_type = N_EXT; if (psect == GTM_CODE) newsym->n.n_type |= N_TEXT; /* if symbol is in GTM_CODE, it is defined */ else txtrel_cnt++; newsym->n.n_other = 0; newsym->n.n_desc = 0; newsym->n.n_value = value; newsym->resolve = 0; newsym->next = sym; if (sym1) sym1->next = newsym; else symbols = newsym; cdlits++; return 0; } if (!(sym->n.n_type & N_TEXT)) txtrel_cnt++; return sym; } void resolve_sym(void) { uint4 symnum; struct sym_table *sym; struct rel_table *rel; symnum = 0; sym = symbols; while (sym) { if (sym->resolve) { rel = sym->resolve; while (rel) { rel->r.r_symbolnum = symnum; rel = rel->resolve; } } symnum++; sym = sym->next; } } void output_relocation(void) { struct rel_table *rel; DEBUG_ONLY(int cnt;) DEBUG_ONLY(cnt = 0;) rel = text_rel; while (rel) { emit_immed((char *)&rel->r, SIZEOF(rel->r)); rel = rel->next; DEBUG_ONLY(cnt++;) } assert(cnt == txtrel_cnt_in_hdr); DEBUG_ONLY(cnt = 0;) rel = data_rel; while (rel) { emit_immed((char *)&rel->r, SIZEOF(rel->r)); rel = rel->next; DEBUG_ONLY(cnt++;) } assert(cnt == lit_addrs); } void output_symbol(void) { uint4 string_length; struct sym_table *sym; string_length = SIZEOF(int4); sym = symbols; while (sym) { sym->n.n_strx = string_length; emit_immed((char *)&sym->n, SIZEOF(sym->n)); string_length += sym->name_len; sym = sym->next; } emit_immed((char *)&string_length, SIZEOF(string_length)); sym = symbols; while (sym) { emit_immed((char *)&sym->name[0], sym->name_len); sym = sym->next; } } void obj_init(void) { cdlits = txtrel_cnt = 0; data_rel = text_rel = data_rel_end = text_rel_end = 0; symbols = 0; } void emit_literals(void) { uint4 offset, padsize; mliteral *p; set_psect(GTM_LITERALS, 0); offset = stringpool.free - stringpool.base; emit_immed((char *)stringpool.base, offset); /* comp_lits aligns the start of source path on a NATIVE_WSIZE boundary.*/ padsize = PADLEN(offset, NATIVE_WSIZE); if (padsize) { emit_immed(PADCHARS, padsize); offset += padsize; } emit_immed(source_file_name, source_name_len); offset += source_name_len; /* comp_lits aligns the start of routine_name on a NATIVE_WSIZE boundary.*/ padsize = PADLEN(offset, NATIVE_WSIZE); if (padsize) { emit_immed(PADCHARS, padsize); offset += padsize; } emit_immed(routine_name.addr, routine_name.len); offset += routine_name.len; /* comp_lits aligns the start of the literal area on a NATIVE_WSIZE boundary.*/ padsize = PADLEN(offset, NATIVE_WSIZE); if (padsize) { emit_immed(PADCHARS, padsize); offset += padsize; } dqloop(&literal_chain, que, p) { assert (p->rt_addr == offset); MV_FORCE_NUMD(&p->v); if (p->v.str.len) emit_pidr(p->rt_addr + ((char *) &p->v.str.addr - (char *)&p->v), p->v.str.addr - (char *) stringpool.base, (int4 *)&p->v.str.addr); else p->v.str.addr = 0; emit_immed((char *)&p->v, SIZEOF(p->v)); offset += SIZEOF(p->v); } assert(lits_size == offset); } fis-gtm-V6.0-003/sr_i386/op_bkpt.s0000644000032200000250000001071712201176146015367 0ustar librarygtc################################################################# # # # Copyright 2001, 2010 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_bkpt.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_zstepret # PAGE + .DATA .extern frame_pointer .extern zstep_level .text .extern gtm_fetch .extern op_retarg .extern op_zbreak .extern op_zst_break .extern op_zst_over .extern op_zstepret .extern opp_ret # PUBLIC opp_zstepret ENTRY opp_zstepret movl frame_pointer,%eax movw msf_typ_off(%eax),%dx testw $1,%dx je l1 movl zstep_level,%edx cmpl %eax, %edx jg l1 call op_zstepret l1: jmp opp_ret # opp_zstepret ENDP # PUBLIC opp_zstepretarg ENTRY opp_zstepretarg pushl %eax pushl %edx movl frame_pointer,%eax movw msf_typ_off(%eax),%dx testw $1,%dx je l2 movl zstep_level,%edx cmpl %eax, %edx jg l2 call op_zstepret l2: popl %edx popl %eax jmp op_retarg # opp_zstepretarg ENDP # PUBLIC op_zbfetch ENTRY op_zbfetch movl frame_pointer,%edx popl msf_mpc_off(%edx) call gtm_fetch popl %eax # lea esp, [esp][eax*4] leal (%esp,%eax,4),%esp pushl frame_pointer call op_zbreak addl $4,%esp getframe ret # op_zbfetch ENDP # PUBLIC op_zbstart ENTRY op_zbstart movl frame_pointer,%edx popl msf_mpc_off(%edx) pushl %edx call op_zbreak addl $4,%esp getframe ret # op_zbstart ENDP # PUBLIC op_zstepfetch ENTRY op_zstepfetch movl frame_pointer,%edx popl msf_mpc_off(%edx) call gtm_fetch popl %eax # lea esp, [esp][eax*4] leal (%esp,%eax,4),%esp call op_zst_break getframe ret # op_zstepfetch ENDP # PUBLIC op_zstepstart ENTRY op_zstepstart movl frame_pointer,%edx popl msf_mpc_off(%edx) call op_zst_break getframe ret # op_zstepstart ENDP # PUBLIC op_zstzbfetch ENTRY op_zstzbfetch movl frame_pointer,%edx popl msf_mpc_off(%edx) call gtm_fetch popl %eax # lea esp, [esp][eax*4] leal (%esp,%eax,4),%esp pushl frame_pointer call op_zbreak addl $4,%esp call op_zst_break getframe ret # op_zstzbfetch ENDP # PUBLIC op_zstzbstart ENTRY op_zstzbstart movl frame_pointer,%edx popl msf_mpc_off(%edx) pushl %edx call op_zbreak addl $4,%esp call op_zst_break getframe ret # op_zstzbstart ENDP # PUBLIC op_zstzb_fet_over ENTRY op_zstzb_fet_over movl frame_pointer,%edx popl msf_mpc_off(%edx) call gtm_fetch popl %eax # lea esp, [esp][eax*4] leal (%esp,%eax,4),%esp pushl frame_pointer call op_zbreak addl $4,%esp movl zstep_level,%edx cmpl frame_pointer,%edx jle l3 cmpl $0,%eax jne l5 jmp l4 l3: call op_zst_break l4: getframe ret l5: call op_zst_over movl frame_pointer,%edx pushl msf_mpc_off(%edx) ret # op_zstzb_fet_over ENDP # PUBLIC op_zstzb_st_over ENTRY op_zstzb_st_over movl frame_pointer,%edx popl msf_mpc_off(%edx) pushl %edx call op_zbreak addl $4,%esp movl zstep_level,%edx cmpl frame_pointer,%edx jle l6 cmpl $0,%eax jne l8 jmp l7 l6: call op_zst_break l7: getframe ret l8: call op_zst_over movl frame_pointer,%edx pushl msf_mpc_off(%edx) ret # op_zstzb_st_over ENDP # PUBLIC op_zst_fet_over ENTRY op_zst_fet_over movl frame_pointer,%edx popl msf_mpc_off(%edx) call gtm_fetch popl %eax # lea esp, [esp][eax*4] leal (%esp,%eax,4),%esp movl zstep_level,%edx cmpl frame_pointer,%edx jg l9 call op_zst_break getframe ret l9: call op_zst_over movl frame_pointer,%edx pushl msf_mpc_off(%edx) ret # op_zst_fet_over ENDP # PUBLIC op_zst_st_over ENTRY op_zst_st_over movl frame_pointer,%eax popl msf_mpc_off(%eax) movl zstep_level,%edx cmpl %eax,%edx jg l10 call op_zst_break getframe ret l10: call op_zst_over movl frame_pointer,%edx pushl msf_mpc_off(%edx) ret # op_zst_st_over ENDP # PUBLIC opp_zst_over_ret ENTRY opp_zst_over_ret movl frame_pointer,%eax movw msf_typ_off(%eax),%dx testw $1,%dx je l11 movl zstep_level,%edx movl msf_old_frame_off(%eax),%eax cmpl %eax,%edx jg l11 call op_zstepret l11: jmp opp_ret # opp_zst_over_ret ENDP # PUBLIC opp_zst_over_retarg ENTRY opp_zst_over_retarg pushl %eax pushl %edx movl frame_pointer,%eax movw msf_typ_off(%eax),%dx testw $1,%dx je l12 movl zstep_level,%edx movl msf_old_frame_off(%eax),%eax cmpl %eax,%edx jg l12 call op_zstepret l12: popl %edx popl %eax jmp op_retarg # opp_zst_over_retarg ENDP # END fis-gtm-V6.0-003/sr_i386/op_call.s0000644000032200000250000000201612201176146015333 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_call.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_callb # PAGE + .DATA .extern frame_pointer .text .extern copy_stack_frame # PUBLIC op_callb ENTRY op_callb movl frame_pointer,%edx movl (%esp),%eax movl %eax,msf_mpc_off(%edx) addl $2,msf_mpc_off(%edx) call copy_stack_frame ret # op_callb ENDP .sbttl op_callw, op_calll # PUBLIC op_callw, op_calll ENTRY op_calll ENTRY op_callw movl frame_pointer,%edx movl (%esp),%eax movl %eax,msf_mpc_off(%edx) addl $5,msf_mpc_off(%edx) call copy_stack_frame ret # op_calll ENDP # END fis-gtm-V6.0-003/sr_i386/op_callsp.s0000644000032200000250000000236612201176146015706 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_callsp.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_callsp # PAGE + .DATA .extern dollar_truth .extern frame_pointer .text .extern exfun_frame .extern push_tval .sbttl op_callspb # PUBLIC op_callspb ENTRY op_callspb movl frame_pointer,%edx movl (%esp),%eax movl %eax,msf_mpc_off(%edx) addl $2,msf_mpc_off(%edx) # store pc in MUMPS stack frame doit: call exfun_frame pushl dollar_truth call push_tval addl $4,%esp movl frame_pointer,%edx movl msf_temps_ptr_off(%edx),%edi ret # op_callspb ENDP .sbttl op_callspw, op_callspl # PUBLIC op_callspw, op_callspl ENTRY op_callspw ENTRY op_callspl movl frame_pointer,%edx movl (%esp),%eax movl %eax,msf_mpc_off(%edx) addl $5,msf_mpc_off(%edx) # store pc in MUMPS stack frame jmp doit # op_callspw ENDP # END fis-gtm-V6.0-003/sr_i386/op_contain.s0000644000032200000250000000303312201176146016053 0ustar librarygtc################################################################# # # # Copyright 2001, 2009 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_contain.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "mval_def.si" .sbttl op_contain # PAGE + .text sav_eax = -4 sav_edx = -8 .extern matchc .extern n2s .extern underr # PUBLIC op_contain ENTRY op_contain enter $8, $0 pushl %edi pushl %esi pushl %ebx movl %edx, sav_edx(%ebp) mv_force_defined %eax, l1 movl %eax, sav_eax(%ebp) mv_force_str %eax, l2 movl sav_edx(%ebp), %edx mv_force_defined %edx, l3 movl %edx, sav_edx(%ebp) mv_force_str %edx, l4 pushl $1 # pieces argument but have to pass its addr movl %esp, %edx subl $4, %esp # returned value movl %esp, %eax pushl %edx # parm 6 pushl %eax # parm 5 movl sav_eax(%ebp), %eax movl sav_edx(%ebp), %edx pushl mval_a_straddr(%eax) # parm 4 movl mval_l_strlen(%eax), %eax pushl %eax # parm 3 pushl mval_a_straddr(%edx) # parm 2 movl mval_l_strlen(%edx), %eax pushl %eax # parm 1 call matchc leal 24(%esp), %esp # remove args popl %eax # return value popl %edx # updated pieces value (ignored) cmpl $0, %eax popl %ebx popl %esi popl %edi leave ret # op_contain ENDP # END fis-gtm-V6.0-003/sr_i386/op_currtn.s0000644000032200000250000000200612201176146015734 0ustar librarygtc################################################################# # # # Copyright 2001, 2006 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_currtn.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "mval_def.si" .INCLUDE "g_msf.si" .sbttl op_currtn # PAGE + .DATA .extern frame_pointer .text # PUBLIC op_currtn ENTRY op_currtn movw $mval_m_str,mval_w_mvtype(%edx) movl frame_pointer,%eax movl msf_rvector_off(%eax),%eax pushl mrt_rtn_len(%eax) popl mval_l_strlen(%edx) # %edx->str.len = frame_pointer->rvector->routine_name.len movl mrt_rtn_addr(%eax),%eax movl %eax,mval_a_straddr(%edx) # %edx->str.addr = frame_pointer->rvector->routine_name.addr ret # op_currtn ENDP # END fis-gtm-V6.0-003/sr_i386/op_equ.s0000644000032200000250000000124012201176146015210 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_equ.s .sbttl op_equ .include "linkage.si" # .386 # .MODEL FLAT, C .text .extern is_equ # PUBLIC op_equ ENTRY op_equ pushl %edx pushl %eax call is_equ addl $8,%esp cmpl $0,%eax ret # op_equ ENDP # END fis-gtm-V6.0-003/sr_i386/op_equnul.s0000644000032200000250000000204512201176146015733 0ustar librarygtc################################################################# # # # Copyright 2001, 2006 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_equnul.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "mval_def.si" .sbttl op_equnul # PAGE + .DATA .extern undef_inhibit .text .extern underr # PUBLIC op_equnul ENTRY op_equnul mv_if_notdefined %eax, l3 testw $mval_m_str,mval_w_mvtype(%eax) je l2 cmpl $0,mval_l_strlen(%eax) jne l2 l1: movl $1,%eax cmpl $0,%eax ret l2: movl $0,%eax cmpl $0,%eax ret l3: cmpb $0,undef_inhibit # not defined jne l1 # if undef_inhibit, then all undefined # values are equal to null string pushl %eax # really undef call underr addl $4,%esp ret # op_equnul ENDP # END fis-gtm-V6.0-003/sr_i386/op_exfun.s0000644000032200000250000000414212201176146015547 0ustar librarygtc################################################################# # # # Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_exfun.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_exfun # PAGE + # call op_exfun with the following stack: # # return PC # ret_value address # mask # actualcnt # actual1 address # actual2 address # ... .DATA .extern ERR_GTMCHECK .extern dollar_truth .extern frame_pointer .text .extern exfun_frame .extern push_parm .extern rts_error JMP_Jb = 0x0eb JMP_Jv = 0x0e9 actual1 = 20 act_cnt = 16 mask_arg = 12 ret_val = 8 rtn_pc = 4 sav_esi = -4 sav_ebx = -8 sav_msf = -12 # PUBLIC op_exfun ENTRY op_exfun pushl %ebp movl %esp,%ebp pushl %esi pushl %ebx leal sav_msf(%ebp),%esp # establish space for locals movl act_cnt(%ebp),%eax addl $3,%eax negl %eax leal (%esp,%eax,4),%esp # establish space for temps movl frame_pointer,%edx movl rtn_pc(%ebp),%eax cmpb $JMP_Jv,(%eax) je long cmpb $JMP_Jb,(%eax) je byte_off error: pushl ERR_GTMCHECK pushl $1 call rts_error addl $8,%esp jmp retlab byte_off: movl %eax,msf_mpc_off(%edx) addl $2,msf_mpc_off(%edx) jmp cont long: movl %eax,msf_mpc_off(%edx) addl $5,msf_mpc_off(%edx) cont: call exfun_frame leal ret_val(%ebp),%esi movl %esp,%edi movl act_cnt(%ebp),%eax movl %eax,%ecx addl $3,%ecx REP movsl movl dollar_truth,%ecx andl $1,%ecx pushl %ecx # push $T addl $4,%eax pushl %eax # push total count call push_parm # push_parm ($T, ret_value, mask, argc [,arg1, arg2, ...]); done: movl frame_pointer,%edx movl msf_temps_ptr_off(%edx),%edi retlab: leal sav_ebx(%ebp),%esp movl rtn_pc(%ebp),%edx movl act_cnt(%ebp),%eax addl $4,%eax popl %ebx popl %esi popl %ebp leal (%esp,%eax,4),%esp pushl %edx ret # op_exfun ENDP # END fis-gtm-V6.0-003/sr_i386/op_extcall.s0000644000032200000250000000315412201176146016060 0ustar librarygtc################################################################# # # # Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_extcall.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_extcall # PAGE + .DATA .extern ERR_GTMCHECK .extern ERR_LABELUNKNOWN .extern frame_pointer .text .extern auto_zlink .extern new_stack_frame .extern rts_error # PUBLIC op_extcall ENTRY op_extcall putframe addl $4,%esp # burn return pc popl %edx # routine hdr addr popl %eax # label addr cmpl $0,%eax je l2 l1: movl (%eax),%eax # get the line number offset cmpl $0,%eax je l4 addl mrt_curr_ptr(%edx),%eax addl %edx,%eax # get the line number pointer movl (%eax),%eax # get the line number addl mrt_curr_ptr(%edx),%eax addl %edx,%eax pushl %eax pushl $0 pushl %edx call new_stack_frame addl $12,%esp getframe ret l2: cmpl $0,%edx jne l4 subl $4,%esp pushl %esp movl frame_pointer,%eax pushl msf_mpc_off(%eax) call auto_zlink addl $8,%esp cmpl $0,%eax je l3 movl %eax,%edx popl %eax cmpl $0,%eax jne l1 l3: addl $4,%esp pushl ERR_GTMCHECK pushl $1 call rts_error pushl $1 # in original m68020 code ?? addl $8,%esp getframe ret l4: pushl ERR_LABELUNKNOWN pushl $1 call rts_error addl $8,%esp getframe ret # op_extcall ENDP # END fis-gtm-V6.0-003/sr_i386/op_extexfun.s0000644000032200000250000000545012201176146016273 0ustar librarygtc################################################################# # # # Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_extexfun.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_extexfun # PAGE + # call op_extexfun with the following stack: # # return PC # routine # label # ret_value address # mask # actualcnt # actual1 address # actual2 address # ... .DATA .extern ERR_FMLLSTMISSING .extern ERR_GTMCHECK .extern ERR_LABELUNKNOWN .extern dollar_truth .extern frame_pointer .text .extern auto_zlink .extern new_stack_frame .extern push_parm .extern rts_error actual1 = 24 act_cnt = 20 mask_arg = 16 ret_val = 12 label_arg = 8 routine = 4 sav_ebx = -4 sav_msf = -8 # PUBLIC op_extexfun ENTRY op_extexfun putframe addl $4,%esp # burn return PC pushl %ebp movl %esp,%ebp pushl %ebx leal sav_msf(%ebp),%esp # establish space for locals movl act_cnt(%ebp),%eax addl $3,%eax negl %eax leal (%esp,%eax,4),%esp # add space for temps movl routine(%ebp),%edx movl label_arg(%ebp),%eax cmpl $0,%eax je l3 l1: pushl %eax # save labaddr movl (%eax),%eax # get offset to line number entry cmpl $0,%eax je l5 addl mrt_curr_ptr(%edx),%eax addl %edx,%eax # get the pointer to line number entry movl (%eax),%ebx # get line number addl mrt_curr_ptr(%edx),%ebx addl %edx,%ebx popl %eax # restore labaddr cmpl $0,4(%eax) # labaddr += 4, to point to has_parms; then *has_parms je l6 # if has_parms == 0, then issue an error pushl %ebx pushl $0 pushl %edx call new_stack_frame addl $12,%esp leal ret_val(%ebp),%esi movl %esp,%edi movl act_cnt(%ebp),%eax movl %eax,%ecx addl $3,%ecx # include: A(ret_value), mask, argc REP movsl movl dollar_truth,%ecx andl $1,%ecx pushl %ecx addl $4,%eax # include: $T(just pushed) plus other 3 pushl %eax # push total count call push_parm # push_parm ($T, ret_value, mask, argc [,arg1, arg2, ...]); retlab: leal sav_ebx(%ebp),%esp movl act_cnt(%ebp),%eax addl $5,%eax popl %ebx popl %ebp leal (%esp,%eax,4),%esp getframe ret l3: cmpl $0,%edx jne l5 subl $4,%esp movl %esp,%eax pushl %eax movl frame_pointer,%edx pushl msf_mpc_off(%edx) call auto_zlink addl $8,%esp cmpl $0,%eax je l4 movl %eax,%edx popl %eax cmpl $0,%eax jne l1 l4: pushl ERR_GTMCHECK pushl $1 call rts_error jmp retlab l5: pushl ERR_LABELUNKNOWN pushl $1 call rts_error jmp retlab l6: pushl ERR_FMLLSTMISSING pushl $1 call rts_error jmp retlab # op_extexfun ENDP # END fis-gtm-V6.0-003/sr_i386/op_extjmp.s0000644000032200000250000000301612201176146015730 0ustar librarygtc################################################################# # # # Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_extjmp.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_extjmp # PAGE + .DATA .extern ERR_GTMCHECK .extern ERR_LABELUNKNOWN .extern frame_pointer .text .extern auto_zlink .extern flush_jmp .extern rts_error # PUBLIC op_extjmp ENTRY op_extjmp putframe addl $4,%esp # Burn return pc popl %edx cmpl $0,%edx je l2 popl %eax cmpl $0,%eax je l4 l1: movl (%eax),%eax # get line number offset cmpl $0,%eax je l4 addl mrt_curr_ptr(%edx),%eax addl %edx,%eax # get line number pointer movl (%eax),%eax # get line number addl mrt_curr_ptr(%edx),%eax addl %edx,%eax pushl %eax pushl $0 pushl %edx call flush_jmp addl $12,%esp getframe ret l2: movl %esp,%eax pushl %eax movl frame_pointer,%eax pushl msf_mpc_off(%eax) call auto_zlink addl $8,%esp cmpl $0,%eax je l3 movl %eax,%edx popl %eax cmpl $0,%eax jne l1 jmp l4 l3: addl $4,%esp pushl ERR_GTMCHECK pushl $1 call rts_error addl $8,%esp getframe ret l4: pushl ERR_LABELUNKNOWN pushl $1 call rts_error addl $8,%esp getframe ret # op_extjmp ENDP # END fis-gtm-V6.0-003/sr_i386/op_fetchintrrpt.s0000644000032200000250000000210512201176146017133 0ustar librarygtc################################################################# # # # Copyright 2001, 2009 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_fetchintrrpt.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_fetchintrrpt # PAGE + .DATA .extern frame_pointer .extern neterr_pending .text .extern gtm_fetch .extern gvcmz_neterr .extern outofband_clear .extern async_action # PUBLIC op_fetchintrrpt ENTRY op_fetchintrrpt movl frame_pointer,%edx popl msf_mpc_off(%edx) call gtm_fetch popl %eax leal (%esp,%eax,4),%esp cmpb $0,neterr_pending je l1 call outofband_clear pushl $0 call gvcmz_neterr addl $4,%esp l1: pushl $1 call async_action movl frame_pointer,%edx pushl msf_mpc_off(%edx) ret # op_fetchintrrpt ENDP # END fis-gtm-V6.0-003/sr_i386/op_fnget.s0000644000032200000250000000231712201176146015527 0ustar librarygtc################################################################# # # # Copyright 2001, 2009 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_fnget.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "mval_def.si" .sbttl op_fnget # PAGE + # ------------------------------------ # op_fnget.s # # Mumps $Get function # ------------------------------------ # edx - src. mval # eax - dest. mval .text # PUBLIC op_fnget ENTRY op_fnget cmpl $0,%edx je l5 # if arg = 0, set type and len mv_if_notdefined %edx, l5 # Copy the mval from [edx] to [eax]. pushl %edi pushl %esi movl $mval_byte_len,%ecx movl %edx,%esi movl %eax,%edi REP movsb andw $~mval_m_aliascont, mval_w_mvtype(%eax) # Don't propagate alias container flag popl %esi popl %edi ret l5: movw $mval_m_str,mval_w_mvtype(%eax) # string type movl $0,mval_l_strlen(%eax) # dest. str. len. = 0 ret # op_fnget ENDP # END fis-gtm-V6.0-003/sr_i386/op_fnzextract.s0000644000032200000250000000426312201176146016616 0ustar librarygtc################################################################# # # # Copyright 2006, 2008 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_fnzextract.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "mval_def.si" .sbttl op_fnzextract # PAGE + # ------------------------------------ # op_fnzextract.s # # Mumps $Extract function # ------------------------------------ # -------------------------------- # op_fnzextract (int last, int first, mval *src, mval *dest) # -------------------------------- # esi - src mval # edi - dest mval # ecx - src. str. len. # ebx - resultant str. len. # eax - first index # edx - last index last = 8 first = 12 src = 16 dest = 20 .text .extern n2s .extern underr # PUBLIC op_fnzextract ENTRY op_fnzextract enter $0,$0 pushl %edi pushl %esi pushl %ebx movl src(%ebp),%esi # esi - src. mval mv_force_defined %esi, l00 movl %esi, src(%ebp) # save possibly modified src ptr mv_force_str %esi, l01 movl src(%ebp),%esi # esi - src.mval movl first(%ebp),%eax # eax - first cmpl $0,%eax jg l10 movl $1,%eax # if first < 1, then first = 1 l10: movl last(%ebp),%edx # edx - last movl dest(%ebp),%edi # edi - last movw $mval_m_str,mval_w_mvtype(%edi) # always a string movl mval_l_strlen(%esi),%ecx # ecx - src. str. len. cmpl %eax,%ecx # if left index > str. len, # then null result jl l25 cmpl %edx,%ecx # right index may be at most the len. jge l20 # of the source string movl %ecx,%edx l20: movl %edx,%ebx subl %eax,%ebx # result len. = end - start + 1 addl $1,%ebx jg l30 # if len > 0, then continue l25: movl $0,mval_l_strlen(%edi) jmp retlab l30: movl %ebx,mval_l_strlen(%edi) # dest. str. len. subl $1,%eax # base = src.addr + left ind. - 1 addl mval_a_straddr(%esi),%eax movl %eax,mval_a_straddr(%edi) # string addr. retlab: popl %ebx popl %esi popl %edi leave ret # op_fnzextract ENDP # END fis-gtm-V6.0-003/sr_i386/op_follow.s0000644000032200000250000000226112201176146015724 0ustar librarygtc################################################################# # # # Copyright 2001, 2008 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_follow.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "mval_def.si" .sbttl op_follow # PAGE + sav_eax = -4 sav_edx = -8 .text .extern memvcmp .extern n2s .extern underr # PUBLIC op_follow ENTRY op_follow enter $8, $0 movl %edx, sav_edx(%ebp) mv_force_defined %eax, l1 movl %eax, sav_eax(%ebp) mv_force_str %eax, l2 movl sav_edx(%ebp), %edx mv_force_defined %edx, l3 movl %edx, sav_edx(%ebp) mv_force_str %edx, l4 movl sav_eax(%ebp),%eax movl sav_edx(%ebp),%edx movl mval_l_strlen(%edx),%ecx pushl %ecx pushl mval_a_straddr(%edx) movl mval_l_strlen(%eax),%ecx pushl %ecx pushl mval_a_straddr(%eax) call memvcmp addl $16,%esp cmpl $0,%eax leave ret # op_follow ENDP # END fis-gtm-V6.0-003/sr_i386/op_forcenum.s0000644000032200000250000000276712201176147016254 0ustar librarygtc################################################################# # # # Copyright 2001, 2008 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_forcenum.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "mval_def.si" .sbttl op_forcenum # PAGE + .text .extern s2n # edx - source mval # eax - destination mval # PUBLIC op_forcenum ENTRY op_forcenum pushl %eax mv_force_defined %edx, l00 pushl %edx mv_force_num %edx, l10 popl %edx popl %eax testw $mval_m_str,mval_w_mvtype(%edx) je l20 testw $mval_m_num_approx,mval_w_mvtype(%edx) je l40 l20: testw $mval_m_int_without_nm,mval_w_mvtype(%edx) je l30 movw $mval_m_int,mval_w_mvtype(%eax) movl mval_l_m1(%edx),%edx movl %edx,mval_l_m1(%eax) ret l30: pushl %ebx movw $mval_m_nm,mval_w_mvtype(%eax) movb mval_b_exp(%edx),%bl movb %bl,mval_b_exp(%eax) # Copy the only numeric part of Mval from [edx] to [eax]. movl mval_l_m0(%edx),%ebx movl %ebx,mval_l_m0(%eax) movl mval_l_m1(%edx),%ebx movl %ebx,mval_l_m1(%eax) popl %ebx ret l40: # Copy the Mval from [edx] to [eax]. pushl %edi pushl %esi movl %eax,%edi movl %edx,%esi movl $mval_byte_len,%ecx REP movsb popl %esi popl %edi ret # op_forcenum ENDP # END fis-gtm-V6.0-003/sr_i386/op_forchk1.s0000644000032200000250000000114412201176147015757 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_forchk1.s .sbttl op_forchk1 # .386 # .MODEL FLAT, C .include "linkage.si" .text # PUBLIC op_forchk1 ENTRY op_forchk1 ret # op_forchk1 ENDP # END fis-gtm-V6.0-003/sr_i386/op_forinit.s0000644000032200000250000000236612201176147016103 0ustar librarygtc################################################################# # # # Copyright 2001, 2008 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_forinit.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .INCLUDE "mval_def.si" .sbttl op_forinit # PAGE + .DATA .extern frame_pointer .text .extern numcmp .extern s2n .extern underr # PUBLIC op_forinit ENTRY op_forinit movl frame_pointer,%edx popl msf_mpc_off(%edx) movl 4(%esp),%eax mv_force_defined %eax, l0 movl %eax, 4(%esp) mv_force_num %eax, t2 movl 4(%esp),%eax cmpl $0,mval_l_m1(%eax) js l2 mv_if_int %eax, l1 testb $mval_esign_mask,mval_b_exp(%eax) jne l2 l1: movl 8(%esp),%eax movl %eax,4(%esp) call numcmp addl $12,%esp movl frame_pointer,%edx pushl msf_mpc_off(%edx) cmpl $0,%eax ret l2: movl 8(%esp),%eax pushl %eax call numcmp addl $16,%esp movl frame_pointer,%edx pushl msf_mpc_off(%edx) cmpl $0,%eax ret # op_forinit ENDP # END fis-gtm-V6.0-003/sr_i386/op_forintrrpt.s0000644000032200000250000000160012201176147016630 0ustar librarygtc################################################################# # # # Copyright 2001, 2011 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_forintrrpt.s .sbttl op_forintrrpt # .386 # .MODEL FLAT, C .include "linkage.si" .DATA .extern neterr_pending .extern restart_pc .text .extern gvcmz_neterr .extern async_action .extern outofband_clear # PUBLIC op_forintrrpt ENTRY op_forintrrpt cmpb $0,neterr_pending je l1 call outofband_clear pushl $0 call gvcmz_neterr addl $4,%esp l1: pushl $0 call async_action addl $4,%esp ret # op_forintrrpt ENDP # END fis-gtm-V6.0-003/sr_i386/op_forlcldo.s0000644000032200000250000000226712201176147016235 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_forlcldo.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_forlcldo # PAGE + .DATA .extern frame_pointer .text .extern exfun_frame .sbttl op_forlcldob # PUBLIC op_forlcldob ENTRY op_forlcldob movl frame_pointer,%edx movl (%esp),%eax movl %eax,msf_mpc_off(%edx) addl $2,msf_mpc_off(%edx) # store pc in MUMPS stack frame doit: call exfun_frame movl frame_pointer,%edx movl msf_temps_ptr_off(%edx),%edi ret # op_forlcldob ENDP .sbttl op_forlcldow, op_forlcldol # PUBLIC op_forlcldow, op_forlcldol ENTRY op_forlcldol ENTRY op_forlcldow movl frame_pointer,%edx movl (%esp),%eax movl %eax,msf_mpc_off(%edx) addl $5,msf_mpc_off(%edx) # store pc in MUMPS stack frame jmp doit # op_forlcldol ENDP # END fis-gtm-V6.0-003/sr_i386/op_forloop.s0000644000032200000250000000707112201176147016107 0ustar librarygtc################################################################# # # # Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_forloop.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .INCLUDE "mval_def.si" .sbttl op_forloop # PAGE + # Called with the stack contents: # call return # ptr to index mval # ptr to step mval # ptr to terminator mval # loop address .DATA .extern frame_pointer # ten_dd DD 10 ten_dd: .long 10 .text .extern add_mvals .extern numcmp .extern s2n .extern underr term = 12 step = 8 indx = 4 # PUBLIC op_forloop ENTRY op_forloop movl frame_pointer,%edx popl msf_mpc_off(%edx) enter $0, $0 pushl %edi pushl %esi pushl %ebx movl indx(%ebp),%esi mv_force_defined_strict %esi, l0 # disregard NOUNDEF movl %esi, indx(%ebp) mv_force_num %esi, l1 movl indx(%ebp),%esi movl step(%ebp),%edi movw mval_w_mvtype(%esi),%ax movw mval_w_mvtype(%edi),%dx andw %dx,%ax testw $mval_m_int_without_nm,%ax je L66 movl mval_l_m1(%esi),%eax addl mval_l_m1(%edi),%eax cmpl $MANT_HI,%eax jge L68 cmpl $-MANT_HI,%eax jle L67 movw $mval_m_int,mval_w_mvtype(%esi) movl %eax,mval_l_m1(%esi) jmp L63 L67: movb $mval_esign_mask,mval_b_exp(%esi) # set sign bit negl %eax jmp L69 L68: movb $0,mval_b_exp(%esi) # clear sign bit L69: movw $mval_m_nm,mval_w_mvtype(%esi) orb $69,mval_b_exp(%esi) # set exponent field movl %eax,%ebx movl $0,%edx idivl ten_dd,%eax movl %eax,mval_l_m1(%esi) imull $10,%eax,%eax subl %eax,%ebx imull $MANT_LO,%ebx,%ebx movl %ebx,mval_l_m0(%esi) jmp L63 L66: pushl %esi pushl $0 pushl %edi pushl %esi call add_mvals addl $16,%esp movl indx(%ebp),%esi L63: movl step(%ebp),%edi testw $mval_m_int_without_nm,mval_w_mvtype(%edi) jne a cmpb $0,mval_b_exp(%edi) jl b jmp a2 a: cmpl $0,mval_l_m1(%edi) jl b a2: movl term(%ebp),%edi jmp e b: movl %esi,%edi # if step is negative, reverse compare movl term(%ebp),%esi e: # compare indx and term movw mval_w_mvtype(%esi),%ax movw mval_w_mvtype(%edi),%dx andw %dx,%ax testw $2,%ax je ccmp movl mval_l_m1(%esi),%eax subl mval_l_m1(%edi),%eax jmp tcmp ccmp: pushl %edi pushl %esi call numcmp addl $8,%esp cmpl $0,%eax tcmp: jle d movl indx(%ebp),%esi movl step(%ebp),%edi movw mval_w_mvtype(%esi),%ax movw mval_w_mvtype(%edi),%dx andw %dx,%ax testw $mval_m_int_without_nm,%ax je l66 movl mval_l_m1(%esi),%eax subl mval_l_m1(%edi),%eax cmpl $MANT_HI,%eax jge l68 cmpl $-MANT_HI,%eax jle l67 movw $mval_m_int,mval_w_mvtype(%esi) movl %eax,mval_l_m1(%esi) jmp l63 l67: movb $mval_esign_mask,mval_b_exp(%esi) # set sign bit negl %eax jmp l69 l68: movb $0,mval_b_exp(%esi) # clear sign bit l69: movw $mval_m_nm,mval_w_mvtype(%esi) orb $69,mval_b_exp(%esi) # set exponent field movl %eax,%ebx movl $0,%edx idivl ten_dd,%eax movl %eax,mval_l_m1(%esi) imull $10,%eax,%eax subl %eax,%ebx imull $MANT_LO,%ebx,%ebx movl %ebx,mval_l_m0(%esi) jmp l63 l66: pushl %esi pushl $1 pushl %edi pushl %esi call add_mvals addl $16,%esp l63: popl %ebx popl %esi popl %edi leave addl $16,%esp # remove op_forloop arguments movl frame_pointer,%edx pushl msf_mpc_off(%edx) ret d: popl %ebx popl %esi popl %edi leave addl $12,%esp # remove term, step, indx; leave loop addr ret # op_forloop ENDP # END fis-gtm-V6.0-003/sr_i386/op_gettruth.s0000644000032200000250000000162612201176147016275 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_gettruth.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "mval_def.si" .sbttl op_gettruth # PAGE + .DATA .extern dollar_truth .extern literal_one .extern literal_zero .text # PUBLIC op_gettruth ENTRY op_gettruth pushl %edi pushl %esi cmpl $0,dollar_truth jne l1 leal literal_zero,%esi jmp doit l1: leal literal_one,%esi doit: movl %edx,%edi movl $mval_byte_len,%ecx REP movsb popl %esi popl %edi ret # op_gettruth ENDP # END fis-gtm-V6.0-003/sr_i386/op_iretmvad.s0000644000032200000250000000154612201176147016243 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_iretmvad.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_iretmvad # PAGE + .DATA .extern frame_pointer .text .extern op_unwind # PUBLIC op_iretmvad ENTRY op_iretmvad movl %edx,%ecx # save input parameter from putframe macro putframe addl $4,%esp movl %ecx,%edx pushl %edx call op_unwind popl %eax # return input parameter getframe ret # op_iretmvad ENDP # END fis-gtm-V6.0-003/sr_i386/op_linefetch.s0000644000032200000250000000153312201176147016365 0ustar librarygtc################################################################# # # # Copyright 2001, 2009 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_linefetch.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_linefetch # PAGE + .DATA .extern frame_pointer .text .extern gtm_fetch # PUBLIC op_linefetch ENTRY op_linefetch movl frame_pointer,%eax popl msf_mpc_off(%eax) call gtm_fetch popl %eax leal (%esp,%eax,4),%esp movl frame_pointer,%eax pushl msf_mpc_off(%eax) ret # op_linefetch ENDP # END fis-gtm-V6.0-003/sr_i386/op_linestart.s0000644000032200000250000000136212201176147016431 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_linestart.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_linestart # PAGE + .DATA .extern frame_pointer .text # PUBLIC op_linestart ENTRY op_linestart movl frame_pointer,%edx movl (%esp),%eax movl %eax,msf_mpc_off(%edx) ret # op_linestart ENDP # END fis-gtm-V6.0-003/sr_i386/op_mprofcall.s0000644000032200000250000000211612201176147016401 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_mprofcall.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_mprofcallb # PAGE + .DATA .extern frame_pointer .text .extern copy_stack_frame_sp # PUBLIC op_mprofcallb ENTRY op_mprofcallb movl frame_pointer,%edx movl (%esp),%eax movl %eax,msf_mpc_off(%edx) addl $2,msf_mpc_off(%edx) call copy_stack_frame_sp ret # op_callb ENDP .sbttl op_mprofcallw, op_mprofcalll # PUBLIC op_mprofcallw, op_mprofcalll ENTRY op_mprofcalll ENTRY op_mprofcallw movl frame_pointer,%edx movl (%esp),%eax movl %eax,msf_mpc_off(%edx) addl $5,msf_mpc_off(%edx) call copy_stack_frame_sp ret # op_mprofcalll ENDP # END fis-gtm-V6.0-003/sr_i386/op_mprofcallsp.s0000644000032200000250000000253112201176147016745 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_mprofcallsp.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_mprofcallsp # PAGE + .DATA .extern dollar_truth .extern frame_pointer .text .extern exfun_frame_push_dummy_frame .extern push_tval .sbttl op_mprofcallspb # PUBLIC op_mprofcallspb ENTRY op_mprofcallspb movl frame_pointer,%edx movl (%esp),%eax movl %eax,msf_mpc_off(%edx) addl $2,msf_mpc_off(%edx) # store pc in MUMPS stack frame doit: call exfun_frame_push_dummy_frame pushl dollar_truth call push_tval addl $4,%esp movl frame_pointer,%edx movl msf_temps_ptr_off(%edx),%edi ret # op_mprofcallspb ENDP .sbttl op_mprofcallspw, op_mprofcallspl # PUBLIC op_mprofcallspw, op_mprofcallspl ENTRY op_mprofcallspw ENTRY op_mprofcallspl movl frame_pointer,%edx movl (%esp),%eax movl %eax,msf_mpc_off(%edx) addl $5,msf_mpc_off(%edx) # store pc in MUMPS stack frame jmp doit # op_mprofcallspw ENDP # END fis-gtm-V6.0-003/sr_i386/op_mprofexfun.s0000644000032200000250000000420612201176147016615 0ustar librarygtc################################################################# # # # Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_mprofexfun.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_mprofexfun # PAGE + # call op_mprofexfun with the following stack: # # return PC # ret_value address # mask # actualcnt # actual1 address # actual2 address # ... .DATA .extern ERR_GTMCHECK .extern dollar_truth .extern frame_pointer .text .extern exfun_frame_sp .extern push_parm .extern rts_error JMP_Jb = 0x0eb JMP_Jv = 0x0e9 actual1 = 20 act_cnt = 16 mask_arg = 12 ret_val = 8 rtn_pc = 4 sav_esi = -4 sav_ebx = -8 sav_msf = -12 # PUBLIC op_mprofexfun ENTRY op_mprofexfun pushl %ebp movl %esp,%ebp pushl %esi pushl %ebx leal sav_msf(%ebp),%esp # establish space for locals movl act_cnt(%ebp),%eax addl $3,%eax negl %eax leal (%esp,%eax,4),%esp # establish space for temps movl frame_pointer,%edx movl rtn_pc(%ebp),%eax cmpb $JMP_Jv,(%eax) je long cmpb $JMP_Jb,(%eax) je byte_off error: pushl ERR_GTMCHECK pushl $1 call rts_error addl $8,%esp jmp retlab byte_off: movl %eax,msf_mpc_off(%edx) addl $2,msf_mpc_off(%edx) jmp cont long: movl %eax,msf_mpc_off(%edx) addl $5,msf_mpc_off(%edx) cont: call exfun_frame_sp leal ret_val(%ebp),%esi movl %esp,%edi movl act_cnt(%ebp),%eax movl %eax,%ecx addl $3,%ecx REP movsl movl dollar_truth,%ecx andl $1,%ecx pushl %ecx # push $T addl $4,%eax pushl %eax # push total count call push_parm # push_parm ($T, ret_value, mask, argc [,arg1, arg2, ...]); done: movl frame_pointer,%edx movl msf_temps_ptr_off(%edx),%edi retlab: leal sav_ebx(%ebp),%esp movl rtn_pc(%ebp),%edx movl act_cnt(%ebp),%eax addl $4,%eax popl %ebx popl %esi popl %ebp leal (%esp,%eax,4),%esp pushl %edx ret # op_mprofexfun ENDP # END fis-gtm-V6.0-003/sr_i386/op_mprofextcall.s0000644000032200000250000000321312201176147017121 0ustar librarygtc################################################################# # # # Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_mprofextcall.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_mprofextcall # PAGE + .DATA .extern ERR_GTMCHECK .extern ERR_LABELUNKNOWN .extern frame_pointer .text .extern auto_zlink .extern new_stack_frame_sp .extern rts_error # PUBLIC op_mprofextcall ENTRY op_mprofextcall putframe addl $4,%esp # burn return pc popl %edx # routine hdr addr popl %eax # label addr cmpl $0,%eax je l2 l1: movl (%eax),%eax # get the line number offset cmpl $0,%eax je l4 addl mrt_curr_ptr(%edx),%eax addl %edx,%eax # get the line number pointer movl (%eax),%eax # get the line number addl mrt_curr_ptr(%edx),%eax addl %edx,%eax pushl %eax pushl $0 pushl %edx call new_stack_frame_sp addl $12,%esp getframe ret l2: cmpl $0,%edx jne l4 subl $4,%esp pushl %esp movl frame_pointer,%eax pushl msf_mpc_off(%eax) call auto_zlink addl $8,%esp cmpl $0,%eax je l3 movl %eax,%edx popl %eax cmpl $0,%eax jne l1 l3: addl $4,%esp pushl ERR_GTMCHECK pushl $1 call rts_error pushl $1 # in original m68020 code ?? addl $8,%esp getframe ret l4: pushl ERR_LABELUNKNOWN pushl $1 call rts_error addl $8,%esp getframe ret # op_mprofextcall ENDP # END fis-gtm-V6.0-003/sr_i386/op_mprofextexfun.s0000644000032200000250000000551412201176147017341 0ustar librarygtc################################################################# # # # Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_mprofextexfun.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_mprofextexfun # PAGE + # call op_mprofextexfun with the following stack: # # return PC # routine # label # ret_value address # mask # actualcnt # actual1 address # actual2 address # ... .DATA .extern ERR_FMLLSTMISSING .extern ERR_GTMCHECK .extern ERR_LABELUNKNOWN .extern dollar_truth .extern frame_pointer .text .extern auto_zlink .extern new_stack_frame_sp .extern push_parm .extern rts_error actual1 = 24 act_cnt = 20 mask_arg = 16 ret_val = 12 label_arg = 8 routine = 4 sav_ebx = -4 sav_msf = -8 # PUBLIC op_mprofextexfun ENTRY op_mprofextexfun putframe addl $4,%esp # burn return PC pushl %ebp movl %esp,%ebp pushl %ebx leal sav_msf(%ebp),%esp # establish space for locals movl act_cnt(%ebp),%eax addl $3,%eax negl %eax leal (%esp,%eax,4),%esp # add space for temps movl routine(%ebp),%edx movl label_arg(%ebp),%eax cmpl $0,%eax je l3 l1: pushl %eax # save labaddr movl (%eax),%eax # get offset to line number entry cmpl $0,%eax je l5 addl mrt_curr_ptr(%edx),%eax addl %edx,%eax # get the pointer to line number entry movl (%eax),%ebx # get line number addl mrt_curr_ptr(%edx),%ebx addl %edx,%ebx popl %eax # restore labaddr cmpl $0,4(%eax) # labaddr += 4, to point to has_parms; then *has_parms je l6 # if has_parms == 0, then issue an error pushl %ebx pushl $0 pushl %edx call new_stack_frame_sp addl $12,%esp leal ret_val(%ebp),%esi movl %esp,%edi movl act_cnt(%ebp),%eax movl %eax,%ecx addl $3,%ecx # include: A(ret_value), mask, argc REP movsl movl dollar_truth,%ecx andl $1,%ecx pushl %ecx addl $4,%eax # include: $T(just pushed) plus other 3 pushl %eax # push total count call push_parm # push_parm ($T, ret_value, mask, argc [,arg1, arg2, ...]); retlab: leal sav_ebx(%ebp),%esp movl act_cnt(%ebp),%eax addl $5,%eax popl %ebx popl %ebp leal (%esp,%eax,4),%esp getframe ret l3: cmpl $0,%edx jne l5 subl $4,%esp movl %esp,%eax pushl %eax movl frame_pointer,%edx pushl msf_mpc_off(%edx) call auto_zlink addl $8,%esp cmpl $0,%eax je l4 movl %eax,%edx popl %eax cmpl $0,%eax jne l1 l4: pushl ERR_GTMCHECK pushl $1 call rts_error jmp retlab l5: pushl ERR_LABELUNKNOWN pushl $1 call rts_error jmp retlab l6: pushl ERR_FMLLSTMISSING pushl $1 call rts_error jmp retlab # op_mprofextexfun ENDP # END fis-gtm-V6.0-003/sr_i386/op_mprofforchk1.s0000644000032200000250000000147412201176147017031 0ustar librarygtc################################################################# # # # Copyright 2011 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# .title op_mprofforchk1.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_mprofforchk1 # Called with the stack contents: # call return .DATA .text .extern forchkhandler # PUBLIC op_mprofforchk1 ENTRY op_mprofforchk1 pushl 0(%esp) # throw the current return address on as an arg call forchkhandler addl $4, %esp ret # op_mprofforchk1 ENDP # END fis-gtm-V6.0-003/sr_i386/op_mprofforlcldo.s0000644000032200000250000000240512201176147017273 0ustar librarygtc################################################################# # # # Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_mprofforlcldo.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_mprofforlcldo # PAGE + .DATA .extern frame_pointer .text .extern exfun_frame_sp .sbttl op_mprofforlcldob # PUBLIC op_mprofforlcldob ENTRY op_mprofforlcldob movl frame_pointer,%edx movl (%esp),%eax movl %eax,msf_mpc_off(%edx) addl $2,msf_mpc_off(%edx) # store pc in MUMPS stack frame doit: call exfun_frame_sp movl frame_pointer,%edx movl msf_temps_ptr_off(%edx),%edi ret # op_mprofforlcldob ENDP .sbttl op_mprofforlcldow, op_mprofforlcldol # PUBLIC op_mprofforlcldow, op_mprofforlcldol ENTRY op_mprofforlcldol ENTRY op_mprofforlcldow movl frame_pointer,%edx movl (%esp),%eax movl %eax,msf_mpc_off(%edx) addl $5,msf_mpc_off(%edx) # store pc in MUMPS stack frame jmp doit # op_mprofforlcldol ENDP # END fis-gtm-V6.0-003/sr_i386/op_mproflinefetch.s0000644000032200000250000000177712201176147017443 0ustar librarygtc################################################################# # # # Copyright 2001, 2011 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_mproflinefetch.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_mproflinefetch # PAGE + .DATA .extern frame_pointer .text .extern gtm_fetch .extern stack_leak_check .extern pcurrpos # PUBLIC op_mproflinefetch ENTRY op_mproflinefetch movl frame_pointer,%eax popl msf_mpc_off(%eax) call gtm_fetch call pcurrpos popl %eax # popping generated code args off stack before leak check leal (%esp,%eax,4),%esp call stack_leak_check movl frame_pointer,%eax pushl msf_mpc_off(%eax) ret # op_mproflinefetch ENDP # END fis-gtm-V6.0-003/sr_i386/op_mproflinestart.s0000644000032200000250000000146312201176147017477 0ustar librarygtc################################################################# # # # Copyright 2001, 2011 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_mproflinestart.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_mproflinestart # PAGE + .DATA .extern frame_pointer .text .extern pcurrpos # PUBLIC op_mproflinestart ENTRY op_mproflinestart movl frame_pointer,%edx movl (%esp),%eax movl %eax,msf_mpc_off(%edx) call pcurrpos ret # op_mproflinestart ENDP # END fis-gtm-V6.0-003/sr_i386/op_neg.s0000644000032200000250000000247712201176147015205 0ustar librarygtc################################################################# # # # Copyright 2001, 2008 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_neg.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "mval_def.si" .sbttl op_neg # PAGE + .text # # op_neg ( mval *u, mval *v ) : u = -v # # edx - source mval = &v # eax - destination mval = &u .extern s2n .extern underr # PUBLIC op_neg ENTRY op_neg pushl %eax mv_force_defined %edx, isdefined popl %eax mv_if_number %edx, numer pushl %eax pushl %edx call s2n popl %edx popl %eax numer: mv_if_notint %edx, float movw $mval_m_int,mval_w_mvtype(%eax) movl mval_l_m1(%edx),%edx negl %edx movl %edx,mval_l_m1(%eax) ret float: pushl %ebx # need a temp register movw $mval_m_nm,mval_w_mvtype(%eax) movb mval_b_exp(%edx),%bl xorb $mval_esign_mask,%bl # flip the sign bit movb %bl,mval_b_exp(%eax) movl mval_l_m0(%edx),%ebx movl %ebx,mval_l_m0(%eax) movl mval_l_m1(%edx),%ebx movl %ebx,mval_l_m1(%eax) popl %ebx ret # op_neg ENDP #END fis-gtm-V6.0-003/sr_i386/op_numcmp.s0000644000032200000250000000161712201176147015726 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_numcmp.s .sbttl op_numcmp # .386 # .MODEL FLAT, C .include "linkage.si" # op_numcmp calls numcmp to compare two mvals # # entry: # eax mval *u # edx mval *v # # exit: # condition codes set according to value of # numcmp (u, v) .text .extern numcmp # PUBLIC op_numcmp ENTRY op_numcmp pushl %edx pushl %eax call numcmp addl $8,%esp # restore stack cmpl $0,%eax # set flags according to result from numcmp ret # op_numcmp ENDP # END fis-gtm-V6.0-003/sr_i386/op_pattern.s0000644000032200000250000000242712201176147016104 0ustar librarygtc################################################################# # # # Copyright 2001, 2002 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_pattern.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "mval_def.si" .sbttl op_pattern # PAGE + .text .extern do_patfixed .extern do_pattern # PUBLIC op_pattern ENTRY op_pattern pushl %edx pushl %eax movl mval_a_straddr(%edx),%eax # # This is an array of unaligned ints. If the first word is zero, then call do_pattern # instead of do_patfixed. Only the low order byte is significant and so it is the only # one we need to test. We would do this in assembly because (1) we need the assmembly # routine anyway to save the return value into $TEST and (2) it saves an extra level of # call linkage at the C level to do the decision here. # cmpb $0,(%eax) # little endian compare of low order byte je l1 call do_patfixed jmp l2 l1: call do_pattern l2: addl $8,%esp cmpl $0,%eax ret # op_pattern ENDP # END fis-gtm-V6.0-003/sr_i386/op_restartpc.s0000644000032200000250000000151512201176147016433 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_restartpc.s .sbttl op_restartpc # .386 # .MODEL FLAT, C .include "linkage.si" .include "g_msf.si" .DATA .extern restart_pc .extern restart_ctxt .extern frame_pointer .text # PUBLIC op_restartpc ENTRY op_restartpc movl (%esp),%eax subl $6,%eax movl %eax,restart_pc movl frame_pointer,%eax movl msf_ctxt_off(%eax),%edx movl %edx,restart_ctxt ret # op_restartpc ENDP # END fis-gtm-V6.0-003/sr_i386/op_retarg.s0000644000032200000250000000145012201176147015706 0ustar librarygtc################################################################# # # # Copyright 2001, 2010 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_retarg.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_retarg # PAGE + .DATA .extern frame_pointer .text .extern unw_retarg # PUBLIC op_retarg ENTRY op_retarg movl %edx,(%esp) # Reuse return point on stack (not needed) pushl %eax call unw_retarg addl $8,%esp getframe ret # op_retarg ENDP # END fis-gtm-V6.0-003/sr_i386/op_sorts_after.s0000644000032200000250000000226712201176147016764 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_sorts_after.s .sbttl op_sorts_after # .386 # .MODEL FLAT, C .include "linkage.si" # op_sorts_after.s 80386 # # op_sorts_after(mval *mval1, *mval2) # Call sorts_after() to determine whether mval1 comes after mval2 # in sorting order. Use alternate local collation sequence if # present. # # entry: # eax mval *mval1 # edx mval *mval2 # # Sets condition flags and returns in eax: ## 1 mval1 > mval2 ## 0 mval1 = mval2 ## -1 mval1 < mval2 # .text .extern sorts_after # PUBLIC op_sorts_after ENTRY op_sorts_after pushl %edx pushl %eax call sorts_after addl $8,%esp # restore stack cmpl $0,%eax # set flags according to result from ret # sorts_after. # op_sorts_after ENDP # END fis-gtm-V6.0-003/sr_i386/op_startintrrpt.s0000644000032200000250000000177212201176147017211 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_startintrrpt.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl op_startintrrpt # PAGE + .DATA .extern frame_pointer .extern neterr_pending .text .extern gvcmz_neterr .extern async_action .extern outofband_clear # PUBLIC op_startintrrpt ENTRY op_startintrrpt putframe cmpb $0,neterr_pending je l1 call outofband_clear pushl $0 call gvcmz_neterr addl $4,%esp l1: pushl $1 call async_action addl $8,%esp # 4 bytes to burn return pc, 4 more to remove arg to async_action getframe ret # op_startintrrpt ENDP # END fis-gtm-V6.0-003/sr_i386/op_sto.s0000644000032200000250000000202512201176147015226 0ustar librarygtc################################################################# # # # Copyright 2001, 2009 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_sto.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "mval_def.si" .sbttl op_sto # PAGE + .DATA .extern literal_null .extern undef_inhibit .text .extern underr # PUBLIC op_sto ENTRY op_sto mv_if_notdefined %edx, b a: pushl %edi pushl %esi movl $mval_byte_len,%ecx movl %edx,%esi movl %eax,%edi REP movsb andw $~mval_m_aliascont, mval_w_mvtype(%eax) # Don't propagate alias container flag popl %esi popl %edi ret b: cmpb $0,undef_inhibit je clab leal literal_null,%edx jmp a clab: pushl %edx call underr addl $4,%esp ret # op_sto ENDP # END fis-gtm-V6.0-003/sr_i386/op_zhelp.s0000644000032200000250000000135112201176147015544 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title op_zhelp.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" # PAGE + .DATA .extern frame_pointer .text .extern op_zhelp_xfr # PUBLIC op_zhelp ENTRY op_zhelp movl frame_pointer,%edx popl msf_mpc_off(%edx) call op_zhelp_xfr getframe ret # op_zhelp ENDP # END fis-gtm-V6.0-003/sr_i386/opp_break.s0000644000032200000250000000133612201176147015671 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_break.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_break # PAGE + .DATA .extern frame_pointer .text .extern op_break # PUBLIC opp_break ENTRY opp_break putframe addl $4,%esp call op_break getframe ret # opp_break ENDP # END fis-gtm-V6.0-003/sr_i386/opp_commarg.s0000644000032200000250000000137212201176147016232 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_commarg.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_commarg # PAGE + .DATA .extern frame_pointer .text .extern op_commarg # PUBLIC opp_commarg ENTRY opp_commarg putframe addl $4,%esp call op_commarg addl $8,%esp getframe ret # opp_commarg ENDP # END fis-gtm-V6.0-003/sr_i386/opp_dmode.s0000644000032200000250000000133612201176147015675 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_dmode.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_dmode # PAGE + .DATA .extern frame_pointer .text .extern op_dmode # PUBLIC opp_dmode ENTRY opp_dmode putframe addl $4,%esp call op_dmode getframe ret # opp_dmode ENDP # END fis-gtm-V6.0-003/sr_i386/opp_hardret.s0000644000032200000250000000136312201176147016236 0ustar librarygtc################################################################# # # # Copyright 2001, 2007 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_hardret.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_hardret # PAGE + .DATA .extern frame_pointer .text .extern op_hardret # PUBLIC opp_hardret ENTRY opp_hardret putframe addl $4,%esp call op_hardret getframe ret # opp_hardret ENDP # END fis-gtm-V6.0-003/sr_i386/opp_inddevparms.s0000644000032200000250000000146612201176147017125 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_inddevparms.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_inddevparms # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_inddevparms # PUBLIC opp_inddevparms ENTRY opp_inddevparms # /* PROC */ putframe addl $4,%esp call op_inddevparms addl $12,%esp getframe ret # opp_inddevparms ENDP # END fis-gtm-V6.0-003/sr_i386/opp_indfnname.s0000644000032200000250000000141112201176147016536 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_indfnname.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_indfnname # PAGE + .DATA .extern frame_pointer .text .extern op_indfnname # PUBLIC opp_indfnname ENTRY opp_indfnname putframe addl $4,%esp call op_indfnname addl $12,%esp getframe ret # opp_indfnname ENDP # END fis-gtm-V6.0-003/sr_i386/opp_indfun.s0000644000032200000250000000142312201176147016065 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_indfun.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_indfun # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_indfun # PUBLIC opp_indfun ENTRY opp_indfun # /* PROC */ putframe addl $4,%esp call op_indfun addl $12,%esp getframe ret # opp_indfun ENDP # END fis-gtm-V6.0-003/sr_i386/opp_indglvn.s0000644000032200000250000000143112201176147016242 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_indglvn.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_indglvn # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_indglvn # PUBLIC opp_indglvn ENTRY opp_indglvn # /* PROC */ putframe addl $4,%esp call op_indglvn addl $8,%esp getframe ret # opp_indglvn ENDP # END fis-gtm-V6.0-003/sr_i386/opp_indincr.s0000644000032200000250000000143212201176147016230 0ustar librarygtc################################################################# # # # Copyright 2004 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_indincr.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_indincr # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_indincr # PUBLIC opp_indincr ENTRY opp_indincr # /* PROC */ putframe addl $4,%esp call op_indincr addl $12,%esp getframe ret # opp_indincr ENDP # END fis-gtm-V6.0-003/sr_i386/opp_indlvadr.s0000644000032200000250000000144012201176147016404 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_indlvadr.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_indlvadr # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_indlvadr # PUBLIC opp_indlvadr ENTRY opp_indlvadr # /* PROC */ putframe addl $4,%esp call op_indlvadr addl $4,%esp getframe ret # opp_indlvadr ENDP # END fis-gtm-V6.0-003/sr_i386/opp_indlvarg.s0000644000032200000250000000144012201176147016407 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_indlvarg.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_indlvarg # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_indlvarg # PUBLIC opp_indlvarg ENTRY opp_indlvarg # /* PROC */ putframe addl $4,%esp call op_indlvarg addl $8,%esp getframe ret # opp_indlvarg ENDP # END fis-gtm-V6.0-003/sr_i386/opp_indlvnamadr.s0000644000032200000250000000146412201176147017106 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_indlvnamadr.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_indlvnamadr # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_indlvnamadr # PUBLIC opp_indlvnamadr ENTRY opp_indlvnamadr # /* PROC */ putframe addl $4,%esp call op_indlvnamadr addl $4,%esp getframe ret # opp_indlvnamadr ENDP # END fis-gtm-V6.0-003/sr_i386/opp_indmerge.s0000644000032200000250000000144012201176147016373 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_indmerge.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_indmerge # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_indmerge # PUBLIC opp_indmerge ENTRY opp_indmerge # /* PROC */ putframe addl $4,%esp call op_indmerge addl $8,%esp getframe ret # opp_indmerge ENDP # END fis-gtm-V6.0-003/sr_i386/opp_indpat.s0000644000032200000250000000142212201176147016060 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_indpat.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_indpat # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_indpat # PUBLIC opp_indpat ENTRY opp_indpat # /* PROC */ putframe addl $4,%esp call op_indpat addl $8,%esp getframe ret # opp_indpat ENDP # END fis-gtm-V6.0-003/sr_i386/opp_indrzshow.s0000644000032200000250000000144712201176147016637 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_indrzshow.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_indrzshow # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_indrzshow # PUBLIC opp_indrzshow ENTRY opp_indrzshow # /* PROC */ putframe addl $4,%esp call op_indrzshow addl $8,%esp getframe ret # opp_indrzshow ENDP # END fis-gtm-V6.0-003/sr_i386/opp_indsavglvn.s0000644000032200000250000000155212201176147016760 0ustar librarygtc################################################################# # # # Copyright 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_indsavglvn.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_indsavglvn # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_indsavglvn # PUBLIC opp_indsavglvn ENTRY opp_indsavglvn # /* PROC */ putframe addl $4,%esp # /* burn return pc */ call op_indsavglvn addl $12,%esp # /* burn three passed-in args */ getframe ret # opp_indsavglvn ENDP # END fis-gtm-V6.0-003/sr_i386/opp_indsavlvn.s0000644000032200000250000000154112201176147016607 0ustar librarygtc################################################################# # # # Copyright 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_indsavlvn.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_indsavlvn # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_indsavlvn # PUBLIC opp_indsavlvn ENTRY opp_indsavlvn # /* PROC */ putframe addl $4,%esp # /* burn return pc */ call op_indsavlvn addl $8,%esp # /* burn two passed-in args */ getframe ret # opp_indsavlvn ENDP # END fis-gtm-V6.0-003/sr_i386/opp_indset.s0000644000032200000250000000142212201176147016067 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_indset.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_indset # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_indset # PUBLIC opp_indset ENTRY opp_indset # /* PROC */ putframe addl $4,%esp call op_indset addl $8,%esp getframe ret # opp_indset ENDP # END fis-gtm-V6.0-003/sr_i386/opp_indtext.s0000644000032200000250000000151312201176147016261 0ustar librarygtc################################################################# # # # Copyright 2001, 2002 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_indtext.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_indtext # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_indtext # PUBLIC opp_indtext ENTRY opp_indtext # /* PROC */ putframe addl $4,%esp # burn return PC call op_indtext addl $16,%esp # remove args from stack getframe ret # opp_indtext ENDP # END fis-gtm-V6.0-003/sr_i386/opp_iretmval.s0000644000032200000250000000153612201176147016432 0ustar librarygtc################################################################# # # # Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_iretmval.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_iretmval # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_iretmval # PUBLIC opp_iretmval ENTRY opp_iretmval # /* PROC */ putframe addl $4,%esp # /* burn return pc */ call op_iretmval addl $8,%esp # /* burn two passed-in args */ getframe ret # opp_iretmval ENDP # END fis-gtm-V6.0-003/sr_i386/opp_newintrinsic.s0000644000032200000250000000147212201176147017322 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_newintrinsic.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_newintrinsic # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_newintrinsic # PUBLIC opp_newintrinsic ENTRY opp_newintrinsic # /* PROC */ putframe addl $4,%esp call op_newintrinsic addl $4,%esp getframe ret # opp_newintrinsic ENDP # END fis-gtm-V6.0-003/sr_i386/opp_newvar.s0000644000032200000250000000142012201176147016101 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_newvar.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_newvar # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_newvar # PUBLIC opp_newvar ENTRY opp_newvar # /* PROC */ putframe addl $4,%esp call op_newvar addl $4,%esp getframe ret # opp_newvar ENDP # END fis-gtm-V6.0-003/sr_i386/opp_ret.s0000644000032200000250000000135112201176147015374 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_ret.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_ret # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_unwind # PUBLIC opp_ret ENTRY opp_ret # /* PROC */ addl $4,%esp call op_unwind getframe ret # opp_ret ENDP #END fis-gtm-V6.0-003/sr_i386/opp_rterror.s0000644000032200000250000000151112201176147016277 0ustar librarygtc################################################################# # # # Copyright 2001, 2002 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_rterror.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_rterror # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_rterror # PUBLIC opp_rterror ENTRY opp_rterror # /* PROC */ putframe addl $4,%esp # burn return PC call op_rterror addl $8,%esp # remove args from stack getframe ret # opp_rterror ENDP # END fis-gtm-V6.0-003/sr_i386/opp_svput.s0000644000032200000250000000147312201176147015770 0ustar librarygtc################################################################# # # # Copyright 2001, 2002 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_svput.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_svput # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_svput # PUBLIC opp_svput ENTRY opp_svput # /* PROC */ putframe addl $4,%esp # burn return PC call op_svput addl $8,%esp # remove args from stack getframe ret # opp_svput ENDP # END fis-gtm-V6.0-003/sr_i386/opp_tcommit.s0000644000032200000250000000142112201176147016254 0ustar librarygtc################################################################# # # # Copyright 2001, 2007 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_tcommit.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_tcommit # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_tcommit # PUBLIC opp_tcommit ENTRY opp_tcommit # /* PROC */ putframe addl $4,%esp call op_tcommit getframe ret # opp_tcommit ENDP # END fis-gtm-V6.0-003/sr_i386/opp_trestart.s0000644000032200000250000000144512201176147016456 0ustar librarygtc################################################################# # # # Copyright 2001, 2007 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_trestart.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_trestart # PAGE + .DATA .extern frame_pointer # /*:DWORD */ .text .extern op_trestart # PUBLIC opp_trestart ENTRY opp_trestart # /* PROC */ putframe addl $4,%esp call op_trestart addl $4,%esp getframe ret # opp_trestart ENDP # END fis-gtm-V6.0-003/sr_i386/opp_trollback.s0000644000032200000250000000145312201176147016562 0ustar librarygtc################################################################# # # # Copyright 2001, 2003 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_trollback.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_trollback # PAGE + .DATA .extern frame_pointer # /*:DWORD */ .text .extern op_trollback # PUBLIC opp_trollback ENTRY opp_trollback # /* PROC */ putframe addl $4,%esp call op_trollback addl $4,%esp getframe ret # opp_trollback ENDP # END fis-gtm-V6.0-003/sr_i386/opp_tstart.s0000644000032200000250000000215112201176147016122 0ustar librarygtc################################################################# # # # Copyright 2001, 2010 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_tstart.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_tstart # PAGE + .DATA .extern frame_pointer # /* :DWORD */ .text .extern op_tstart # PUBLIC opp_tstart ENTRY opp_tstart # /* PROC */ putframe movl $0,%eax # put arg0 over return call address since movl %eax,(%esp) # .. we dont need it: NOT an implicit tstart call op_tstart movl 12(%esp),%eax # get number of variables to preserve cmpl $0,%eax # -1 = not restartable, jge l1 # -2 = preserve all variables movl $0,%eax l1: addl $4,%eax # total args to op_tstart == preservecnt + 4 leal (%esp,%eax,4),%esp getframe ret # opp_tstart ENDP # END fis-gtm-V6.0-003/sr_i386/opp_xnew.s0000644000032200000250000000137312201176147015567 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_xnew.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_xnew # PAGE + .DATA .extern frame_pointer .text .extern op_xnew # PUBLIC opp_xnew ENTRY opp_xnew putframe addl $4,%esp call op_xnew popl %eax leal (%esp,%eax,4),%esp getframe ret # opp_xnew ENDP # END fis-gtm-V6.0-003/sr_i386/opp_zcont.s0000644000032200000250000000134512201176147015742 0ustar librarygtc################################################################# # # # Copyright 2001, 2007 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_zcont.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_zcont # PAGE + .DATA .extern frame_pointer .text .extern op_zcont # PUBLIC opp_zcont ENTRY opp_zcont putframe addl $4,%esp call op_zcont getframe ret # opp_zcont ENDP # END fis-gtm-V6.0-003/sr_i386/opp_zg1.s0000644000032200000250000000141112201176147015300 0ustar librarygtc################################################################# # # # Copyright 2010 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_zg1.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_zg1 # PAGE + .DATA .extern frame_pointer .text .extern op_zg1 # PUBLIC opp_zg1 ENTRY opp_zg1 putframe addl $4,%esp # burn return pc call op_zg1 addl $4,%esp # burn passed-in arg getframe ret # opp_zg1 ENDP # END fis-gtm-V6.0-003/sr_i386/opp_zgoto.s0000644000032200000250000000144012201176147015743 0ustar librarygtc################################################################# # # # Copyright 2010, 2011 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title opp_zgoto.s # .386 # .MODEL FLAT, C .include "linkage.si" .INCLUDE "g_msf.si" .sbttl opp_zgoto # PAGE + .DATA .extern frame_pointer .text .extern op_zgoto # PUBLIC opp_zgoto ENTRY opp_zgoto putframe addl $4,%esp # burn return pc call op_zgoto addl $16,%esp # burn passed in 4 args getframe ret # opp_zgoto ENDP # END fis-gtm-V6.0-003/sr_i386/pseudo_ret.s0000644000032200000250000000117612201176147016102 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # PAGE ,132 .title pseudo_ret.s .sbttl pseudo_ret # .386 # .MODEL FLAT, C .include "linkage.si" .text .extern opp_ret # PUBLIC pseudo_ret ENTRY pseudo_ret call opp_ret # pseudo_ret ENDP # END fis-gtm-V6.0-003/sr_i386/ttt.c0000666000032200000250000013506712201176214014532 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "vxi.h" #include "vxt.h" #include "xfer_enum.h" LITDEF short ttt[4229] = { /* 0 */ 0,0,0,0,324,3399,2842,548, /* 8 */ 2220,2827,2857,1910,402,3349,2022,2973, /* 16 */ 2099,2090,3582,3619,2063,2072,2138,2084, /* 24 */ 2129,2108,2045,748,775,763,802,814, /* 32 */ 826,844,886,904,922,943,972,1002, /* 40 */ 1017,1032,1047,1065,1077,2943,2958,1149, /* 48 */ 1182,1215,1254,1317,1368,1644,1659,1674, /* 56 */ 1704,1743,1755,1779,1806,1827,1842,3414, /* 64 */ 3436,0,0,0,0,563,0,504, /* 72 */ 0,1896,0,2929,0,0,0,0, /* 80 */ 0,0,356,414,2198,2204,2619,2646, /* 88 */ 2664,2767,2705,2696,2782,3488,3572,2878, /* 96 */ 0,2908,3039,3002,2987,3017,3363,3215, /* 104 */ 3281,3494,3506,3521,3545,3554,3539,3530, /* 112 */ 3314,3615,3628,3650,3687,3699,3720,3744, /* 120 */ 3810,0,0,2815,2180,3091,4178,636, /* 128 */ 4181,690,2676,3057,518,524,4184,2283, /* 136 */ 2370,2270,471,2306,2390,2054,2328,2400, /* 144 */ 4187,2165,2156,4191,1386,1404,4192,352, /* 152 */ 348,3305,426,4196,4199,4202,2894,4205, /* 160 */ 4208,4211,4214,4217,4220,3385,0,2791, /* 168 */ 2459,2437,1623,2428,2216,2036,2742,1931, /* 176 */ 715,2732,0,0,2235,3563,3591,1599, /* 184 */ 3515,2318,1924,533,3711,1791,2147,1302, /* 192 */ 339,3043,602,668,586,646,3675,1197, /* 200 */ 1236,3643,2871,2174,2806,2885,618,1089, /* 208 */ 2746,4223,2380,3762,3780,3795,495,2761, /* 216 */ 3035,1869,3831,3822,1440,3377,577,1689, /* 224 */ 1731,2343,4226,3448,2416,724,862,3074, /* 232 */ 3603,3472,3458,3465,3454,700,957,2293, /* 240 */ 1131,2257,1119,2117,1104,1164,2355,1569, /* 248 */ 1512,1497,1551,1467,1479,1524,1452,1536, /* 256 */ 1584,0,3335,0,981,990,3194,3260, /* 264 */ 1818,3173,3239,2244,3867,3837,3843,3855, /* 272 */ 3877,1341,1353,1275,1287,1329,3426,1719, /* 280 */ 1854,3891,3906,3942,3969,3924,3101,3113, /* 288 */ 3125,3137,2655,2670,1611,435,790,1422, /* 296 */ 627,3149,3161,3954,3960,0,0,0, /* 304 */ 0,3666,3981,3992,4004,4013,4027,4040, /* 312 */ 4050,4067,4076,4085,4097,4109,4121,4136, /* 320 */ 4148,0,0,4157,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB, /* 328 */ VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3, /* 336 */ VXT_XFER,SIZEOF(char *) * (short int)xf_add,VXT_END, /* 339 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_bindparm, /* 347 */ VXT_END, /* 348 */ VXI_INCL,VXT_VAL,1,VXT_END, /* 352 */ VXI_CLRL,VXT_VAL,0,VXT_END, /* 356 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_break,VXT_END, /* 360 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callb,VXI_BRB,VXT_JMP,1,VXT_END, /* 367 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_calll,VXI_JMP,VXT_JMP,1,VXT_END, /* 374 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callw,VXI_BRW,VXT_JMP,1,VXT_END, /* 381 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspb,VXI_BRB,VXT_JMP,1,VXT_END, /* 388 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspl,VXI_JMP,VXT_JMP,1,VXT_END, /* 395 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspw,VXI_BRW,VXT_JMP,1,VXT_END, /* 402 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, /* 410 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_cat,VXT_END, /* 414 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 422 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_close,VXT_END, /* 426 */ VXI_BICB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_false, /* 434 */ VXT_END, /* 435 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_clralsvars, /* 443 */ VXT_END, /* 444 */ VXI_TSTL,VXT_VAL,1,VXT_END, /* 448 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2bool, /* 456 */ VXT_END, /* 457 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2mint, /* 465 */ VXI_MOVL,VXT_REG,0x50,VXT_VAL,0,VXT_END, /* 471 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, /* 479 */ SIZEOF(char *) * (short int)xf_commarg,VXT_END, /* 481 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVL,VXT_VAL,1, /* 489 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mint2mval,VXT_END, /* 495 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2num, /* 503 */ VXT_END, /* 504 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, /* 512 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_contain,VXT_END, /* 518 */ VXI_MOVL,VXT_REG,0x6C,VXT_ADDR,0,VXT_END, /* 524 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_currtn, /* 532 */ VXT_END, /* 533 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, /* 541 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_cvtparm,VXT_END, /* 548 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 556 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_div,VXT_END, /* 563 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1, /* 571 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equ,VXT_END, /* 577 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equnul, /* 585 */ VXT_END, /* 586 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, /* 594 */ 2,VXI_PUSHL,VXT_LIT,0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END, /* 602 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, /* 610 */ 2,VXI_PUSHAB,VXT_VAL,0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END, /* 618 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunret, /* 626 */ VXT_END, /* 627 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunretals, /* 635 */ VXT_END, /* 636 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, /* 644 */ SIZEOF(char *) * (short int)xf_extcall,VXT_END, /* 646 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, /* 654 */ 3,VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, /* 662 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END, /* 668 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, /* 676 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, /* 684 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END, /* 690 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, /* 698 */ SIZEOF(char *) * (short int)xf_extjmp,VXT_END, /* 700 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 708 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_exp,VXT_END, /* 715 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fetch, /* 723 */ VXT_END, /* 724 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL, /* 732 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL, /* 740 */ VXT_LIT,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END, /* 748 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, /* 756 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnascii,VXT_END, /* 763 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, /* 771 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnchar,VXT_END, /* 775 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, /* 783 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzascii,VXT_END, /* 790 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 798 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzahandle,VXT_END, /* 802 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, /* 810 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzchar,VXT_END, /* 814 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 822 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fndata,VXT_END, /* 826 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, /* 834 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER, /* 842 */ SIZEOF(char *) * (short int)xf_fnextract,VXT_END, /* 844 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, /* 852 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER, /* 860 */ SIZEOF(char *) * (short int)xf_fnzextract,VXT_END, /* 862 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL, /* 870 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, /* 878 */ VXT_VAL,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END, /* 886 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, /* 894 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, /* 902 */ SIZEOF(char *) * (short int)xf_fnfind,VXT_END, /* 904 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, /* 912 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, /* 920 */ SIZEOF(char *) * (short int)xf_fnzfind,VXT_END, /* 922 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, /* 930 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, /* 938 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfnumber,VXT_END, /* 943 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0, /* 951 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget,VXT_END, /* 957 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 965 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget2,VXT_END, /* 972 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget, /* 980 */ VXT_END, /* 981 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget1, /* 989 */ VXT_END, /* 990 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 998 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget1,VXT_END, /* 1002 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 1010 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnincr,VXT_END, /* 1017 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 1025 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnj2,VXT_END, /* 1032 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 1040 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzj2,VXT_END, /* 1047 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, /* 1055 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, /* 1063 */ SIZEOF(char *) * (short int)xf_fnj3,VXT_END, /* 1065 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 1073 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlength,VXT_END, /* 1077 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 1085 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlength,VXT_END, /* 1089 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 1097 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvname,VXT_END, /* 1104 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL, /* 1112 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvnameo2,VXT_END, /* 1119 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 1127 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvprvname,VXT_END, /* 1131 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL, /* 1139 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,2,VXT_XFER, /* 1147 */ SIZEOF(char *) * (short int)xf_fnname,VXT_END, /* 1149 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 1157 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnnext,VXT_END, /* 1164 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL, /* 1172 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, /* 1180 */ SIZEOF(char *) * (short int)xf_fno2,VXT_END, /* 1182 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 1190 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnorder,VXT_END, /* 1197 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, /* 1205 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, /* 1213 */ SIZEOF(char *) * (short int)xf_fnp1,VXT_END, /* 1215 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, /* 1223 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, /* 1231 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpiece,VXT_END, /* 1236 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, /* 1244 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, /* 1252 */ SIZEOF(char *) * (short int)xf_fnzp1,VXT_END, /* 1254 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, /* 1262 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, /* 1270 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpiece,VXT_END, /* 1275 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 1283 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqlength,VXT_END, /* 1287 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 1295 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqsubscript,VXT_END, /* 1302 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 1310 */ 0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnquery,VXT_END, /* 1317 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 1325 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnrandom,VXT_END, /* 1329 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 1337 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnreverse,VXT_END, /* 1341 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 1349 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack1,VXT_END, /* 1353 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, /* 1361 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack2,VXT_END, /* 1368 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, /* 1376 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, /* 1384 */ SIZEOF(char *) * (short int)xf_fntext,VXT_END, /* 1386 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, /* 1394 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, /* 1402 */ SIZEOF(char *) * (short int)xf_fntranslate,VXT_END, /* 1404 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, /* 1412 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, /* 1420 */ SIZEOF(char *) * (short int)xf_fnztranslate,VXT_END, /* 1422 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, /* 1430 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, /* 1438 */ SIZEOF(char *) * (short int)xf_fnztrigger,VXT_END, /* 1440 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, /* 1448 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnview,VXT_END, /* 1452 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, /* 1460 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitand,VXT_END, /* 1467 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, /* 1475 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitcoun,VXT_END, /* 1479 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 1487 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER, /* 1495 */ SIZEOF(char *) * (short int)xf_fnzbitfind,VXT_END, /* 1497 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, /* 1505 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitget,VXT_END, /* 1512 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, /* 1520 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitlen,VXT_END, /* 1524 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, /* 1532 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitnot,VXT_END, /* 1536 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, /* 1544 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitor,VXT_END, /* 1551 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 1559 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER, /* 1567 */ SIZEOF(char *) * (short int)xf_fnzbitset,VXT_END, /* 1569 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, /* 1577 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitstr,VXT_END, /* 1584 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, /* 1592 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitxor,VXT_END, /* 1599 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL, /* 1607 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzcall,VXT_END, /* 1611 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 1619 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdata,VXT_END, /* 1623 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL, /* 1631 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, /* 1639 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdate,VXT_END, /* 1644 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 1652 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzfile,VXT_END, /* 1659 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 1667 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetdvi,VXT_END, /* 1674 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, /* 1682 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetjpi,VXT_END, /* 1689 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL, /* 1697 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetlki,VXT_END, /* 1704 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 1712 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetsyi,VXT_END, /* 1719 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 1727 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzjobexam,VXT_END, /* 1731 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 1739 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlkid,VXT_END, /* 1743 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 1751 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzm,VXT_END, /* 1755 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL, /* 1763 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, /* 1771 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzparse,VXT_END, /* 1779 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 1787 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpid,VXT_END, /* 1791 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 1799 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzprevious,VXT_END, /* 1806 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 1814 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpriv,VXT_END, /* 1818 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzqgblmod, /* 1826 */ VXT_END, /* 1827 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 1835 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsearch,VXT_END, /* 1842 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 1850 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsetprv,VXT_END, /* 1854 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL, /* 1862 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsigproc,VXT_END, /* 1869 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,6,VXI_PUSHAB,VXT_VAL, /* 1877 */ 5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB, /* 1885 */ VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,7, /* 1893 */ VXT_XFER,SIZEOF(char *) * (short int)xf_fnztrnlnm,VXT_END, /* 1896 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, /* 1904 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_follow,VXT_END, /* 1910 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1, /* 1918 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forcenum,VXT_END, /* 1924 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forchk1,VXT_END, /* 1931 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 1939 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forinit,VXT_END, /* 1944 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldob,VXI_BRB,VXT_JMP,1,VXT_END, /* 1951 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldol,VXI_JMP,VXT_JMP,1,VXT_END, /* 1958 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldow,VXI_BRW,VXT_JMP,1,VXT_END, /* 1965 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL, /* 1973 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB, /* 1981 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END, /* 1984 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL, /* 1992 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB, /* 2000 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END, /* 2003 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL, /* 2011 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB, /* 2019 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END, /* 2022 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_getindx, /* 2030 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, /* 2036 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_gettruth, /* 2044 */ VXT_END, /* 2045 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvdata, /* 2053 */ VXT_END, /* 2054 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvextnam, /* 2062 */ VXT_END, /* 2063 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvget, /* 2071 */ VXT_END, /* 2072 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, /* 2080 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvincr,VXT_END, /* 2084 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvkill,VXT_END, /* 2090 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnaked, /* 2098 */ VXT_END, /* 2099 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvname, /* 2107 */ VXT_END, /* 2108 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnext, /* 2116 */ VXT_END, /* 2117 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, /* 2125 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvo2,VXT_END, /* 2129 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvorder, /* 2137 */ VXT_END, /* 2138 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvput, /* 2146 */ VXT_END, /* 2147 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvquery, /* 2155 */ VXT_END, /* 2156 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvrectarg, /* 2164 */ VXT_END, /* 2165 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvsavtarg, /* 2173 */ VXT_END, /* 2174 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvzwithdraw,VXT_END, /* 2180 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, /* 2188 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER, /* 2196 */ SIZEOF(char *) * (short int)xf_gvzwrite,VXT_END, /* 2198 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_halt,VXT_END, /* 2204 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 2212 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_hang,VXT_END, /* 2216 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_hardret,VXT_END, /* 2220 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 2228 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_idiv,VXT_END, /* 2235 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_igetsrc, /* 2243 */ VXT_END, /* 2244 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 2252 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_inddevparms,VXT_END, /* 2257 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, /* 2265 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname,VXT_END, /* 2270 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 2278 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfun,VXT_END, /* 2283 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, /* 2291 */ SIZEOF(char *) * (short int)xf_indglvn,VXT_END, /* 2293 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 2301 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indincr,VXT_END, /* 2306 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvadr,VXI_MOVL,VXT_REG, /* 2314 */ 0x50,VXT_ADDR,0,VXT_END, /* 2318 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, /* 2326 */ SIZEOF(char *) * (short int)xf_indlvarg,VXT_END, /* 2328 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, /* 2336 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indname,VXT_END, /* 2343 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvnamadr,VXI_MOVL,VXT_REG, /* 2351 */ 0x50,VXT_ADDR,0,VXT_END, /* 2355 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, /* 2363 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indo2,VXT_END, /* 2370 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, /* 2378 */ SIZEOF(char *) * (short int)xf_indpat,VXT_END, /* 2380 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, /* 2388 */ SIZEOF(char *) * (short int)xf_indrzshow,VXT_END, /* 2390 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, /* 2398 */ SIZEOF(char *) * (short int)xf_indset,VXT_END, /* 2400 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, /* 2408 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indtext,VXT_END, /* 2416 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL, /* 2424 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_iocontrol,VXT_END, /* 2428 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_iretmvad, /* 2436 */ VXT_END, /* 2437 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, /* 2445 */ SIZEOF(char *) * (short int)xf_iretmval,VXT_END, /* 2447 */ VXI_BRB,VXT_JMP,1,VXT_END, /* 2451 */ VXI_JMP,VXT_JMP,1,VXT_END, /* 2455 */ VXI_BRW,VXT_JMP,1,VXT_END, /* 2459 */ VXI_JMP,VXT_VAL,1,VXT_END, /* 2463 */ VXI_BEQL,VXT_JMP,1,VXT_END, /* 2467 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, /* 2474 */ VXI_BNEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, /* 2481 */ VXI_BGEQ,VXT_JMP,1,VXT_END, /* 2485 */ VXI_BLSS,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, /* 2492 */ VXI_BLSS,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, /* 2499 */ VXI_BGTR,VXT_JMP,1,VXT_END, /* 2503 */ VXI_BLEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, /* 2510 */ VXI_BLEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, /* 2517 */ VXI_BLEQ,VXT_JMP,1,VXT_END, /* 2521 */ VXI_BGTR,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, /* 2528 */ VXI_BGTR,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, /* 2535 */ VXI_BLSS,VXT_JMP,1,VXT_END, /* 2539 */ VXI_BGEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, /* 2546 */ VXI_BGEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, /* 2553 */ VXI_BNEQ,VXT_JMP,1,VXT_END, /* 2557 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END, /* 2564 */ VXI_BEQL,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END, /* 2571 */ VXI_BLBC,VXT_REG,0x5A,VXT_JMP,1,VXT_END, /* 2577 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1, /* 2585 */ VXT_END, /* 2586 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1, /* 2594 */ VXT_END, /* 2595 */ VXI_BLBS,VXT_REG,0x5A,VXT_JMP,1,VXT_END, /* 2601 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1, /* 2609 */ VXT_END, /* 2610 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1, /* 2618 */ VXT_END, /* 2619 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,7,VXI_PUSHL,VXT_VAL, /* 2627 */ 6,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL, /* 2635 */ VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1, /* 2643 */ VXT_XFER,SIZEOF(char *) * (short int)xf_job,VXT_END, /* 2646 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_kill, /* 2654 */ VXT_END, /* 2655 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_killalias, /* 2663 */ VXT_END, /* 2664 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killall,VXT_END, /* 2670 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killaliasall,VXT_END, /* 2676 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, /* 2684 */ 3,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_labaddr,VXI_MOVL,VXT_REG, /* 2692 */ 0x50,VXT_ADDR,0,VXT_END, /* 2696 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckdecr, /* 2704 */ VXT_END, /* 2705 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckincr, /* 2713 */ VXT_END, /* 2714 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END, /* 2720 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END, /* 2726 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END, /* 2732 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, /* 2740 */ SIZEOF(char *) * (short int)xf_linefetch,VXT_END, /* 2742 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_linestart,VXT_END, /* 2746 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, /* 2754 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END, /* 2761 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_lkinit,VXT_END, /* 2767 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, /* 2775 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END, /* 2782 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lock, /* 2790 */ VXT_END, /* 2791 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, /* 2799 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvpatwrite,VXT_END, /* 2806 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwithdraw, /* 2814 */ VXT_END, /* 2815 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL, /* 2823 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwrite,VXT_END, /* 2827 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 2835 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_flt_mod,VXT_END, /* 2842 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 2850 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_mul,VXT_END, /* 2857 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1, /* 2865 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_neg,VXT_END, /* 2871 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newintrinsic,VXT_END, /* 2878 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newvar,VXT_END, /* 2885 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_nullexp, /* 2893 */ VXT_END, /* 2894 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, /* 2902 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_numcmp,VXT_END, /* 2908 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, /* 2916 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, /* 2924 */ VXT_LIT,4,VXT_XFER,SIZEOF(char *) * (short int)xf_open,VXT_END, /* 2929 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, /* 2937 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_pattern,VXT_END, /* 2943 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 2951 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpopulation,VXT_END, /* 2958 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 2966 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpopulation,VXT_END, /* 2973 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_putindx, /* 2981 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, /* 2987 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, /* 2995 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_rdone,VXT_END, /* 3002 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, /* 3010 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_read,VXT_END, /* 3017 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL, /* 3025 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,3,VXT_XFER, /* 3033 */ SIZEOF(char *) * (short int)xf_readfl,VXT_END, /* 3035 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_END, /* 3039 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_ret,VXT_END, /* 3043 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVL,VXT_VAL,2, /* 3051 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_retarg,VXT_END, /* 3057 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 3065 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0, /* 3073 */ VXT_END, /* 3074 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 3082 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0, /* 3090 */ VXT_END, /* 3091 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, /* 3099 */ SIZEOF(char *) * (short int)xf_rterror,VXT_END, /* 3101 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, /* 3109 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setals2als,VXT_END, /* 3113 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, /* 3121 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsin2alsct,VXT_END, /* 3125 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, /* 3133 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsctin2als,VXT_END, /* 3137 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, /* 3145 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsct2alsct,VXT_END, /* 3149 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, /* 3157 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2als,VXT_END, /* 3161 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT, /* 3169 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2alsct,VXT_END, /* 3173 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, /* 3181 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, /* 3189 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setextract,VXT_END, /* 3194 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, /* 3202 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, /* 3210 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setp1,VXT_END, /* 3215 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, /* 3223 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, /* 3231 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setpiece,VXT_END, /* 3239 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, /* 3247 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, /* 3255 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzextract,VXT_END, /* 3260 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, /* 3268 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, /* 3276 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzp1,VXT_END, /* 3281 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL, /* 3289 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, /* 3297 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setzpiece,VXT_END, /* 3305 */ VXI_BISB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_true, /* 3313 */ VXT_END, /* 3314 */ VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, /* 3322 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,3,VXI_CALLS, /* 3330 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzbrk,VXT_END, /* 3335 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2, /* 3343 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sorts_after,VXT_END, /* 3349 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_srchindx, /* 3357 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, /* 3363 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1, /* 3371 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END, /* 3377 */ VXI_MOVC3,VXT_LIT,16,VXT_VAL,2,VXT_VAL,1,VXT_END, /* 3385 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0, /* 3393 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END, /* 3399 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 3407 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_sub,VXT_END, /* 3414 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 3422 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svget,VXT_END, /* 3426 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, /* 3434 */ SIZEOF(char *) * (short int)xf_psvput,VXT_END, /* 3436 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 3444 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svput,VXT_END, /* 3448 */ VXI_MOVL,VXT_REG,0x50,VXT_REG,0x5A,VXT_END, /* 3454 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tcommit,VXT_END, /* 3458 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trollback,VXT_END, /* 3465 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trestart,VXT_END, /* 3472 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, /* 3480 */ 2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tstart,VXT_END, /* 3488 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_unlock,VXT_END, /* 3494 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 3502 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_use,VXT_END, /* 3506 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_view, /* 3514 */ VXT_END, /* 3515 */ VXI_CMPL,VXT_VAL,1,VXT_VAL,2,VXT_END, /* 3521 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_write, /* 3529 */ VXT_END, /* 3530 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wteol, /* 3538 */ VXT_END, /* 3539 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_wtff,VXT_END, /* 3545 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wtone, /* 3553 */ VXT_END, /* 3554 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wttab, /* 3562 */ VXT_END, /* 3563 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_xkill, /* 3571 */ VXT_END, /* 3572 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER, /* 3580 */ SIZEOF(char *) * (short int)xf_xnew,VXT_END, /* 3582 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zallocate, /* 3590 */ VXT_END, /* 3591 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 3599 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zattach,VXT_END, /* 3603 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 3611 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zcompile,VXT_END, /* 3615 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END, /* 3619 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zdeallocate, /* 3627 */ VXT_END, /* 3628 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 3636 */ 1,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_zedit,VXT_END, /* 3643 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zg1,VXT_END, /* 3650 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHL,VXT_VAL,4,VXI_PUSHAB,VXT_VAL, /* 3658 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zgoto,VXT_END, /* 3666 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zhalt, /* 3674 */ VXT_END, /* 3675 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 3683 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zhelp,VXT_END, /* 3687 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 3695 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zlink,VXT_END, /* 3699 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL, /* 3707 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zmess,VXT_END, /* 3711 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zprevious, /* 3719 */ VXT_END, /* 3720 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL, /* 3728 */ 4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB, /* 3736 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_zprint,VXT_END, /* 3744 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL, /* 3752 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER, /* 3760 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END, /* 3762 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL, /* 3770 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER, /* 3778 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END, /* 3780 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 3788 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END, /* 3795 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 3803 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END, /* 3810 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 3818 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zsystem,VXT_END, /* 3822 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_ztcommit, /* 3830 */ VXT_END, /* 3831 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztstart,VXT_END, /* 3837 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_merge,VXT_END, /* 3843 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 3851 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END, /* 3855 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 3863 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END, /* 3867 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER, /* 3875 */ SIZEOF(char *) * (short int)xf_indmerge,VXT_END, /* 3877 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_m_srchindx, /* 3885 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, /* 3891 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 3899 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzconvert2,VXT_END, /* 3906 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL, /* 3914 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, /* 3922 */ SIZEOF(char *) * (short int)xf_fnzconvert3,VXT_END, /* 3924 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL, /* 3932 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER, /* 3940 */ SIZEOF(char *) * (short int)xf_fnzsubstr,VXT_END, /* 3942 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 3950 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwidth,VXT_END, /* 3954 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztrigger,VXT_END, /* 3960 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zwritesvn, /* 3968 */ VXT_END, /* 3969 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 3977 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwrite,VXT_END, /* 3981 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_igetdst,VXI_MOVL,VXT_REG,0x50, /* 3989 */ VXT_ADDR,0,VXT_END, /* 3992 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 4000 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_indget1,VXT_END, /* 4004 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_glvnpop, /* 4012 */ VXT_END, /* 4013 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_glvnslot, /* 4021 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END, /* 4027 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL, /* 4035 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indsavglvn,VXT_END, /* 4040 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER, /* 4048 */ SIZEOF(char *) * (short int)xf_indsavlvn,VXT_END, /* 4050 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 4058 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshlvn,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0, /* 4066 */ VXT_END, /* 4067 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savgvn, /* 4075 */ VXT_END, /* 4076 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savlvn, /* 4084 */ VXT_END, /* 4085 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 4093 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_shareslot,VXT_END, /* 4097 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 4105 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_stoglvn,VXT_END, /* 4109 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT, /* 4117 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshgvn,VXT_END, /* 4121 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL, /* 4129 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname2,VXT_END, /* 4136 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT, /* 4144 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_indget2,VXT_END, /* 4148 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_indmerge2, /* 4156 */ VXT_END, /* 4157 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL, /* 4165 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS, /* 4173 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpeek,VXT_END, /* 4178 */ 360,374,367,2447,2455,2451,2714,2726, /* 4186 */ 2720,0,0,0,481,457,448,0, /* 4194 */ 0,444,1965,2003,1984,2595,2610,2601, /* 4202 */ 2571,2586,2577,2463,2474,2467,2553,2564, /* 4210 */ 2557,2499,2510,2503,2517,2528,2521,2535, /* 4218 */ 2546,2539,2481,2492,2485,1944,1958,1951, /* 4226 */ 381,395,388}; fis-gtm-V6.0-003/sr_i386/zbreaksp.h0000644000032200000250000000242712201176147015537 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ typedef unsigned char zb_code; #define ZB_CODE_MASK 0xff #define INST_TYPE zb_code /* The ZBreak command operates by finding the generated code for the op_linestart or op_linefetch for the source * line in question and changing the offset in the transfer table load address instruction from the op_linestart or * op_linefetch offset to the appropriate zbreak functionality opcode offset. * In some platforms(IA64 and ZOS) since the INSTRUCTION LAYOUT is complex we need following * macros for instruction manipulation. * EXTRACT_OFFSET_TO_M_OPCODE * FIX_OFFSET_WITH_ZBREAK_OFFSET * EXTRACT_AND_UPDATE_INST * These macros are called only when COMPLEX_INSTRUCTION_UPDATE is defined * If COMPLEX_INSTRUCTION_UPDATE is not defined portable code in the caller of these macros * is invoked. */ #undef COMPLEX_INSTRUCTION_UPDATE fis-gtm-V6.0-003/sr_linux/0000755000032200000250000000000012201176146014205 5ustar librarygtcfis-gtm-V6.0-003/sr_linux/arch.gtc0000644000032200000250000000071512201176146015624 0ustar librarygtc################################################################# # # # Copyright 2001 Sanchez Computer Associates, Inc. # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# arch="linux" export arch fis-gtm-V6.0-003/sr_linux/caller_id.c0000644000032200000250000000620712201176146016274 0ustar librarygtc/**************************************************************** * * * Copyright 2008, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* caller_id routine called from CRIT_TRACE macro to * return the return address of our caller allowing CRIT_TRACE * (used in various semaphore routines) to determine who was * calling those semaphore routines and for what purpose and * when. This is a system dependent type of operation and is * generally implemented in assembly language. * Presently 32bit linux system has its own implementation in * assembly. Similar implementation will not work on x86_64 * since register rbp is also used as M Frame pointer in its * assembly files. * This particular implementation will work only on Linux x86_64 system * due to its dependency on "backtrace" function call which is not * available on all Unix flovours. */ #include "mdef.h" #include #include #include "gtm_stdlib.h" #include "gt_timer.h" #include "caller_id.h" #define MAX_TRACE_DEPTH 3 /*We need the callers caller of caller_id */ #define RETURN_ADDRESS_DEPTH 2 GBLREF boolean_t blocksig_initialized; GBLREF sigset_t block_sigsent; GBLREF int process_exiting; GBLREF volatile boolean_t timer_in_handler; static boolean_t caller_id_reent = FALSE; /* If ever true, our helper gets a lobotomy */ caddr_t caller_id(void) { void *trace[MAX_TRACE_DEPTH]; int trace_size; sigset_t savemask; /* We cannot let this routine nest itself due to the impolite things that * occur when the exception routines get re-entered so just play dead. */ if (caller_id_reent) return (caddr_t)-1; /* Return 0 if we are already in timer or generic signal signal handler to prevent deadlocks * due to nested mallocs/frees resulting from interrupting in external function calls. */ if (timer_in_handler || process_exiting) return (caddr_t)0; /* When backtrace is processing and a signal occurs, there is the potential for a deadlock -- waiting on a * lock that this process already holds. A work around is to temporarily block signals (SIGINT, SIGQUIT, * SIGTERM, SIGTSTP, SIGCONT, SIGALRM) and then restore them after the backtrace call returns. */ /* It is possible for this routine to be invoked during process startup (as part of err_init()) so * block_sigsent could not be initialized yet. Therefore this does not have an assert(blocksig_initialized) * that similar code in other places (e.g. dollarh.c) has. */ if (blocksig_initialized) sigprocmask(SIG_BLOCK, &block_sigsent, &savemask); caller_id_reent = TRUE; trace_size = backtrace(trace, MAX_TRACE_DEPTH); caller_id_reent = FALSE; if (blocksig_initialized) sigprocmask(SIG_SETMASK, &savemask, NULL); /* backtrace will return call stack with address.*/ if (trace_size >= RETURN_ADDRESS_DEPTH) return (caddr_t)trace[RETURN_ADDRESS_DEPTH]; else return NULL; } fis-gtm-V6.0-003/sr_linux/genexport.csh0000644000032200000250000000220712201176146016720 0ustar librarygtc################################################################# # # # Copyright 2001, 2010 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# ############################################################################################ # # genexport.csh - to generate the linker script *.export to export # all call-in related symbols from libgtmshr.so # Argument # $1 - The pathname of a .exp file that list out all symbols to be exposed # $2 - output verstion script file to be specified with ld --version-script. # # Example output: # { # global: # gtm_ci; # gtm_exit; # gtm_zstatus; # local: # *; # }; ############################################################################################ echo "{" >$2 echo "global:" >>$2 sed 's/\(.*\)/ \1;/g' $1 >>$2 echo "local:" >>$2 echo " *;" >>$2 echo "};" >>$2 fis-gtm-V6.0-003/sr_linux/gtm_env_sp.csh0000644000032200000250000002763212201176146017057 0ustar librarygtc################################################################# # # # Copyright 2001, 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # ########################################################################################## # # gtm_env_sp.csh - environment variable values and aliases specific to Linux # ########################################################################################## # # Once the environment variables have been initialized, be careful not to # re-initialize them for each subshell (i.e., don't undo any explicit changes that # have been made since the last version change). set platform_name = `uname | sed 's/-//g' | tr '[A-Z]' '[a-z]'` set mach_type = `uname -m` ### Sanitize platform_name and match_type # Cygwin adds the Windows version e.g. uname = CYGWIN_NT-5.1 set platform_only = `echo $platform_name | sed 's/_.*//'` # sanitize i386 thru i686 to one option, do not use this to set build optimizations! if ( "linux" == $platform_name ) then set mach_type = `uname -m | sed 's/i[3456]86/ia32/' ` endif # default to 64bit builds when object mode is not set if (!($?OBJECT_MODE)) then setenv OBJECT_MODE 64 endif ### 64bit vs 32bit builds # The only 32 bit targets are cygwin, ia32 and x86_64 with specific settings if ( ( "ia32" == $mach_type ) || ( "cywgin" == $platform_only ) ) then setenv gt_build_type 32 # build 32 bit on x86_64 when $gtm_inc/x86_64.h does not exist with comlist.csh OR when OBJECT_MODE is set to 32 with comlist.mk else if ( "x86_64" == $mach_type && ((! -e $gtm_inc/x86_64.h && "inc" == "${gtm_inc:t}") || "32" == $OBJECT_MODE)) then setenv gt_build_type 32 else setenv gt_build_type 64 setenv gt_ld_m_shl_options "-shared" endif if ( $?gtm_version_change == "1" ) then # Compiler selections: # if !( $?gtm_linux_compiler ) then setenv gtm_linux_compiler gcc endif if ( "ia64" == $mach_type ) then if ( "gcc" != $gtm_linux_compiler ) then if (-r /usr/bin/icc) then setenv gt_cc_compiler "icc -i-static" # name of C compiler endif endif endif # Archiver definitions: # GNU ar q equals r, S prevents generating the symbol table but # requires ranlib before linking setenv gt_ar_option_create "qSv" # quick, verbose setenv gt_ar_option_update "rv" # replace, verbose setenv gt_ar_option_delete "dv" # delete, verbose setenv gt_ar_use_ranlib "yes" # Assembler definitions: # From before conversion from MASM or get MASM running under DOSEMU or such # setenv gt_as_use_prebuilt "yes" # GNU as if ( "ia64" == $mach_type ) then if ( "icc" == $gtm_linux_compiler ) then setenv gt_cpp_compiler "icc" # name of C preprocessor setenv gt_cpp_options_common "-x assembler-with-cpp" setenv gt_as_assembler "icc" setenv gt_as_options_common "-c -i-static" setenv gt_as_option_optimize "$gt_as_option_optimize -O3" else setenv gt_as_assembler "gcc -c" endif endif if ( "ia64" != $mach_type ) then setenv gt_as_assembler "as" if ("s390x" == $mach_type) then setenv gt_as_options_common "-march=z9-109" setenv gt_as_option_debug "--gdwarf-2" else if ( "cygwin" == $platform_only ) then setenv gt_as_options_common "--defsym cygwin=1" setenv gt_as_option_debug "--gdwarf-2" else setenv gt_as_option_debug "--gstabs" endif endif # to avoid naming files with .S # smw 1999/12/04 setenv gt_as_options_common "-c -x assembler-with-cpp" setenv gt_as_option_DDEBUG "" # C definitions: # generate position independent code setenv gt_cc_shl_fpic "-fPIC" if ( "cygwin" == $platform_only ) then setenv gt_cc_shl_fpic "" endif # setenv gt_cc_options_common "-c -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64" # For gcc: _BSD_SOURCE for caddr_t, others # _XOPEN_SOURCE=500 should probably define POSIX 199309 and/or # POSIX 199506 but doesnt so... # -fsigned-char for Linux390 but shouldn't hurt x86 # setenv gt_cc_options_common "-c -ansi -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -D_POSIX_C_SOURCE=199506L # setenv gt_cc_options_common "$gt_cc_options_common -D_FILE_OFFSET_BITS=64 -DFULLBLOCKWRITES -fsigned-char" # _GNU_SOURCE includes _XOPEN_SOURCE=400, _BSD_SOURCE, and _POSIX_C_SOURCE-199506L among others # Need _XOPEN_SOURCE=600 for posix_memalign() interface (replaces obsolete memalign) if ( "cygwin" == $platform_only ) then # on Cygwin, -ansi defines __STRICT_ANSI__ which suppresses many prototypes setenv gt_cc_options_common "-c " else setenv gt_cc_options_common "-c -ansi " endif setenv gt_cc_options_common "$gt_cc_options_common -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 " setenv gt_cc_options_common "$gt_cc_options_common -D_XOPEN_SOURCE=600 -fsigned-char " if ( "ia64" != $mach_type ) then set tmpgtmval = `echo $gt_cc_compiler | grep icc` if ($status) then setenv gt_cc_options_common "$gt_cc_options_common $gt_cc_shl_fpic" else setenv gt_cc_options_common "$gt_cc_options_common $gt_cc_shl_fpic -Wimplicit" endif setenv gt_cc_options_common "$gt_cc_options_common -Wmissing-prototypes -D_LARGEFILE64_SOURCE" endif if ( "cygwin" == $platform_only ) then setenv gt_cc_options_common "$gt_cc_options_common -DNO_SEM_TIME -DNO_SEM_GETPID" endif # 32 bit ICU headers of 32 bit linux are in /emul/ia32-linux/usr/include/ if ( "32" == $gt_build_type ) then if (-d /emul/ia32-linux/usr/include/) setenv gt_cc_option_I "-I/emul/ia32-linux/usr/include/" endif if ( "linux" == $platform_name ) then set lversion=`uname -r` set ltemp_ver=`echo $lversion | sed 's/./& /g'` if ($ltemp_ver[3] == "2" && $ltemp_ver[1] == "2") then setenv gt_cc_options_common "$gt_cc_options_common -DNeedInAddrPort" endif if ( "x86_64" == $mach_type ) then # see if the compiler supports unused-result warnings # Note: Compilers that dont support --help=warnings will not output unused-result. # Currently, only compilers that support --help=warnings need to have unused-result # turned off. Trying to turn it off on compilers that dont support it causes errors. cc --help=warnings | & grep unused-result >/dev/null if (! $status ) then # if it does, turn them off setenv gt_cc_options_common "$gt_cc_options_common -Wno-unused-result" endif endif endif # -fno-defer-pop to prevent problems with assembly/generated code with optimization # -fno-strict-aliasing since we don't comply with the rules # -ffloat-store for consistent results avoiding rounding differences # -fno-omit-frame-pointer so %rbp always gets set up (required by caller_id()). Default changed in gcc 4.6. if ( "ia64" != $mach_type ) then setenv gt_cc_option_optimize "-O2 -fno-defer-pop -fno-strict-aliasing -ffloat-store" if ( "32" == $gt_build_type ) then # applies to 32bit x86_64, ia32 and cygwin setenv gt_cc_option_optimize "$gt_cc_option_optimize -fno-omit-frame-pointer -march=i686" endif endif # -g generate debugging information for dbx (no longer overrides -O) setenv gt_cc_option_debug "-g" if ( "cygwin" == $platform_only ) then setenv gt_cc_option_debug "$gt_cc_option_debug -gdwarf-2 -fno-inline -fno-inline-functions" endif # Linker definitions: setenv gt_ld_linker "$gt_cc_compiler" # redefine to use new C compiler definition # -M generate link map onto standard output setenv gt_ld_options_common "-Wl,-M" setenv gt_ld_options_gtmshr "-Wl,-u,gtm_filename_to_id -Wl,--version-script,gtmshr_symbols.export" setenv gt_ld_options_all_exe "-rdynamic -Wl,-u,gtm_filename_to_id -Wl,-u,gtm_zstatus" setenv gt_ld_options_all_exe "$gt_ld_options_all_exe -Wl,--version-script,gtmexe_symbols.export" # optimize for all 64bit platforms # # -lrt doesn't work to pull in semaphores with GCC 4.6, so use -lpthread. # Add -lc in front of -lpthread to avoid linking in thread-safe versions # of libc routines from libpthread. setenv gt_ld_syslibs " -lelf -lncurses -lm -ldl -lc -lpthread -lrt" if ( 32 == $gt_build_type ) then # 32bit x86_64 and ia32 - decided at the beginning of the file setenv gt_ld_syslibs " -lncurses -lm -ldl -lc -lpthread -lrt" endif if ( "cygwin" == $platform_only ) then setenv gt_ld_syslibs "-lncurses -lm -lcrypt" endif # -lrt for async I/O in mupip recover/rollback setenv gt_ld_aio_syslib "-lrt" if ( "cygwin" == $platform_only ) then setenv gt_ld_aio_syslib "" endif # Shared library definition overrides: setenv gt_cc_shl_options "-c $gt_cc_shl_fpic" setenv gt_ld_shl_linker "cc" setenv gt_ld_shl_options "-shared" # If we are trying to force a 32 bit build on a 64 bit x86 machine, then we need to explicitly specify a 32 bit # over-ride option. if ( "x86_64" == $mach_type && "32" == $gt_build_type ) then setenv gt_cc_options_common "$gt_cc_options_common -m32" setenv gt_ld_options_gtmshr "$gt_ld_options_gtmshr -m32" setenv gt_cc_shl_options "$gt_cc_shl_options -m32" setenv gt_ld_shl_options "$gt_ld_shl_options -m32" setenv gt_ld_options_common "$gt_ld_options_common -m32" endif # need to re-define these in terms of new gt_ld_options_common: setenv gt_ld_options_bta "$gt_ld_options_common" setenv gt_ld_options_dbg "$gt_ld_options_common" setenv gt_ld_options_pro "$gt_ld_options_common" setenv gt_ld_shl_suffix ".so" # lint definition overrides # setenv gt_lint_linter "" setenv gt_lint_options_library "-x" setenv gt_lint_options_common "" endif # PBO(Profile based optimization) settings for Linux-IA64, intel compiler. set gtm_build_image = `basename $gtm_exe` if ( "ia64" == $mach_type && "pro" == $gtm_build_image && "icc" == $gtm_linux_compiler) then setenv gt_cc_option_optimize "-O3" if ($?gtm_pbo_option) then @ need_mkdir = 0 if !($?gtm_pbo_db) then @ need_mkdir = 1 setenv gtm_pbo_db "$gtm_log/pbo" else if !(-e $gtm_pbo_db) then @ need_mkdir = 1 endif if (1 == $need_mkdir) then mkdir -p $gtm_pbo_db chmod 775 $gtm_pbo_db # Others need ability to write to the pbo files endif if ($gtm_pbo_option == "collect") then setenv gt_cc_option_optimize "-prof-gen -prof-dir $gtm_pbo_db" setenv gt_ld_options_pro "$gt_ld_options_pro -prof-gen -prof-dir $gtm_pbo_db" setenv gt_as_option_optimize "$gt_cc_option_optimize" else if ($gtm_pbo_option == "use") then setenv gt_cc_option_optimize "-O3 -prof-use -prof-dir $gtm_pbo_db" setenv gt_ld_options_pro "$gt_ld_options_pro -prof-dir $gtm_pbo_db" endif endif endif # Assembler definitions: # Note: we need to specify the assembler output file name or it will write it to the source directory. if ( "ia64" == $mach_type ) then alias gt_as_bta 'gt_as $gt_as_option_debug $gt_as_option_nooptimize' alias gt_as_dbg 'gt_as $gt_as_option_DDEBUG $gt_as_option_debug $gt_as_option_nooptimize' alias gt_as_pro 'gt_as $gt_as_option_optimize ' endif if ( "s390x" == $mach_type) then setenv gt_asm_arch_size "-m64" else if ( "64" == $gt_build_type) then setenv gt_asm_arch_size "--64" else setenv gt_asm_arch_size "--32" endif if ( "ia64" != $mach_type ) then alias gt_as_bta \ 'gt_as $gt_as_option_debug $gt_as_option_nooptimize $gt_asm_arch_size -o `basename \!:1 .s`.o \!:1' # If the value of the alias variable extends the 132 character limit, use a temporary variable # (like gtm_as_dbg_var below) and use that in the alias value to stick to the the coding standard. set gt_as_dbg_var = "$gt_as_option_DDEBUG $gt_as_option_debug $gt_as_option_nooptimize $gt_asm_arch_size" alias gt_as_dbg 'gt_as $gt_as_dbg_var -o `basename \!:1 .s`.o \!:1' alias gt_as_pro 'gt_as $gt_as_option_optimize $gt_asm_arch_size -o `basename \!:1 .s`.o \!:1' endif fis-gtm-V6.0-003/sr_linux/gtm_env_sp.mk0000644000032200000250000001217512201176146016705 0ustar librarygtc################################################################# # # # Copyright 2001, 2012 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# # ########################################################################################## # # gtm_env_sp.mk - environment variable values and aliases specific to Linux # if not Linux we assume Cygwin and x86 # ########################################################################################## # GNU assembler options gt_as_assembler=as gt_as_option_DDEBUG= gt_as_option_debug=--gstabs gt_as_option_nooptimize= gt_as_option_optimize= gt_as_options= gt_as_options_common=--64 gt_as_src_suffix=.s ifeq ($(gt_machine_type), ia64) gt_as_assembler=gcc -c gt_as_option_debug= else ifeq ($(gt_machine_type), s390x) gt_as_options_common=-march=z9-109 -m64 gt_as_option_debug=--gdwarf-2 else ifeq ($(gt_machine_type), CYGWIN) gt_as_option_debug=--gdwarf-2 gt_as_options_common=--defsym cygwin=1 endif endif endif ifeq ($(gt_build_type), 32) ifeq ($(gt_os_type),Linux) gt_as_options_common=--32 endif endif # C compiler options gt_cc_shl_fpic=-fPIC gt_cc_options_common=-c -ansi ifeq ($(gt_os_type),CYGWIN) gt_cc_option_debug=$(gt_cc_option_debug) -gdwarf-2 -fno-inline -fno-inline-functions gt_cc_shl_fpic= gt_cc_options_common=-c endif gt_cc_compiler=cc gt_cc_option_DBTABLD=-DNOLIBGTMSHR gt_cc_option_DDEBUG=-DDEBUG gt_cc_option_debug=-g gt_cc_option_nooptimize= gt_cc_option_optimize=-O2 -fno-defer-pop -fno-strict-aliasing -ffloat-store gt_cc_options_common+= -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_XOPEN_SOURCE=600 -fsigned-char ifeq ($(gt_machine_type), x86_64) ifeq ($(gt_build_type),32) # The /emul/ia32-linux/... directory doesn't exist on most machines, but when it's there we need it. No problem # with always includeing it. gt_cc_option_I+= -I/emul/ia32-linux/usr/include/ else gt_cc_option_I= endif endif # autodepend option gt_cc_dep_option=-w ifeq ($(gt_machine_type), ia64) gt_cc_option_optimize=-O else gt_cc_options_common+= $(gt_cc_shl_fpic) -Wmissing-prototypes -D_LARGEFILE64_SOURCE ifeq ($(gt_build_type),32) gt_cc_option_optimize+= -march=i686 endif endif gt_cc_shl_options=-c $(gt_cc_shl_fpic) ifeq ($(gt_os_type),CYGWIN) gt_cc_options_common+= -DNO_SEM_TIME -DNO_SEM_GETPID endif # Linker definitions: gt_ld_aio_syslib= gt_ld_ci_options=-Wl,-u,gtm_ci -Wl,-u,gtm_filename_to_id -Wl,--version-script,gtmshr_symbols.export gt_ld_ci_u_option=-Wl,-u,gtm_ci gt_ld_linker=$(gt_cc_compiler) gt_ld_m_shl_linker=ld gt_ld_m_shl_options=-shared gt_ld_option_output=-o gt_ld_options_all_exe=-rdynamic -Wl,-u,gtm_filename_to_id -Wl,-u,gtm_zstatus -Wl,--version-script,gtmexe_symbols.export gt_ld_options_bta=-Wl,-M gt_ld_options_common=-Wl,-M gt_ld_options_dbg=-Wl,-M gt_ld_options_gtmshr=-Wl,-u,gtm_filename_to_id -Wl,--version-script,gtmshr_symbols.export gt_ld_options_pro=-Wl,-M gt_ld_shl_linker=cc gt_ld_shl_options=-shared gt_ld_shl_suffix=.so gt_ld_sysrtns= ifeq ($(gt_build_type),32) gt_ld_m_shl_options= endif # -lrt for async I/O in mupip recover/rollback # -lrt doesn't work to pull in semaphores with GCC 4.6, so use -lpthread. # Add -lc in front of -lpthread to avoid linking in thread-safe versions # of libc routines from libpthread. ifeq ($(gt_build_type), 64) gt_ld_syslibs=-lrt -lelf -lncurses -lm -ldl -lc -lpthread else ifeq ($(gt_os_type),Linux) gt_ld_syslibs=-lrt -lncurses -lm -ldl -lc -lpthread else gt_ld_syslibs=-lncurses -lm -lcrypt endif endif # lint definition overrides gt_lint_linter= gt_lint_options_library=-x gt_lint_options_common= gt_cpus=$(shell grep -c process /proc/cpuinfo) # used to build VPATH # Apparently Ubuntu does not like the -e option for echo, delete this if the *.mdep make files generate an error ifeq ($(distro),ubuntu) gt_echoe=echo else gt_echoe=echo -e endif ifeq ($(gt_build_type), 32) gt_cc_options_common+=-m32 gt_ld_options_gtmshr+=-m32 gt_cc_shl_options+=-m32 gt_ld_options_common+=-m32 endif # # gas assembly - the preprocessor works # define gt-as $(gt_as_assembler) $(gt_as_options) $< -o $@ endef define gt_cpp $(gt_cpp_compiler) -E $(gt_cpp_options_common) $(gt_cc_option_I) $< > $<_cpp.s endef define gt-as_cpp $(gt_as_assembler) $(gt_as_options) $<_cpp.s -o $@ endef # # gcc specific rule to get the depend file (CC -M) # define gt-dep @echo $*.o $*.d : '\' > $@; \ echo $(notdir $(filter-out /usr/include% /usr/lib% /usr/local/include% /usr/local/lib/%, \ $(filter %.c %.h,$(shell $(gt_cc_compiler) -M $(gt_cc_options) $(gt_cc_dep_option) $<)))) >> $@ endef define gt-export @echo "{" >$@ @echo "global:" >>$@ @sed 's/\(.*\)/ \1;/g' $< >>$@ @echo "local:" >>$@ @echo " *;" >>$@ @echo "};" >>$@ endef fis-gtm-V6.0-003/sr_linux/gtm_getenv.c0000644000032200000250000000250112201176146016506 0ustar librarygtc/**************************************************************** * * * Copyright 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifdef __CYGWIN__ /* In Cygwin 1.54-2 and gdb 6.5.50, the Cygwin environment variables * * are not passed to the program being debugged properly. getenv() * * only sees the Windows variables. * */ #include "gtm_unistd.h" #include "gtm_stdlib.h" #include "gtm_string.h" extern char **environ; /* array of pointers, last has NULL */ char *gtm_getenv(char *varname) { char *eq, **p; size_t len; if (NULL == environ || NULL == varname) return NULL; len = strlen(varname); for (p = environ; *p; p++) { eq = strchr(*p, '='); if (eq && (*p + len) == eq) { if (!strncasecmp(varname, *p, len)) /* environ names are upcased */ return (eq + 1); } } return NULL; } #endif fis-gtm-V6.0-003/sr_linux/hugetlbfs_overrides.c0000644000032200000250000001135312201176146020421 0ustar librarygtc/**************************************************************** * * * Copyright 2012, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* * This file contains functions related to Linux HugeTLB support. Its functions rely * on libhugetlbfs which allocates memory in Huge Pages. * This library is Linux only and works only on (currently) x86, AMD64 and PowerPC * Supported Huge Page functionality requires the following prerequisites: * Linux kernel support of Huge Pages * x86_64 or i386 architecture * libhugetlbfs.so being installed * Availability of Huge Pages through setting value to /proc/sys/vm/nr_hugepages or hugepages= kernel parameter or * /proc/sys/vm/nr_overcommit_hugepages * In order to use shmget with Huge Pages, either the process gid should be in /proc/sys/vm/hugetlb_shm_group or the * process should have CAP_IPC_LOCK * In order to remap .text/.data/.bss sections, a file system of type hugetlbfs should be mounted * Appropriate environmental variables should be set (refer to libhugetlbfs documentation) to enable/disable Huge Pages */ #include "mdef.h" #include #include "gtm_string.h" #include "get_page_size.h" #include "hugetlbfs_overrides.h" #undef shmget #include "send_msg.h" #include "wbox_test_init.h" #ifdef DEBUG # define WBTEST_HUGETLB_DLSYM_ERROR "WBTEST_HUGETLB_DLSYM error" #endif GBLDEF long gtm_os_hugepage_size = -1; /* Default Huge Page size of OS. If huge pages are not supported or the * value doesn't fit into a *long* it will be equal to the OS page size */ OS_PAGE_SIZE_DECLARE /* ptr to libhugetlbfs's overriden shmget. It uses Linux Huge Pages to back the shared segment if possible */ STATICDEF int (*p_shmget) (key_t, size_t, int) = NULL; /* returns default huge page size of the OS or -1 in case huge pages are not supported or their sizes doesn't * fit into a long. Refer to libhugetlbfs for further info. */ STATICDEF long (*p_gethugepagesize) (void) = NULL; STATICDEF boolean_t hugetlb_is_attempted = FALSE; /* all shmget declarations have already been MACROed to gtm_shmget in mdefsp.h so we need to declare the real * one here */ extern int shmget (key_t __key, size_t __size, int __shmflg); error_def(ERR_DLLNORTN); error_def(ERR_TEXT); /* A MACRO in mdefsp.h (LINUX_ONLY) replaces all shmget with this function */ int gtm_shmget (key_t key, size_t size, int shmflg) { assert(hugetlb_is_attempted); /* libhugetlbfs_init must be called prior to this function */ return p_shmget(key, size, shmflg); } /* * This function initializes libhugetlbfs if it's available. Upon dlopen() the initializing function of libhugetlbfs * is called. If libhugetlbfs is available gtm_shmget uses its shmget. Otherwise it falls back to the native shmget. * For malloc to use hugepages, it calls __morecore() hook if it needs more memory. In case libhugetlbfs is available * and other Huge Page conditions are met, the libhugetlbfs assigns __morecore() to a version which backs them with * hugepages during its initialization * Consult libhugetlbfs documentation for a list of HugeTLB configuration environment variables. */ void libhugetlbfs_init(void) { char *error = NULL; void *handle; assert(!hugetlb_is_attempted); handle = dlopen("libhugetlbfs.so", RTLD_NOW); GTM_WHITE_BOX_TEST(WBTEST_HUGETLB_DLOPEN, handle, NULL); if (NULL != handle) { /* C99 standard leaves casting from "void *" to a function pointer undefined. The assignment used * below is the POSIX.1-2003 (Technical Corrigendum 1) workaround; */ *(void **) (&p_shmget) = dlsym(handle, "shmget"); GTM_WHITE_BOX_TEST(WBTEST_HUGETLB_DLSYM, p_shmget, NULL); if (NULL != p_shmget) /* NULL value for shmget() necessarily means it was not found */ { *(void **) (&p_gethugepagesize) = dlsym(handle, "gethugepagesize"); if (NULL != p_gethugepagesize) gtm_os_hugepage_size = p_gethugepagesize(); else error = dlerror(); } else error = dlerror(); GTM_WHITE_BOX_TEST(WBTEST_HUGETLB_DLSYM, error, WBTEST_HUGETLB_DLSYM_ERROR); if (error) { p_shmget = NULL; send_msg(VARLSTCNT(8) ERR_DLLNORTN, 2, LEN_AND_LIT("shmget from libhugetlbfs.so"), ERR_TEXT, 2, LEN_AND_STR(error)); } } if (NULL == p_shmget) p_shmget = &shmget; /* Fall back to using the native shmget */ get_page_size(); if (-1 == gtm_os_hugepage_size) gtm_os_hugepage_size = OS_PAGE_SIZE; assert(0 == (gtm_os_hugepage_size % OS_PAGE_SIZE)); /* huge pages sizes are multiples of page sizes */ hugetlb_is_attempted = TRUE; } fis-gtm-V6.0-003/sr_linux/hugetlbfs_overrides.h0000644000032200000250000000151012201176146020420 0ustar librarygtc/**************************************************************** * * * Copyright 2012, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef HUGETLBFS_OVERRIDES_H_ #define HUGETLBFS_OVERRIDES_H_ #if defined(__linux__) && ( defined(__i386__) || defined(__x86_64__) ) # define HUGETLB_SUPPORTED 1 #endif GBLREF long gtm_os_hugepage_size; #define OS_HUGEPAGE_SIZE gtm_os_hugepage_size extern int gtm_shmget(key_t __key, size_t __size, int __shmflg); void libhugetlbfs_init(void); #endif /* HUGETLBFS_OVERRIDES_H_ */ fis-gtm-V6.0-003/sr_linux/inst_flush.c0000644000032200000250000000116512201176146016532 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* STUB FILE only for non-ia64 versions */ #include "mdef.h" #include "inst_flush.h" void inst_flush(void *start, int4 len) { IA64_ONLY(cacheflush(start, len, 0 )); } fis-gtm-V6.0-003/sr_linux/platform.cmake0000644000032200000250000000347112201176146017040 0ustar librarygtc################################################################# # # # Copyright 2013 Fidelity Information Services, Inc # # # # This source code contains the intellectual property # # of its copyright holder(s), and is made available # # under a license. If you do not know the terms of # # the license, please stop and do not read further. # # # ################################################################# if("${CMAKE_SIZEOF_VOID_P}" EQUAL 4) set(arch "x86") set(bits 32) set(FIND_LIBRARY_USE_LIB64_PATHS FALSE) else() set(arch "x86_64") set(bits 64) endif() # Platform directories list(APPEND gt_src_list sr_linux) if(${bits} EQUAL 32) list(APPEND gt_src_list sr_i386 sr_x86_regs sr_unix_nsb) else() list(APPEND gt_src_list sr_x86_64 sr_x86_regs) set(gen_xfer_desc 1) endif() # Assembler set(CMAKE_INCLUDE_FLAG_ASM "-Wa,-I") # gcc -I does not make it to "as" # Compiler set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ansi -fsigned-char -fPIC -Wmissing-prototypes -fno-omit-frame-pointer") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fno-defer-pop -fno-strict-aliasing -ffloat-store") add_definitions( #-DNOLIBGTMSHR #gt_cc_option_DBTABLD=-DNOLIBGTMSHR -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_XOPEN_SOURCE=600 -D_LARGEFILE64_SOURCE ) # Linker set(gtm_link "-Wl,-u,gtm_filename_to_id -Wl,-u,gtm_zstatus -Wl,--version-script,\"${GTM_BINARY_DIR}/gtmexe_symbols.export\"") set(gtm_dep "${GTM_BINARY_DIR}/gtmexe_symbols.export") set(libgtmshr_link "-Wl,-u,gtm_ci -Wl,-u,gtm_filename_to_id -Wl,--version-script,\"${GTM_BINARY_DIR}/gtmshr_symbols.export\"") set(libgtmshr_dep "${GTM_BINARY_DIR}/gtmexe_symbols.export") if(${bits} EQUAL 32) set(libmumpslibs "-lncurses -lm -ldl -lc -lpthread -lrt") else() set(libmumpslibs "-lelf -lncurses -lm -ldl -lc -lpthread -lrt") endif() fis-gtm-V6.0-003/sr_linux/release_name.h0000644000032200000250000000156012201176146017000 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifdef __CYGWIN__ #define GTM_RELEASE_NAME "GT.M V6.0-003 CYGWIN x86" #elif defined(__ia64) #define GTM_RELEASE_NAME "GT.M V6.0-003 Linux IA64" #elif defined(__x86_64__) #define GTM_RELEASE_NAME "GT.M V6.0-003 Linux x86_64" #elif defined(__s390__) #define GTM_RELEASE_NAME "GT.M V6.0-003 Linux S390X" #else #define GTM_RELEASE_NAME "GT.M V6.0-003 Linux x86" #endif #define GTM_PRODUCT "GT.M" #define GTM_VERSION "V6.0" fis-gtm-V6.0-003/sr_port/0000755000032200000250000000000012201176201014022 5ustar librarygtcfis-gtm-V6.0-003/sr_port/act_in_gvt.c0000644000032200000250000000304612201176176016321 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "collseq.h" #include "spec_type.h" #ifdef GTM_TRIGGER #include #include "gv_trigger.h" #endif GBLREF gv_namehead *gv_target; GBLREF gv_key *gv_altkey; void act_in_gvt(void) { collseq *csp; error_def(ERR_COLLATIONUNDEF); error_def(ERR_COLLTYPVERSION); error_def(ERR_GVIS); # ifdef GTM_TRIGGER if ((HASHT_GBLNAME_LEN == gv_target->gvname.var_name.len) && (0 == MEMCMP_LIT(gv_target->gvname.var_name.addr, HASHT_GBLNAME))) return; /* No collation for triggers */ # endif if (csp = ready_collseq((int)(gv_target->act))) { if (!do_verify(csp, gv_target->act, gv_target->ver)) { gv_target->root = 0; rts_error(VARLSTCNT(8) ERR_COLLTYPVERSION, 2, gv_target->act, gv_target->ver, ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base); } } else { gv_target->root = 0; rts_error(VARLSTCNT(7) ERR_COLLATIONUNDEF, 1, gv_target->act, ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base); } gv_target->collseq = csp; return; } fis-gtm-V6.0-003/sr_port/actuallist.c0000644000032200000250000001011712201176154016342 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "mdq.h" #include "fullbool.h" #include "advancewindow.h" #include "show_source_line.h" GBLREF boolean_t run_time; error_def(ERR_COMMAORRPAREXP); error_def(ERR_MAXACTARG); error_def(ERR_NAMEEXPECTED); error_def(ERR_SIDEEFFECTEVAL); int actuallist (oprtype *opr) { boolean_t se_warn; int i, j, mask, parmcount; oprtype ot; triple *counttrip, *masktrip, *ref0, *ref1, *ref2; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(TK_LPAREN == TREF(window_token)); advancewindow(); masktrip = newtriple(OC_PARAMETER); mask = 0; counttrip = newtriple(OC_PARAMETER); masktrip->operand[1] = put_tref(counttrip); ref0 = counttrip; if (TK_RPAREN == TREF(window_token)) parmcount = 0; else { for (parmcount = 1; ; parmcount++) { if (MAX_ACTUALS < parmcount) { stx_error (ERR_MAXACTARG); return FALSE; } if (TK_PERIOD == TREF(window_token)) { advancewindow (); if (TK_IDENT == TREF(window_token)) { ot = put_mvar(&(TREF(window_ident))); mask |= (1 << parmcount - 1); advancewindow(); } else if (TK_ATSIGN == TREF(window_token)) { if (!indirection(&ot)) return FALSE; ref2 = newtriple(OC_INDLVNAMADR); ref2->operand[0] = ot; ot = put_tref(ref2); mask |= (1 << parmcount - 1); } else { stx_error(ERR_NAMEEXPECTED); return FALSE; } } else if (TK_COMMA == TREF(window_token)) { ref2 = newtriple(OC_NULLEXP); ot = put_tref(ref2); } else if (EXPR_FAIL == expr(&ot, MUMPS_EXPR)) return FALSE; ref1 = newtriple(OC_PARAMETER); ref0->operand[1] = put_tref(ref1); ref1->operand[0] = ot; if (TK_COMMA == TREF(window_token)) { advancewindow (); if (TK_RPAREN == TREF(window_token)) { ref0 = ref1; ref2 = newtriple(OC_NULLEXP); ot = put_tref(ref2); ref1 = newtriple(OC_PARAMETER); ref0->operand[1] = put_tref(ref1); ref1->operand[0] = ot; parmcount++; break; } } else if (TREF(window_token) == TK_RPAREN) break; else { stx_error (ERR_COMMAORRPAREXP); return FALSE; } ref0 = ref1; } if ((1 < parmcount) && (TREF(side_effect_base))[TREF(expr_depth)]) { /* at least two arguments and at least one side effect - look for lvns needing protection */ assert(OLD_SE != TREF(side_effect_handling)); se_warn = (!run_time && (SE_WARN == TREF(side_effect_handling))); for (i = 0, j = parmcount, ref0 = counttrip->operand[1].oprval.tref; --j; ref0 = ref0->operand[1].oprval.tref) { /* no need to do the last argument - can't have a side effect after it */ assert(OC_PARAMETER == ref0->opcode); assert((TRIP_REF == ref0->operand[0].oprclass) && (TRIP_REF == ref0->operand[1].oprclass)); if (!((1 << i++) & mask) && (OC_VAR == ref0->operand[0].oprval.tref->opcode)) { /* can only protect pass-by-value (not pass-by-reference) */ ref1 = maketriple(OC_STOTEMP); ref1->operand[0] = put_tref(ref0->operand[0].oprval.tref); ref0->operand[0].oprval.tref = ref1; dqins(ref0, exorder, ref1); /* NOTE:this violates information hiding */ if (se_warn) ISSUE_SIDEEFFECTEVAL_WARNING(ref0->src.column); } } /* the following asserts check we're getting only TRIP_REF or empty operands */ assert((NO_REF == ref0->operand[0].oprclass) || (TRIP_REF == ref0->operand[0].oprclass)); assert(((NO_REF == ref0->operand[0].oprclass) ? TRIP_REF : NO_REF) == ref0->operand[1].oprclass); } } advancewindow(); masktrip->operand[0] = put_ilit(mask); counttrip->operand[0] = put_ilit(parmcount); parmcount += 2; *opr = put_tref(masktrip); return parmcount; } fis-gtm-V6.0-003/sr_port/add_atom.c0000644000032200000250000000725212201176154015753 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "copy.h" #include "patcode.h" #include "min_max.h" /* This function is part of the MUMPS compiler. It adds one pattern atom to the string of compiled pattern atoms. * If the atom to be added can be "compressed" with the previous one, this function will allow compress() to do so. */ boolean_t add_atom(int *count, uint4 pattern_mask, pat_strlit *strlit_buff, boolean_t infinite, int *min, int *max, int *size, int *total_min, int *total_max, int lower_bound, int upper_bound, int altmin, int altmax, boolean_t *last_infinite_ptr, uint4 **fstchar_ptr, uint4 **outchar_ptr, uint4 **lastpatptr_ptr) { uint4 *patmaskptr; gtm_uint64_t bound; int4 bytelen; if ((pattern_mask & PATM_STRLIT) && !strlit_buff->bytelen && *count) { /* A special case is a pattern like xxx?1N5.7""2A . Since there is an infinite number of empty strings between * any two characters in a string, a pattern atom that counts repetitions of the fixed string "" can be ignored. * That is, such an atom can only be ignored if it is not the only one in the pattern... */ return TRUE; } if (*count && !*(size - 1)) { /* If the previous atom was an n.m"", it should be removed. In such a case, the last four values * in the 'outchar' array are PATM_STRLIT (pattern mask), 0 (bytelen), 0 (charlen), flags (ASCII and no BADCHAR). */ assert(3 == PAT_STRLIT_PADDING); assert(PATM_STRLIT == *(*outchar_ptr - (PAT_STRLIT_PADDING + 1))); assert(0 == *(*outchar_ptr - 3)); /* bytelen */ assert(0 == *(*outchar_ptr - 2)); /* charlen */ assert(!((*(*outchar_ptr - 1)) & PATM_STRLIT_NONASCII)); /* flags - ascii */ assert(!((*(*outchar_ptr - 1)) & PATM_STRLIT_BADCHAR)); /* flags - no badchar */ *outchar_ptr -= (PAT_STRLIT_PADDING + 1); (*count)--; assert(0 == *count); min--; max--; size--; } if (pattern_mask & PATM_ALT) { lower_bound = BOUND_MULTIPLY(lower_bound, altmin, bound); upper_bound = BOUND_MULTIPLY(upper_bound, altmax, bound); } if (*count && pat_compress(pattern_mask, strlit_buff, infinite, *last_infinite_ptr, *lastpatptr_ptr)) { min--; max--; size--; *min = MIN(*min + lower_bound, PAT_MAX_REPEAT); *max = MIN(*max + upper_bound, PAT_MAX_REPEAT); } else { *min = MIN(lower_bound, PAT_MAX_REPEAT); *max = MIN(upper_bound, PAT_MAX_REPEAT); *lastpatptr_ptr = patmaskptr = *outchar_ptr; *last_infinite_ptr = infinite; (*outchar_ptr)++; if (*outchar_ptr - *fstchar_ptr > MAX_PATTERN_LENGTH) return FALSE; if ((pattern_mask & PATM_ALT) || !(pattern_mask & PATM_STRLIT)) { *patmaskptr++ = pattern_mask; *size = 1; } else { bytelen = strlit_buff->bytelen; *outchar_ptr += DIVIDE_ROUND_UP(bytelen, SIZEOF(uint4)) + PAT_STRLIT_PADDING; if (*outchar_ptr - *fstchar_ptr > MAX_PATTERN_LENGTH) return FALSE; *patmaskptr++ = pattern_mask; memcpy(patmaskptr, strlit_buff, bytelen + PAT_STRLIT_PADDING * SIZEOF(uint4)); *size = strlit_buff->charlen; } (*count)++; } *total_min += BOUND_MULTIPLY(*size, lower_bound, bound); if (*total_min > PAT_MAX_REPEAT) *total_min = PAT_MAX_REPEAT; *total_max += BOUND_MULTIPLY(*size, upper_bound, bound); if (*total_max > PAT_MAX_REPEAT) *total_max = PAT_MAX_REPEAT; return TRUE; } fis-gtm-V6.0-003/sr_port/add_inter.h0000644000032200000250000000115612201176154016136 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef ADD_INTER_DEFINED /* Declare parms for add_inter.c */ int4 add_inter (int val, sm_int_ptr_t addr, sm_global_latch_ptr_t latch); #define ADD_INTER_DEFINED #endif fis-gtm-V6.0-003/sr_port/adjust_frames.c0000644000032200000250000000224112201176176017027 0ustar librarygtc/**************************************************************** * * * Copyright 2002, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "stack_frame.h" GBLREF stack_frame *frame_pointer; void adjust_frames(unsigned char *old_ptext_beg, unsigned char *old_ptext_end, unsigned char *new_ptext_beg) { stack_frame *fp; for (fp = frame_pointer; NULL != fp; fp = fp->old_frame_pointer) { #ifdef GTM_TRIGGER if (fp->type & SFT_TRIGR) /* Have a trigger baseframe, pick up stack continuation frame_pointer stored by base_frame() */ fp = *(stack_frame **)(fp + 1); assert(fp); #endif assert((frame_pointer < frame_pointer->old_frame_pointer) || (NULL == frame_pointer->old_frame_pointer)); if (old_ptext_beg <= fp->mpc && fp->mpc <= old_ptext_end) fp->mpc += (new_ptext_beg - old_ptext_beg); } return; } fis-gtm-V6.0-003/sr_port/advancewindow.c0000644000032200000250000002110112201176154017021 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "compiler.h" #include "toktyp.h" #include "stringpool.h" #include "gtm_caseconv.h" #include "advancewindow.h" #include "show_source_line.h" #ifdef UNICODE_SUPPORTED #include "gtm_utf8.h" #include "gtm_icu_api.h" /* U_ISPRINT() needs this header */ #endif GBLREF unsigned char *source_buffer; GBLREF short int source_column; GBLREF char *lexical_ptr; GBLREF spdesc stringpool; GBLREF boolean_t gtm_utf8_mode; GBLREF boolean_t run_time; LITREF char ctypetab[NUM_CHARS]; error_def(ERR_LITNONGRAPH); error_def(ERR_NUMOFLOW); static readonly unsigned char apos_ok[] = { 0,TK_NEXCLAIMATION,0,0,0,0,TK_NAMPERSAND,0 ,0,0,0,0,0,0,0,0 ,0,0,0,0,0,0,0,0 ,0,0,0,0,TK_NLESS,TK_NEQUAL,TK_NGREATER,TK_NQUESTION ,0,0,0,0,0,0,0,0 ,0,0,0,0,0,0,0,0 ,0,0,0,0,0,0,0,0 ,0,0,0,TK_NLBRACKET,0,TK_NRBRACKET,0,0 }; void advancewindow(void) { unsigned char *cp1, *cp2, *cp3, x; char *tmp; int y, charlen; # ifdef UNICODE_SUPPORTED uint4 ch; unsigned char *cptr; # endif DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; TREF(last_source_column) = source_column; source_column = (unsigned char *)lexical_ptr - source_buffer + 1; TREF(window_token) = TREF(director_token); TREF(window_mval) = TREF(director_mval); (TREF(director_mval)).mvtype = 0; /* keeps mval from being GC'd since it is not useful until re-used */ tmp = (TREF(window_ident)).addr; /* More efficient to swap pointers between window_ident.addr & director_ident.addr */ TREF(window_ident) = TREF(director_ident); /* than to copy text from director_ident to window_ident */ (TREF(director_ident)).addr = tmp; x = *lexical_ptr; switch (y = ctypetab[x]) { case TK_EOL: TREF(director_token) = TK_EOL; return; /* if next character is terminator, avoid incrementing past it */ case TK_QUOTE: ENSURE_STP_FREE_SPACE(MAX_SRCLINE); cp1 = (unsigned char *)lexical_ptr + 1; cp2 = cp3 = stringpool.free; for (;;) { # ifdef UNICODE_SUPPORTED if (gtm_utf8_mode) cptr = (unsigned char *)UTF8_MBTOWC((sm_uc_ptr_t)cp1, source_buffer + MAX_SRCLINE, ch); # endif x = *cp1++; if ((SP > x) UNICODE_ONLY(|| (gtm_utf8_mode && !(U_ISPRINT(ch))))) { TREF(last_source_column) = cp1 - source_buffer; if ('\0' == x) { TREF(director_token) = TREF(window_token) = TK_ERROR; return; } if (!run_time) { show_source_line(TRUE); dec_err(VARLSTCNT(1) ERR_LITNONGRAPH); } } if ('\"' == x) { UNICODE_ONLY(assert(!gtm_utf8_mode || (cp1 == cptr))); if ('\"' == *cp1) cp1++; else break; } *cp2++ = x; # ifdef UNICODE_SUPPORTED if (gtm_utf8_mode && (cptr > cp1)) { assert(4 > (cptr - cp1)); for (; cptr > cp1;) *cp2++ = *cp1++; } # endif assert(cp2 <= stringpool.top); } lexical_ptr = (char *)cp1; TREF(director_token) = TK_STRLIT; (TREF(director_mval)).mvtype = MV_STR; (TREF(director_mval)).str.addr = (char *)cp3; (TREF(director_mval)).str.len = INTCAST(cp2 - cp3); stringpool.free = cp2; s2n(&(TREF(director_mval))); # ifdef UNICODE_SUPPORTED if (gtm_utf8_mode && !run_time) { /* UTF8 mode and not compiling an indirect gets an optimization to set the * (true) length of the string into the mval */ charlen = utf8_len_stx(&(TREF(director_mval)).str); if (0 > charlen) /* got a BADCHAR error */ TREF(director_token) = TK_ERROR; else { assert(charlen == (TREF(director_mval)).str.char_len); (TREF(director_mval)).mvtype |= MV_UTF_LEN; } } # endif return; case TK_LOWER: case TK_PERCENT: case TK_UPPER: cp2 = (unsigned char *)((TREF(director_ident)).addr); cp3 = cp2 + MAX_MIDENT_LEN; for (;;) { if (cp2 < cp3) *cp2++ = x; y = ctypetab[x = *++lexical_ptr]; /* note assignment */ if ((TK_UPPER != y) && (TK_DIGIT != y) && (TK_LOWER != y)) break; } (TREF(director_ident)).len = INTCAST(cp2 - (unsigned char*)(TREF(director_ident)).addr); TREF(director_token) = TK_IDENT; return; case TK_PERIOD: if (ctypetab[x = *(lexical_ptr + 1)] != TK_DIGIT) /* note assignment */ break; case TK_DIGIT: (TREF(director_mval)).str.addr = lexical_ptr; (TREF(director_mval)).str.len = MAX_SRCLINE; (TREF(director_mval)).mvtype = MV_STR; lexical_ptr = (char *)s2n(&(TREF(director_mval))); if (!((TREF(director_mval)).mvtype &= MV_NUM_MASK)) { stx_error(ERR_NUMOFLOW); TREF(director_token) = TK_ERROR; return; } if (TREF(s2n_intlit)) { TREF(director_token) = TK_NUMLIT ; n2s(&(TREF(director_mval))); } else { TREF(director_token) = TK_INTLIT ; (TREF(director_mval)).str.len = INTCAST(lexical_ptr - (TREF(director_mval)).str.addr); ENSURE_STP_FREE_SPACE((TREF(director_mval)).str.len); memcpy(stringpool.free, (TREF(director_mval)).str.addr, (TREF(director_mval)).str.len); assert (stringpool.free <= stringpool.top) ; } return; case TK_APOSTROPHE: if (32 <= (x = *++lexical_ptr)) /* note assignment */ { x -= 32; if (x < ARRAYSIZE(apos_ok)) { if (y = apos_ok[x]) { if (DEL < (x = *++lexical_ptr)) /* note assignment */ { TREF(director_token) = TK_ERROR; return; } if (TK_RBRACKET == ctypetab[x]) { lexical_ptr++; y = TK_NSORTS_AFTER; } TREF(director_token) = y; return; } } } TREF(director_token) = TK_APOSTROPHE; return; case TK_GREATER: case TK_LESS: if (TK_EQUAL == ctypetab[*(lexical_ptr + 1)]) { ++lexical_ptr; y = ((TK_LESS == y) ? TK_NGREATER : TK_NLESS); } break; case TK_SEMICOLON: while (*++lexical_ptr) ; assert(TK_EOL == ctypetab[*lexical_ptr]); TREF(director_token) = TK_EOL; return; /* if next character is terminator, avoid incrementing past it */ case TK_ASTERISK: if (DEL < (x = *(lexical_ptr + 1))) /* note assignment */ { TREF(director_token) = TK_ERROR; return; } if (TK_ASTERISK == ctypetab[x]) { lexical_ptr++; y = TK_EXPONENT; } break; case TK_RBRACKET: if ((x = *(lexical_ptr + 1)) > DEL) /* note assignment */ { TREF(director_token) = TK_ERROR; return; } if (TK_RBRACKET == ctypetab[x]) { lexical_ptr++; y = TK_SORTS_AFTER; } break; case TK_ATSIGN: if (DEL < (x = *(lexical_ptr + 1))) /* note assignment */ { TREF(director_token) = TK_ERROR; return; } if (TK_HASH == ctypetab[x]) { lexical_ptr++; y = TK_ATHASH; } default: ; } lexical_ptr++; TREF(director_token) = y; return; } #ifdef GTM_TRIGGER /* The M standard does not allow the '#' character to appear inside mnames but in specific places, we want to allow this * so that triggers, which have the imbedded '#' character in their routine names, can be debugged and printed. The places * where this is allowed follow. * * 1. $TEXT() * 2. ZBREAK * 3. ZPRINT * * All other uses still prohibit '#' from being in an MNAME. Routines that need to allow # in a name can call this routine to * recombine the existing token and the look-ahead (director) token such that '#' is considered part of an mident. */ void advwindw_hash_in_mname_allowed(void) { unsigned char *cp2, *cp3, x; unsigned char ident_buffer[SIZEOF(mident_fixed)]; int ident_len, ch; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(TK_IDENT == TREF(window_token)); assert(TK_HASH == TREF(director_token)); /* First copy the existing token we want to expand into our safe-haven */ memcpy(ident_buffer, (TREF(window_ident)).addr, (TREF(window_ident)).len); /* Now parse further until we run out of [m]ident */ cp2 = ident_buffer + (TREF(window_ident)).len; cp3 = ident_buffer + MAX_MIDENT_LEN; *cp2++ = '#'; /* We are only called if director token is '#' so put that char in buffer now */ /* Start processing with the token following the '#' */ for (x = *lexical_ptr, ch = ctypetab[x]; ((TK_UPPER == ch) || (TK_DIGIT == ch) || (TK_LOWER == ch) || (TK_HASH == ch)); x = *++lexical_ptr, ch = ctypetab[x]) { if (cp2 < cp3) *cp2++ = x; } (TREF(director_ident)).len = INTCAST(cp2 - ident_buffer); TREF(director_token) = TK_IDENT; memcpy((TREF(director_ident)).addr, ident_buffer, (TREF(director_ident)).len); advancewindow(); /* Makes the homogenized token the current token (again) and prereads next token */ } #endif fis-gtm-V6.0-003/sr_port/advancewindow.h0000644000032200000250000000120712201176154017033 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef ADVANCEWINDOW_included #define ADVANCEWINDOW_included void advancewindow(void); #ifdef GTM_TRIGGER void advwindw_hash_in_mname_allowed(void); #endif #endif /* ADVANCEWINDOW_included */ fis-gtm-V6.0-003/sr_port/alias.h0000644000032200000250000003473512201176154015307 0ustar librarygtc/**************************************************************** * * * Copyright 2009, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef ALIAS_H_ # define ALIAS_H_ #define DOLLAR_ZWRTAC "$ZWRTAC" /* Min and max for the number of stringpool garbage collections (SPGC) that will be done without having done a lv_val garbage collection (aka LVGC aka als_lvval_gc). While I did give these numbers some thought, they aren't far from semi-random. Since the LVGC is kind of expensive (requiring two traversals of the lv_vals in a symbol table) I decided 2 SPGCs was good to spread the cost of one LVGC over. For the max, I didn't want to let it get too high so the tuning algorithm didn't take a long time to get back to a more frequent value when necessary yet 64 seems fairly infrequent. These numbers are totally subject to future studies.. [SE 12/2008] */ #define MIN_SPGC_PER_LVGC 2 #define MAX_SPGC_PER_LVGC 64 #include "zwrite.h" /* Macro used intermittently in code to debug alias code in general. Note this macro must be specified as a compile option since it is used in macros that do not pull in this alias.h header file. */ #ifdef DEBUG_ALIAS # define DBGALS(x) DBGFPF(x) # define DBGALS_ONLY(x) x #else # define DBGALS(x) # define DBGALS_ONLY(x) #endif /* Macro used intermittently to trace reference count changes */ /* #define DEBUG_REFCNT */ #ifdef DEBUG_REFCNT # define DBGRFCT(x) DBGFPF(x) # define DBGRFCT_ONLY(x) x #else # define DBGRFCT(x) # define DBGRFCT_ONLY(x) #endif /* Since DBGFPF calls flush_pio, if we are debugging, include the defining header file */ #if defined(DEBUG_ALIAS) || defined(DEBUG_REFCNT) # include "io.h" #endif /* Macro to increment total refcount (and optionally trace it) */ #define INCR_TREFCNT(lv) \ { \ assert(LV_IS_BASE_VAR(lv)); \ DBGRFCT((stderr, "\nIncrement trefcnt for lv_val at 0x"lvaddr" from %d to %d by %s line %d\n", \ (lv), (lv)->stats.trefcnt, (lv)->stats.trefcnt + 1, __FILE__, __LINE__)); \ ++(lv)->stats.trefcnt; \ } /* Macro to decrement total refcount (and optionally trace it) */ #define DECR_TREFCNT(lv) \ { \ assert(LV_IS_BASE_VAR(lv)); \ DBGRFCT((stderr, "\nDecrement trefcnt for lv_val at 0x"lvaddr" from %d to %d by %s line %d\n", \ (lv), (lv)->stats.trefcnt, (lv)->stats.trefcnt - 1, __FILE__, __LINE__)); \ --(lv)->stats.trefcnt; \ assert(0 <= (lv)->stats.trefcnt); \ } /* Macro to increment container refcount (and optionally trace it) */ #define INCR_CREFCNT(lv) \ { \ assert(LV_IS_BASE_VAR(lv)); \ DBGRFCT((stderr, "\nIncrement crefcnt for lv_val at 0x"lvaddr" from %d to %d by %s line %d\n", \ (lv), (lv)->stats.crefcnt, (lv)->stats.crefcnt + 1, __FILE__, __LINE__)); \ ++(lv)->stats.crefcnt; \ } /* Macro to decrement container refcount (and optionally trace it) */ #define DECR_CREFCNT(lv) \ { \ assert(LV_IS_BASE_VAR(lv)); \ DBGRFCT((stderr, "\nDecrement crefcnt for lv_val at 0x"lvaddr" from %d to %d by %s line %d\n", \ (lv), (lv)->stats.crefcnt, (lv)->stats.crefcnt - 1, __FILE__, __LINE__)); \ --(lv)->stats.crefcnt; \ assert(0 <= (lv)->stats.crefcnt); \ } /* There are three flavors of DECR_BASE_REF depending on the activities we need to persue. The first two flavors DECR_BASE_REF and DECR_BASE_REF_RQ take 2 parms (hashtable entry and lv_val addresses). Both of these do hashtable entry maint in addition to lv_val maint but do it in different ways. The DECR_BASE_REF macro's purpose is to leave the hashtable always pointing to a valid lv_val. If the one we are decrementing goes to zero, we can just zap that one and leave it there but if the refcnt is not zero, we can't do that. Since another command may follow the command doing the DECR_BASE_REF (e.g. KILL *), we can't leave the hash table entry with a null value since gtm_fetch() won't be called to fill it in so we must allocate a new lv_val for it. By contrast, with the DECR_BASE_REF_RQ macro, if the lv_val refcnt goes to zero, the lv_val is requeued and in either case, the hte address is cleared to make way for a new value. The 3rd flavor is the DCR_BASE_REF_NOSYM macro which is used for orphaned lv_vals not in a hashtable. This macro just requeues lv_vals that hit a refcnt of zero. */ #define LVP_KILL_SUBTREE_IF_EXISTS(lvp, dotpsave) \ { \ lvTree *lvt_child; \ \ assert(LV_IS_BASE_VAR(lvp)); \ assert(0 == (lvp)->stats.crefcnt); \ lvt_child = LV_GET_CHILD(lvp); \ if (NULL != lvt_child) \ { \ assert(((lvTreeNode *)(lvp)) == LVT_PARENT(lvt_child)); \ LV_CHILD(lvp) = NULL; \ lv_killarray(lvt_child, dotpsave); \ } \ } /* Macro to decrement a base var reference and do appropriate cleanup */ #define DECR_BASE_REF(tabent, lvp, dotpsave) \ { /* Perform reference count maintenance for base var */ \ lv_val *dbr_lvp; \ symval *sym; \ \ assert(LV_IS_BASE_VAR(lvp)); \ assert(0 < (lvp)->stats.trefcnt); \ DECR_TREFCNT(lvp); \ sym = LV_GET_SYMVAL(lvp); \ if (0 == (lvp)->stats.trefcnt) \ { /* This lv_val can be effectively killed and remain in hte */ \ LVP_KILL_SUBTREE_IF_EXISTS(lvp, dotpsave); \ assert(NULL == (lvp)->tp_var); \ LVVAL_INIT(lvp, sym); \ } else \ { /* lv_val otherwise still in use -- put a new one in this hte */ \ assert((lvp)->stats.trefcnt >= (lvp)->stats.crefcnt); \ dbr_lvp = lv_getslot(sym); \ DBGRFCT((stderr, "DECR_BASE_REF: Resetting hte 0x"lvaddr" from 0x"lvaddr" to 0x"lvaddr"\n", \ tabent, (lvp), dbr_lvp)); \ LVVAL_INIT(dbr_lvp, sym); \ tabent->value = dbr_lvp; \ } \ } /* Macro to decrement a base var reference and do appropriate cleanup except the tabent value is unconditionally * cleared and the lvval put on the free queue. Used when the tabent is about to be reused for a different lv. */ #define DECR_BASE_REF_RQ(tabent, lvp, dotpsave) \ { /* Perform reference count maintenance for base var */ \ assert(LV_IS_BASE_VAR(lvp)); \ assert(0 < (lvp)->stats.trefcnt); \ DECR_TREFCNT(lvp); \ DBGRFCT((stderr, "DECR_BASE_REF_RQ: Resetting hte 0x"lvaddr" from 0x"lvaddr" to NULL\n", \ tabent, tabent->value)); \ tabent->value = (void *)NULL; \ if (0 == (lvp)->stats.trefcnt) \ { /* This lv_val is done .. requeue it after it is killed */ \ LVP_KILL_SUBTREE_IF_EXISTS(lvp, dotpsave); \ LV_FREESLOT(lvp); \ } else \ assert((lvp)->stats.trefcnt >= (lvp)->stats.crefcnt); \ } /* Macro to decrement a base var reference and do appropriate cleanup except no hash table entry value cleanup is done. */ #define DECR_BASE_REF_NOSYM(lvp, dotpsave) \ { /* Perform reference count maintenance for base var */ \ assert(LV_IS_BASE_VAR(lvp)); \ assert(0 < (lvp)->stats.trefcnt); \ DECR_TREFCNT(lvp); \ if (0 == (lvp)->stats.trefcnt) \ { /* This lv_val is done .. requeue it after it is killed */ \ LVP_KILL_SUBTREE_IF_EXISTS(lvp, dotpsave); \ LV_FREESLOT(lvp); \ } else \ assert((lvp)->stats.trefcnt >= (lvp)->stats.crefcnt); \ } /* Macro to decrement an alias container reference and do appropriate cleanup */ #define DECR_AC_REF(lvp, dotpsave) \ { \ if (MV_ALIASCONT & (lvp)->v.mvtype) \ { /* Killing an alias container, perform reference count maintenance */ \ \ GBLREF uint4 dollar_tlevel; \ \ lv_val *lvref = (lv_val *)(lvp)->v.str.addr; \ assert(0 == (lvp)->v.str.len); \ assert(!LV_IS_BASE_VAR(lvp)); \ assert(lvref); \ assert(LV_IS_BASE_VAR(lvref)); \ assert(0 < lvref->stats.crefcnt); \ assert(0 < lvref->stats.trefcnt); \ if (dotpsave && dollar_tlevel && (NULL != lvref->tp_var) \ && !lvref->tp_var->var_cloned && (1 == lvref->stats.trefcnt)) \ /* Only clone (here) if target is going to be deleted by decrement */ \ TP_VAR_CLONE(lvref); \ DECR_CREFCNT(lvref); \ DECR_BASE_REF_NOSYM(lvref, dotpsave); \ } \ } /* Macro to mark nested symvals as having had alias activity. Mark nested symvals until we get * to a symval owning the lv_val specified. This loop will normally only run once except in the * case where the lv_val given is owned by a symval nested by an exclusive NEW. */ #define MARK_ALIAS_ACTIVE(lv_own_svlvl) \ { \ symval *sv; \ int4 lcl_own_svlvl; \ \ lcl_own_svlvl = lv_own_svlvl; \ for (sv = curr_symval; ((NULL != sv) && (sv->symvlvl >= lcl_own_svlvl)); sv = sv->last_tab) \ sv->alias_activity = TRUE; \ } /* The following *_CNTNRS_IN_TREE macros scan the supplied tree for container vars. Note that in debug mode, * even if "has_aliascont" is NOT set, we will still scan the array for containers but if one is found, then we will assert fail. * Note this means the processing is different for PRO and DBG builds in that this routine will not even be called in PRO if * the has_aliascont flag is not on in the base mval. But this allows us to check the integrity of the has_aliascont flag * in DBG because we will fail if ever a container is found in an array with the flag turned off. */ /* Macro to scan a lvTree for container vars and for each one, treat it as if it had been specified in a TP restart variable list * by setting it up to be cloned if deleted. This activity should nest so container vars that point to further trees should also * be scanned. */ #define TPSAV_CNTNRS_IN_TREE(lv_base) \ { \ lvTree *lvt; \ \ assert(LV_IS_BASE_VAR(lv_base)); \ if (lv_base->stats.tstartcycle != tstartcycle) \ { /* If haven't processed this lv_val for this transaction (or nested transaction */ \ lv_base->stats.tstartcycle = tstartcycle; \ /* Note it is possible that this lv_val has the current tstart cycle if there has been a restart. We still need \ to rescan the var anyway since one attempt can execute differently than a following attempt and thus create \ different variables for us to find -- if it has aliases in it that is. \ */ \ if ((NULL != (lvt = LV_GET_CHILD(lv_base))) PRO_ONLY(&& (lv_base)->has_aliascont)) \ { \ DBGRFCT((stderr, "\n## TPSAV_CNTNRS_IN_TREE: Beginning processing lvTree at 0x"lvaddr"\n", lv_base)); \ als_prcs_tpsav_cntnr(lvt); \ DBGRFCT((stderr, "\n## TPSAV_CNTNRS_IN_TREE: Finished processing lvTree at 0x"lvaddr"\n", lv_base)); \ } \ } else \ DBGRFCT((stderr, "\n## TPSAV_CNTNRS_IN_TREE: Bypassing lvTree at 0x"lvaddr" as already processed\n", lv_base)); \ } /* Macro similar to TPSAV_CNTNRS_IN_TREE() above but in this case, we know we want to increment the reference counts * for all found container var targets. They have already been saved (we will assert they have a tp_var!) and we just want to * reestablish the reference counts. This is used when a saved array is being restored and the containers in it need to have * their reference counts re-established. */ #define TPREST_CNTNRS_IN_TREE(lv_base) \ { \ lvTree *lvt; \ \ assert(LV_IS_BASE_VAR(lv_base)); \ if ((NULL != (lvt = LV_GET_CHILD(lv_base))) PRO_ONLY(&& (lv_base)->has_aliascont)) \ { \ DBGRFCT((stderr, "\n++ TPREST_CNTNRS_IN_TREE: Beginning processing lvTree at 0x"lvaddr"\n", lv_base)); \ als_prcs_tprest_cntnr(lvt); \ DBGRFCT((stderr, "\n++ TPREST_CNTNRS_IN_TREE: Finished processing lvTree at 0x"lvaddr"\n", lv_base)); \ } \ } /* Macro similar to TPREST_CNTNRS_IN_TREE() above but in this case we want to decrement the containers since we are in unwind processing */ #define TPUNWND_CNTNRS_IN_TREE(lv_base) \ { \ lvTree *lvt; \ \ assert(LV_IS_BASE_VAR(lv_base)); \ if ((NULL != (lvt = LV_GET_CHILD(lv_base))) PRO_ONLY(&& (lv_base)->has_aliascont)) \ { \ DBGRFCT((stderr, "\n-- TPUNWND_CNTNRS_IN_TREE: Beginning processing lvTree at 0x"lvaddr"\n", lv_base)); \ als_prcs_tpunwnd_cntnr(lvt); \ DBGRFCT((stderr, "\n-- TPUNWND_CNTNRS_IN_TREE: Finished processing lvTree at 0x"lvaddr"\n", lv_base)); \ } else \ DBGRFCT((stderr, "\n-- TPUNWND_CNTNRS_IN_TREE: Scan for lvTree at 0x"lvaddr" bypassed - no containers", lv_base));\ } /* Macro to scan a tree for container vars, delete what they point to and unmark the container so it is no longer a container */ #define KILL_CNTNRS_IN_TREE(lv_base) \ { \ lvTree *lvt; \ \ assert(LV_IS_BASE_VAR(lv_base)); \ if ((NULL != (lvt = LV_GET_CHILD(lv_base))) PRO_ONLY(&& (lv_base)->has_aliascont)) \ als_prcs_kill_cntnr(lvt); \ } /* Macro to scan an lvval for containers pointing to other structures that need to be scanned in xnew pop processing */ #define XNEWREF_CNTNRS_IN_TREE(lv_base) \ { \ lvTree *lvt; \ \ assert(LV_IS_BASE_VAR(lv_base)); \ if ((NULL != (lvt = LV_GET_CHILD(lv_base))) PRO_ONLY(&& (lv_base)->has_aliascont)) \ als_prcs_xnewref_cntnr(lvt); \ } /* Macro to mark the base frame of the current var as having a container */ #define MARK_CONTAINER_ONBOARD(lv_base) \ { \ assert(LV_IS_BASE_VAR(lv_base)); \ lv_base->has_aliascont = TRUE; \ } void als_lsymtab_repair(hash_table_mname *table, ht_ent_mname *table_base_orig, int table_size_orig); void als_check_xnew_var_aliases(symval *oldsymtab, symval *cursymtab); void als_zwrhtab_init(void); void als_prcs_tpsav_cntnr(lvTree *lvt); void als_prcs_tprest_cntnr(lvTree *lvt); void als_prcs_tpunwnd_cntnr(lvTree *lvt); void als_prcs_kill_cntnr(lvTree *lvt); void als_prcs_xnewref_cntnr(lvTree *lvt); ht_ent_mname *als_lookup_base_lvval(lv_val *lvp); zwr_alias_var *als_getzavslot(void); int als_lvval_gc(void); DBGALS_ONLY(void als_lvmon_output(void);) #endif /* !ALIAS_H_ */ fis-gtm-V6.0-003/sr_port/alias_funcs.c0000644000032200000250000015667712201176176016516 0ustar librarygtc/**************************************************************** * * * Copyright 2009, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #include #include #include "stack_frame.h" #include "op.h" #include "stp_parms.h" #include "lv_val.h" #include "error.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdskill.h" #include "gdscc.h" #include "filestruct.h" #include "jnl.h" /* needed for tp.h */ #include "tp.h" #include "tp_frame.h" #include "mv_stent.h" #include "alias.h" #include "gtm_malloc.h" #include "stringpool.h" #include "mmemory.h" #include "gtmio.h" #include "have_crit.h" GBLREF stack_frame *frame_pointer; GBLREF symval *curr_symval; GBLREF unsigned char *msp, *stackbase, *stacktop, *stackwarn; GBLREF mv_stent *mv_chain; GBLREF tp_frame *tp_pointer; GBLREF zwr_hash_table *zwrhtab; GBLREF trans_num local_tn; /* transaction number for THIS PROCESS */ GBLREF uint4 tstartcycle; GBLREF uint4 lvtaskcycle; /* lv_val cycle for misc lv_val related tasks */ GBLREF mstr **stp_array; GBLREF int stp_array_size; GBLREF lv_val *zsrch_var, *zsrch_dir1, *zsrch_dir2; GBLREF tp_frame *tp_pointer; GBLREF int4 SPGC_since_LVGC; /* stringpool GCs since the last dead-data GC */ GBLREF boolean_t suspend_lvgcol; GBLREF lv_xnew_var *xnewvar_anchor; GBLREF lv_xnew_ref *xnewref_anchor; GBLREF mval *alias_retarg; LITREF mname_entry null_mname_entry; /* Local routines -- not made static so they show up in pro core stack traces */ STATICFNDCL void als_xnew_killaliasarray(lvTree *lvt); STATICFNDCL void als_prcs_xnew_alias_cntnr(lvTree *lvt, symval *popdsymval, symval *cursymval); STATICFNDCL void als_prcs_markreached_cntnr(lvTree *lvt); CONDITION_HANDLER(als_check_xnew_var_aliases_ch); /* Define macros locally used by this routine only. General use macros are defined in alias.h */ /* Macro to decrement a base var reference. This lightweight version (of DECR_BASE_REF) used by "als_check_xnew_var_aliases" * is used to bypass most of the the LV_FREESLOT/LV_FLIST_ENQUEUE macro and do only reference count maint since the entire * symtab and all its lv_vals (lv_blks) are going to be released shortly. */ #define DECR_BASE_REF_LIGHT(lvp) \ { /* Perform reference count maintenance for base var */ \ lvTree *lvt_child; \ \ assert(LV_IS_BASE_VAR(lvp)); \ assert(0 < (lvp)->stats.trefcnt); \ DECR_TREFCNT(lvp); \ assert((lvp)->stats.trefcnt >= (lvp)->stats.crefcnt); \ if (0 == (lvp)->stats.trefcnt) \ { \ (lvp)->v.mvtype = 0; \ lvt_child = LV_GET_CHILD(lvp); \ if (lvt_child) \ { \ LV_CHILD(lvp) = NULL; \ als_xnew_killaliasarray(lvt_child); \ } \ } \ } /* Macro to decrement an alias container reference. This lightweight version used by "als_check_xnew_var_aliases" * is used to bypass the DECR_BASE_REF_NOSYM macro invocation (in most cases) and do only reference count maint * since the entire symtab and all its lv_vals (lv_blks) are going to be released shortly. Note this macro is * known to only be used on subscripted nodes hence the additional initial assert. */ #define DECR_AC_REF_LIGHT(LVP) \ { \ symval *lvp_sym, *lvref_sym; \ lv_val *lvp_base; \ \ assert(!LV_IS_BASE_VAR(LVP)); \ if (MV_ALIASCONT & (LVP)->v.mvtype) \ { /* Killing an alias container, perform reference count maintenance */ \ lv_val *lvref = (lv_val *)(LVP)->v.str.addr; \ assert(lvref); \ assert(LV_IS_BASE_VAR(lvref)); \ assert(0 == (LVP)->v.str.len); \ assert(0 < lvref->stats.crefcnt); \ assert(0 < lvref->stats.trefcnt); \ DECR_CREFCNT(lvref); \ lvref_sym = LV_GET_SYMVAL(lvref); \ lvp_base = LV_GET_BASE_VAR(LVP); \ lvp_sym = LV_GET_SYMVAL(lvp_base); \ if (lvref_sym == lvp_sym) \ { /* pointed to lvval owned by popd symval, use light flavor */ \ DECR_BASE_REF_LIGHT(lvref); \ } else \ { /* pointed to lvval owned by other symval, use full flavor */ \ DECR_BASE_REF_NOSYM(lvref, TRUE); \ } \ } \ } /* Macro to mark an lv_val as reachable and process its descendants if any. * Note that like the _CNTNRS_IN_TREE macros, in dbg mode, we will scan the array * for containers even if has_aliascont flag is FALSE. */ #define MARK_REACHABLE(lvp) \ { \ lvTree *lvt; \ symval *sym; \ \ assert((lvp)); \ /* Since this macro can be called in cases where the lv_val is NOT valid, such as in \ * the case an MVST_PVAL mv_stent entry with an mvs_val entry that has been deleted \ * by alias reassignment (see unw_mv_ent), we need to verify we have an actual lv_val \ * by the same methods used to build the lv_val list and only then check if this \ * lv_val has been processed yet. \ */ \ sym = LV_SYMVAL(lvp); \ if ((NULL != sym) && SYM_IS_SYMVAL(sym) && ((lvp)->stats.lvtaskcycle != lvtaskcycle)) \ { /* This lv_val has not been processed yet */ \ DBGRFCT((stderr, "\nMARK_REACHABLE: Marking lv 0x"lvaddr" as reachable\n", \ (lvp))); \ (lvp)->stats.lvtaskcycle = lvtaskcycle; /* Mark it */ \ if ((NULL != (lvt = LV_GET_CHILD(lvp))) PRO_ONLY(&& (lvp)->has_aliascont)) \ { /* And it has descendents to process */ \ DBGRFCT((stderr, "MARK_REACHABLE: Scanning same lv for containers\n")); \ als_prcs_markreached_cntnr(lvt); \ } \ } \ } /* Macro to clone an lv_val */ #define CLONE_LVVAL(oldlv, newlv, cursymval) \ { \ assert(LV_IS_BASE_VAR(oldlv)); \ newlv = lv_getslot(cursymval); \ *newlv = *oldlv; \ LV_SYMVAL(newlv) = cursymval; \ lv_var_clone(newlv, newlv); \ oldlv->v.mvtype = MV_LVCOPIED; \ oldlv->ptrs.copy_loc.newtablv = newlv; \ } /* Macro to initialize a ZWR_ZAV_BLK structure */ #define ZAV_BLK_INIT(zavb, zavbnext) \ (zavb)->next = (zavbnext); \ (zavb)->zav_base = (zavb)->zav_free = (zwr_alias_var *)((char *)(zavb) + SIZEOF(zwr_zav_blk)); \ (zavb)->zav_top = (zwr_alias_var *)((char *)(zavb)->zav_base + (SIZEOF(zwr_alias_var) * ZWR_ZAV_BLK_CNT)); /* Macro to run a given tree looking for container vars. Process what they point to in order to make sure what they point to * doesn't live in the symbol tree being popped. If so, move to the current tree (copying if necessary). If what is being pointed * to was not passed through then it will not be put into the symbol table but will instead just be data pointed to by the * container var. Like the _CNTNRS_IN_TREE macros, in dbg mode, we will scan the array for containers even if has_aliascont * flag is FALSE. */ #define RESOLV_ALIAS_CNTNRS_IN_TREE(LV_BASE, POPDSYMVAL, CURSYMVAL) \ { \ lvTree *lvt; \ \ if ((NULL != (lvt = LV_GET_CHILD(LV_BASE))) && ((LV_BASE)->stats.lvtaskcycle != lvtaskcycle) \ PRO_ONLY(&& (LV_BASE)->has_aliascont)) \ { \ (LV_BASE)->stats.lvtaskcycle = lvtaskcycle; \ als_prcs_xnew_alias_cntnr(lvt, POPDSYMVAL, CURSYMVAL); \ } \ } /* Routine to repair the l_symtab entries in the stack due to hash table expansion such that the * l_symtab entries no longer point to valid hash table entries. * * Note that the "repair" done by this routine depends on the special processing done in * expand_hashtab_mname (EXPAND_HASHTAB rtn in hashtab_implementation.h) which does not free the * old table and places the addresses of the new hash table entries in the the value of the old * hash table entries. This allows this routine to access the old table with the existing * l_symtab entries and pull the new values that should be put in the respective l_symtab * entries before it completes the cleanup and releases the old hash table. * * Operation - Loop through the stack and: * * 1) For each unique l_symtab, run through the entries in the l_symtab. * 2) If entry is null, skip. * 3) If entry falls within range of the old symbol table, load the address in it and verify * that it falls within the range of the new symbol table. * 4) If the entry does not fall within the range of the old symtab: * a) Stop the search as we must have run into an older symtab * b) If debug, assert fail if this is not the first_symbol in this l_symtab we have seen * since an l_symtab can only point to one symtab). * 5) Get new entry address from within the old entry. * 6) Debug only: Assert fail if the new entry address not in range of new symtab. * 7) Note that after procesing the stack to get to the l_symtab entries, we also process the * mv_stent types that contain hash table entry pointers and have to be processed in the same * fashion as the l_symtab entries. This processing saves us the hashtable lookup necessary to * pop NEW'd or parameter values when undoing a stack level and restoring previous values. */ void als_lsymtab_repair(hash_table_mname *table, ht_ent_mname *table_base_orig, int table_size_orig) { int htcnt; boolean_t done; mv_stent *mv_st_ent; ht_ent_mname *table_top_orig, **last_lsym_hte, **htep, *htenew; stack_frame *fp, *fpprev; DEBUG_ONLY(boolean_t first_sym;) assert(table); assert(table_base_orig); assert(table_base_orig != curr_symval->h_symtab.base); table_top_orig = table_base_orig + table_size_orig; last_lsym_hte = NULL; done = FALSE; fp = frame_pointer; assert(frame_pointer); do { /* Once through for each stackframe using the same symbol table. Note this loop is similar * to the stack frame loop in op_clralsvars.c. */ if (fp->l_symtab != last_lsym_hte) { /* Different l_symtab than last time (don't want to update twice) */ last_lsym_hte = fp->l_symtab; if (htcnt = fp->vartab_len) /* Note assignment */ { /* Only process non-zero length l_symtabs */ DEBUG_ONLY(first_sym = TRUE); for (htep = fp->l_symtab; htcnt; --htcnt, ++htep) { if (NULL == *htep) continue; if (*htep < table_base_orig || *htep >= table_top_orig) { /* Entry doesn't point to the current symbol table */ assert(first_sym); done = TRUE; break; } htenew = (ht_ent_mname *)((*htep)->value); /* Pick up entry we should now use */ assert(htenew >= table->base && htenew < (table->base + table->size)); *htep = htenew; DEBUG_ONLY(first_sym = FALSE); } } } fpprev = fp; fp = fp->old_frame_pointer; if (done) break; if (SFF_CI & fpprev->flags) { /* Callins needs to be able to crawl past apparent end of stack to earlier stack segments. * We should be in the base frame now. See if an earlier frame exists. * Note we don't worry about trigger base frames here because triggers *always* have a * different symbol table - previous symbol tables and stack levels are not affected. */ fp = *(stack_frame **)(fp + 1); /* Backups up to "prev pointer" created by base_frame() */ if ((NULL == fp) || (fp >= (stack_frame *)stackbase) || (fp < (stack_frame *)stacktop)) break; /* Pointer not within the stack -- must be earliest occurence */ } } while(fp); /* Next, check the mv_stents for the stackframes we processed. Certain mv_stents also have hash * table references in them that need repair. */ for (mv_st_ent = mv_chain; mv_st_ent < (mv_stent *)(fp ? fp : fpprev); /* Last stack frame actually processed */ mv_st_ent = (mv_stent *)(mv_st_ent->mv_st_next + (char *)mv_st_ent)) { switch (mv_st_ent->mv_st_type) { /* The types processed here contain hash table pointers that need to be modified */ case MVST_NTAB: htep = &mv_st_ent->mv_st_cont.mvs_ntab.hte_addr; break; case MVST_PVAL: htep = &mv_st_ent->mv_st_cont.mvs_pval.mvs_ptab.hte_addr; break; case MVST_NVAL: htep = &mv_st_ent->mv_st_cont.mvs_nval.mvs_ptab.hte_addr; break; default: continue; } if (NULL == *htep) continue; if ((*htep < table_base_orig) || (*htep >= table_top_orig)) /* Entry doesn't point to the current symbol table so ignore it since it didn't change */ continue; htenew = (ht_ent_mname *)((*htep)->value); /* Pick up entry we should now use */ assert((htenew >= table->base) && (htenew < (table->base + table->size))); *htep = htenew; } /* For debug at least make unusable in case any stragglers point to it -- even though we are somewhat duplicating * the SmInitAlloc gtmdgblvl flag here, this is so critical for debugging we want to do this even when general * checking is not being done. SE 09/2008 */ DEBUG_ONLY(memset(table_base_orig, 0xfe, table_size_orig * SIZEOF(ht_ent_mname))); } /* Local routine! condition handler whose sole function is to turn off the flag that says we are in "als_check_xnew_var_alias" */ CONDITION_HANDLER(als_check_xnew_var_aliases_ch) { START_CH; suspend_lvgcol = FALSE; NEXTCH; } /* When an xNEW'd symtab is popped, and there are alias concerns, this routine is called to make things right. Things that * can be wrong: * 1) If a variable was passed through to the new symtab and then was aliased to a var that belonged to the new symbol table, * the lv_val in the old symtab was released and a new one assigned in the new symbol table. We have to: * a) copy that value back to the previous symtab and * b) we have to fix the reference count since the alias owned by the new symtab is going away. * 2) If a variable is passed through to the new symtab and within that variable an alias container is created that points * to a var in the newer symtab we need to copy that var/array back to the older symtab so the value remains. * 3) This gets more interesting to deal with when that var is also aliased by a passed through variable (combining issues 1 & 2). * * Operation: * 1) When the new symtab was created by op_xnew, if there were variables that were passed through, they are recorded in the * symtab chained from xnew_var_list. * 2) Go through that list of variables, lookup each in the popped symbol table and change the hash table entries to deleted * so those entries are not found in subsequent scans. * 3) Do a more simplistic kill-alias-all in the popped symtab. This involves the following: * a) Run the hash table looking for aliased variables. If found, do the reference count maintenance but don't worry about * deleting any data since it will all go away after we return and unw_mv_ent() releases the symbol table and lv_blk chains. * b) While running the hash table, run any variable trees we find anchored. * 4) Go through the list of forwarded vars again (xnew_var_list) in the popped symval and see if any of the lv_vals are owned * by the symval being popped. If they are, then the lv_vals involved need to be copied to lv_vals owned by the (now) * current symtab because the popped symtab's lv_vals will be released by unw_mv_ent() when we return. Note that this also * involves going through the tree of these vars in case any container vars point to an array that is not being dealt with * in some fashion by one of the other vars we passed through. We avoid processing arrays multiple times by marking them * with an incremented lvtaskval. * 5) Go through the list of referenced lv_vals (via containers of xnew_var_list vars) by traversing the xnew_ref_list if it * exists. These vars were recorded because we may not be able to get to them still just by traversing the reference list vars * so they were pre-recorded so we could scan the worst case of vars that could have containers pointing to the symtab about * to be popped. * 6) If a pending alias return value exists, check it to see if it also needs to be processed. * * Note: to prevent re-scanning of already scanned array, this routine uses the lvtaskcycle value. To do this, we use the * suspend_lvgcol global variable to tell "stp_gcol" to not do LVGC processing (which also uses lvtaskcycle). */ void als_check_xnew_var_aliases(symval *popdsymval, symval *cursymval) { lv_xnew_var *xnewvar, *xnewvar_next; lv_xnew_ref *xnewref, *xnewref_next; ht_ent_mname *tabent; hash_table_mname *popdsymtab, *cursymtab; ht_ent_mname *htep, *htep_top; lv_val *lv, *prevlv, *currlv, *popdlv; lv_val *newlv, *oldlv; boolean_t bypass_lvscan, bypass_lvrepl; DBGRFCT_ONLY(mident_fixed vname;) ESTABLISH(als_check_xnew_var_aliases_ch); suspend_lvgcol = TRUE; assert(NULL != popdsymval); assert(NULL != cursymval); assert((NULL != popdsymval->xnew_var_list) || (NULL != alias_retarg)); DBGRFCT((stderr, "\nals_check_xnew_var_aliases: Beginning xvar pop processing\n")); /* Step 2: (step 1 done in op_xnew()) - Run the list of vars that were passed through the xnew and remove them * from the popped hash table so they can not be found by the step 3 scan below - meaning we won't mess with the * reference counts of these entries but we will record their locations so we can process them in step 4. */ popdsymtab = &popdsymval->h_symtab; cursymtab = &cursymval->h_symtab; for (xnewvar = popdsymval->xnew_var_list; xnewvar; xnewvar = xnewvar->next) { tabent = lookup_hashtab_mname(popdsymtab, &xnewvar->key); assert(tabent); xnewvar->lvval = (lv_val *)tabent->value; /* Cache lookup results for 2nd pass in step 4 */ delete_hashtab_ent_mname(popdsymtab, tabent); } /* Step 3: Run popped hash table undoing alias references. */ DBGRFCT((stderr, "als_check_xnew_var_aliases: Step 3 - running popped symtab tree undoing local refcounts\n")); for (htep = popdsymtab->base, htep_top = popdsymtab->top; htep < htep_top; htep++) { if (HTENT_VALID_MNAME(htep, lv_val, lv)) DECR_BASE_REF_LIGHT(lv); } /* Step 4: See what, if anything, needs to be copied from popped level to current level. There are 3 possible * cases here. Note in all cases, we must decrement the use counters of prevlv since they were incremented in * op_xnew to keep things from disappearing prematurely (we don't want the LVs we saved to be scrapped and re-used * so we make sure they stay around). * * Vars used: * * prevlv == lv from the current symbol table. * currlv == lv we are going to eventually put into the current symbol table * popdlv == lv from the popped symbol table * * Cases follow: * * Condition Action * * a) prevlv == popdlv Scan prevlv for alias containers pointing to popped symtab. * b) prevlv != popdlv && popdlv in popd symtab. Clone popdlv into currlv & do alias container scan. * c) prevlv != popdlv && popdlv not in popd symtab. Same as case (a). Note this includes the case where popdlv * already resides in cursymtab. */ DBGRFCT((stderr, "als_check_xnew_var_aliases: Step 4 - beginning unwind scan of passed through vars\n")); INCR_LVTASKCYCLE; for (xnewvar = popdsymval->xnew_var_list; xnewvar; xnewvar = xnewvar_next) { bypass_lvscan = bypass_lvrepl = FALSE; tabent = lookup_hashtab_mname(cursymtab, &xnewvar->key); assert(tabent); /* Had better be there since it was passed in thru the exclusive new */ DBGRFCT_ONLY( memcpy(vname.c, tabent->key.var_name.addr, tabent->key.var_name.len); vname.c[tabent->key.var_name.len] = '\0'; ); prevlv = (lv_val *)tabent->value; popdlv = xnewvar->lvval; /* Value of this var in popped symtab */ DBGRFCT((stderr, "als_check_xnew_var_aliases: var '%s' prevlv: 0x"lvaddr" popdlv: 0x"lvaddr"\n", &vname.c, prevlv, popdlv)); if (prevlv == popdlv) { /* Case (a) - Just do the scan below */ currlv = prevlv; bypass_lvrepl = TRUE; } else if (popdsymval == LV_GET_SYMVAL(popdlv)) { /* Case (b) - Clone the var and tree into blocks owned by current symtab with the caveat that we need not * do this if the array has already been cloned (because more than one var that was passed through it * pointing to it. */ if (MV_LVCOPIED == popdlv->v.mvtype) { /* This lv_val has been copied over already so use that pointer instead to put into the * current hash table. */ currlv = popdlv->ptrs.copy_loc.newtablv; assert(LV_GET_SYMVAL(currlv) == cursymval); bypass_lvscan = TRUE; /* lv_val would have already been scanned */ DBGRFCT((stderr, "als_check_xnew_var_aliases: lv already copied so setting currlv to 0x"lvaddr"\n", currlv)); } else { assert(LV_IS_BASE_VAR(popdlv)); /* lv_val is owned by the popped symtab .. clone it to the new current tree */ CLONE_LVVAL(popdlv, currlv, cursymval); DBGRFCT((stderr, "als_check_xnew_var_aliases: lv has been cloned from 0x"lvaddr" to 0x"lvaddr"\n", popdlv, currlv)); } } else { /* Case (c) - same as (a) except we do replace the lv in cursymtab */ assert(LV_IS_BASE_VAR(popdlv)); currlv = popdlv; } if (!bypass_lvscan) { /* Need to run this tree (if any) to look for container vars buried within */ DBGRFCT((stderr, "als_check_xnew_var_aliases: potentially scanning lv 0x"lvaddr"\n", currlv)); RESOLV_ALIAS_CNTNRS_IN_TREE(currlv, popdsymval, cursymval); } if (1 < prevlv->stats.trefcnt) /* If prevlv is going to be around after we drop op_xnew's refcnt bumps, make sure it gets processed. * If it was processed above, then it is marked such and the macro will bypass processing it again. */ RESOLV_ALIAS_CNTNRS_IN_TREE(prevlv, popdsymval, cursymval); DECR_CREFCNT(prevlv); /* undo bump by op_xnew */ if (!bypass_lvrepl) { /* Replace the lvval in the current symbol table */ DBGRFCT((stderr, "als_check_xnew_var_aliases: Resetting variable '%s' hte at 0x"lvaddr" from 0x"lvaddr " to 0x"lvaddr"\n", &vname.c, tabent, prevlv, currlv)); tabent->value = (void *)currlv; } assert(1 <= prevlv->stats.trefcnt); /* verify op_xnew's bump is still there (may be only one) */ DECR_BASE_REF_NOSYM(prevlv, TRUE); /* undo bump by op_xnew */ xnewvar_next = xnewvar->next; xnewvar->next = xnewvar_anchor; xnewvar_anchor = xnewvar; } /* Step 5: See if anything on the xnew_ref_list needs to be handled */ DBGRFCT((stderr, "als_check_xnew_var_aliases: Step 5: Process xnew_ref_list if any\n")); for (xnewref = popdsymval->xnew_ref_list; xnewref; xnewref = xnewref_next) { prevlv = xnewref->lvval; DBGRFCT((stderr, "als_check_xnew_var_aliases: xnewref-prevlv: 0x"lvaddr"\n", prevlv)); DECR_CREFCNT(prevlv); /* Will remove the trefcnt in final desposition below */ /* Only do the scan if the reference count is greater than 1 since we are going to remove the * refcnts added by op_xnew as we finish here. So if the var is going away anyway, no need * to scan. */ if (1 < prevlv->stats.trefcnt) { /* Process the array */ DBGRFCT((stderr, "als_check_xnew_var_aliases: potentially scanning lv 0x"lvaddr"\n", prevlv)); RESOLV_ALIAS_CNTNRS_IN_TREE(prevlv, popdsymval, cursymval); } else DBGRFCT((stderr, "als_check_xnew_var_aliases: prevlv was deleted\n")); /* Remove refcnt and we are done */ DECR_BASE_REF_NOSYM(prevlv, TRUE); xnewref_next = xnewref->next; xnewref->next = xnewref_anchor; xnewref_anchor = xnewref; } /* Step 6: Check if a pending alias return value exists and if so if it needs to be processed. * This type of value is created by unw_retarg() as the result of a "QUIT *" statement. It is an alias container * mval that lives in the compiler temps of the caller with a pointer in the stack frame of the callee. Since this * mval-container is just an mval and not an lv_val, we have to largely do similar processing to the * "als_prcs_xnew_alias_cntnr" with this block type difference in mind. */ if (NULL != alias_retarg) { assert(0 != (MV_ALIASCONT & alias_retarg->mvtype)); oldlv = (lv_val *)alias_retarg->str.addr; if (MV_LVCOPIED == oldlv->v.mvtype) { /* This lv_val has been copied over already so use that pointer instead */ newlv = oldlv->ptrs.copy_loc.newtablv; alias_retarg->str.addr = (char *)newlv; /* Replace container ptr */ DBGRFCT((stderr, "\nals_check_xnew_var_aliases: alias retarg var found - referenced array already copied" " - Setting pointer in aliascont mval 0x"lvaddr" to lv 0x"lvaddr"\n", alias_retarg, newlv)); } else { assert(LV_IS_BASE_VAR(oldlv)); if (popdsymval == LV_SYMVAL(oldlv)) { /* lv_val is owned by the popped symtab .. clone it to the new current tree */ CLONE_LVVAL(oldlv, newlv, cursymval); alias_retarg->str.addr = (char *)newlv; /* Replace container ptr */ DBGRFCT((stderr, "\nals_check_xnew_var_aliases: alias retarg var found - aliascont mval 0x"lvaddr " being reset to point to lv 0x"lvaddr" which is a clone of lv 0x"lvaddr"\n", alias_retarg, newlv, oldlv)); } else { /* lv_val is owned by current or older symval .. just use it in the subsequent scan in case it * leads us to other lv_vals owned by the popped symtab. */ DBGRFCT((stderr, "\nals_check_xnew_var_aliases: alias retarg var found - aliascont mval 0x"lvaddr " just being (potentially) scanned for container vars\n", alias_retarg)); newlv = oldlv; } RESOLV_ALIAS_CNTNRS_IN_TREE(newlv, popdsymval, cursymval); } } DBGRFCT((stderr, "als_check_xnew_var_aliases: Completed xvar pop processing\n")); suspend_lvgcol = FALSE; REVERT; } /* Local routine! * This routine is basically a slightly lightweight lv_killarray() that goes through a given tree looking for container vars * and performing the necessary reference count cleanup as well as freeing the lv tree nodes but wont go through the * bother of hashtable maintenance since the hashtable is anyways going away as part of the symbol table pop. */ STATICFNDEF void als_xnew_killaliasarray(lvTree *lvt) { lvTreeNode *node, *nextnode; lvTree *tmplvt; DEBUG_ONLY( lv_val *lv; assert(NULL != lvt); lv = (lv_val *)LVT_PARENT(lvt); assert(NULL == LV_CHILD(lv)); /* Owner lv's children pointer MUST be NULL! */ /* See comment in lv_killarray for why this is necessary */ ) /* Iterate through the tree in post-order fashion. Doing it in-order or pre-order has issues since we would have * freed up nodes in the tree but would need to access links in them to get at the NEXT node. */ for (node = lvAvlTreeFirstPostOrder(lvt); NULL != node; node = nextnode) { nextnode = lvAvlTreeNextPostOrder(node); /* determine "nextnode" before freeing "node" */ assert(NULL != node); tmplvt = LV_CHILD(node); if (NULL != tmplvt) { LV_CHILD(node) = NULL; als_xnew_killaliasarray(tmplvt); } DECR_AC_REF_LIGHT(((lv_val *)node)); /* Decrement alias contain ref and cleanup if necessary */ /* If node points to an "lv_val", we need to do a heavyweight LV_FREESLOT call to free up the lv_val. * But we instead do a simple "LVTREENODE_FREESLOT" call because we are guaranteed node points to a "lvTreeNode" * (i.e. it is a subscripted lv and never the base lv). Assert that. */ assert(!LV_IS_BASE_VAR(node)); LVTREENODE_FREESLOT(node); } LVTREE_FREESLOT(lvt); } /* Local routine! * Routine to process an alias container found in a node of a var being "returned" back through an exclusive new. * We may have to move the data. */ STATICFNDEF void als_prcs_xnew_alias_cntnr(lvTree *lvt, symval *popdsymval, symval *cursymval) { lvTree *lvt_child; lvTreeNode *node; lv_val *newlv, *oldlv; assert(NULL != lvt); /* caller should not call if no subtree */ /* In the case of lv_killarray, the only option we have is to do post-order traversal since we are freeing * nodes in the tree as we traverse. But in this case, we dont change the tree structure so we are free to * choose any order. We choose in-order as that is faster than post-order. */ for (node = lvAvlTreeFirst(lvt); NULL != node; node = lvAvlTreeNext(node)) { if (node->v.mvtype & MV_ALIASCONT) { assert(lvt->base_lv->has_aliascont); assert(!LV_IS_BASE_VAR(node)); oldlv = (lv_val *)node->v.str.addr; assert(NULL != oldlv); assert(LV_IS_BASE_VAR(oldlv)); if (MV_LVCOPIED == oldlv->v.mvtype) { /* This lv_val has been copied over already so use that pointer instead */ newlv = oldlv->ptrs.copy_loc.newtablv; assert(LV_IS_BASE_VAR(newlv)); node->v.str.addr = (char *)newlv; /* Replace container ptr */ DBGRFCT((stderr, "\nals_prcs_xnew_alias_cntnr: aliascont var found - referenced array already " "copied - Setting pointer in aliascont lv 0x"lvaddr" to lv 0x"lvaddr"\n", node, newlv)); } else { assert(LV_IS_BASE_VAR(oldlv)); if (popdsymval == LV_SYMVAL(oldlv)) { /* lv_val is owned by the popped symtab .. clone it to the new current tree */ CLONE_LVVAL(oldlv, newlv, cursymval); assert(LV_IS_BASE_VAR(newlv)); node->v.str.addr = (char *)newlv; /* Replace container ptr */ DBGRFCT((stderr, "\nals_prcs_xnew_alias_cntnr: aliascont var found - aliascont lv 0x"lvaddr " being reset to point to lv 0x"lvaddr" which is a clone of lv 0x"lvaddr"\n", node, newlv, oldlv)); } else { /* lv_val is owned by current or older symval .. just use it in the subsequent scan in case * it leads us to other lv_vals owned by the popped symtab. */ DBGRFCT((stderr, "\nals_prcs_xnew_alias_cntnr: aliascont var found - aliascont lv 0x"lvaddr " just being (potentially) scanned for container vars\n", node)); newlv = oldlv; } RESOLV_ALIAS_CNTNRS_IN_TREE(newlv, popdsymval, cursymval); } } lvt_child = LV_GET_CHILD(node); if (NULL != lvt_child) /* Descend recursively down this tree as well */ als_prcs_xnew_alias_cntnr(lvt_child, popdsymval, cursymval); } } /* Routine to process an alias container found in an array being "saved" by TSTART (op_tstart). We need to set this array up * so it gets copied just like op_tstart does for the base variables that are specified in it. In addition, this new array * itself needs to be scanned so if it points to anything, that too gets saved if modified (all handled by * TP_SAVE_RESTART_VAR macro). */ void als_prcs_tpsav_cntnr(lvTree *lvt) { lvTree *lvt_child; lvTreeNode *node; lv_val *cntnr_lv_base; assert(NULL != lvt); /* caller should not call if no subtree */ /* In the case of lv_killarray, the only option we have is to do post-order traversal since we are freeing * nodes in the tree as we traverse. But in this case, we dont change the tree structure so we are free to * choose any order. We choose in-order as that is faster than post-order. */ for (node = lvAvlTreeFirst(lvt); NULL != node; node = lvAvlTreeNext(node)) { if (node->v.mvtype & MV_ALIASCONT) { assert(lvt->base_lv->has_aliascont); assert(!LV_IS_BASE_VAR(node)); cntnr_lv_base = (lv_val *)node->v.str.addr; /* Extract container pointer */ assert(NULL != cntnr_lv_base); assert(LV_IS_BASE_VAR(cntnr_lv_base)); assert(1 <= cntnr_lv_base->stats.trefcnt); assert(1 <= cntnr_lv_base->stats.crefcnt); if (NULL == cntnr_lv_base->tp_var) { /* Save this var if it hasn't already been saved */ assert(cntnr_lv_base->stats.tstartcycle != tstartcycle); DBGRFCT((stderr, "\ntpSAV_container: Container at 0x"lvaddr " refers to lv 0x"lvaddr" -- Creating tpsav block\n", node, cntnr_lv_base)); TP_SAVE_RESTART_VAR(cntnr_lv_base, tp_pointer, &null_mname_entry); INCR_CREFCNT(cntnr_lv_base); /* 2nd increment for reference via a container node */ INCR_TREFCNT(cntnr_lv_base); if (LV_HAS_CHILD(cntnr_lv_base)) TPSAV_CNTNRS_IN_TREE(cntnr_lv_base); } else { /* If not saving it, we still need to bump the ref count(s) for this reference and * process any children if we have't already seen this node (taskcycle check will tell us this). */ DBGRFCT((stderr, "\ntpSAV_container: Container at 0x"lvaddr" refers to lv 0x"lvaddr " -- Incrementing refcnts\n", node, cntnr_lv_base)); INCR_CREFCNT(cntnr_lv_base); INCR_TREFCNT(cntnr_lv_base); assert(0 < cntnr_lv_base->stats.trefcnt); assert(0 < cntnr_lv_base->stats.crefcnt); if (cntnr_lv_base->stats.tstartcycle != tstartcycle) { DBGRFCT((stderr, "\ntpSAV_container: .. Container at 0x"lvaddr" refers to lv 0x"lvaddr " -- processing tree\n", node, cntnr_lv_base)); if (LV_HAS_CHILD(cntnr_lv_base)) TPSAV_CNTNRS_IN_TREE(cntnr_lv_base); } else { DBGRFCT((stderr, "\ntpSAV_container: .. Container at 0x"lvaddr" refers to lv 0x"lvaddr " -- Already processed -- bypassing\n", node, cntnr_lv_base)); } } } lvt_child = LV_GET_CHILD(node); if (NULL != lvt_child) /* Descend recursively down this tree as well */ als_prcs_tpsav_cntnr(lvt_child); } } /* For a given container var found in the tree we need to re-establish the reference counts for the base var * the container is pointing to. Used during a local var restore on a TP restart. */ void als_prcs_tprest_cntnr(lvTree *lvt) { lvTree *lvt_child; lvTreeNode *node; lv_val *cntnr_lv_base; assert(NULL != lvt); /* caller should not call if no subtree */ /* In the case of lv_killarray, the only option we have is to do post-order traversal since we are freeing * nodes in the tree as we traverse. But in this case, we dont change the tree structure so we are free to * choose any order. We choose in-order as that is faster than post-order. */ for (node = lvAvlTreeFirst(lvt); NULL != node; node = lvAvlTreeNext(node)) { if (node->v.mvtype & MV_ALIASCONT) { assert(lvt->base_lv->has_aliascont); assert(!LV_IS_BASE_VAR(node)); cntnr_lv_base = (lv_val *)node->v.str.addr; /* Extract container pointer */ assert(NULL != cntnr_lv_base); assert(LV_IS_BASE_VAR(cntnr_lv_base)); assert(1 <= cntnr_lv_base->stats.trefcnt); assert(1 <= cntnr_lv_base->stats.crefcnt); assert(cntnr_lv_base->tp_var); DBGRFCT((stderr, "\ntpREST_cntnr_node: Processing container at 0x"lvaddr"\n", node)); INCR_CREFCNT(cntnr_lv_base); INCR_TREFCNT(cntnr_lv_base); assert(0 < (cntnr_lv_base)->stats.trefcnt); assert(0 < (cntnr_lv_base)->stats.crefcnt); } lvt_child = LV_GET_CHILD(node); if (NULL != lvt_child) /* Descend recursively down this tree as well */ als_prcs_tprest_cntnr(lvt_child); } } /* For a given container, decrement the ref count of the creature it points to. Part of unwinding an unmodified * tp saved variable. */ void als_prcs_tpunwnd_cntnr(lvTree *lvt) { lvTree *lvt_child; lvTreeNode *node; lv_val *cntnr_lv_base; assert(NULL != lvt); /* caller should not call if no subtree */ /* In the case of lv_killarray, the only option we have is to do post-order traversal since we are freeing * nodes in the tree as we traverse. But in this case, we dont change the tree structure so we are free to * choose any order. We choose in-order as that is faster than post-order. */ for (node = lvAvlTreeFirst(lvt); NULL != node; node = lvAvlTreeNext(node)) { if (node->v.mvtype & MV_ALIASCONT) { assert(lvt->base_lv->has_aliascont); assert(!LV_IS_BASE_VAR(node)); cntnr_lv_base = (lv_val *)node->v.str.addr; /* Extract container pointer */ assert(NULL != cntnr_lv_base); assert(LV_IS_BASE_VAR(cntnr_lv_base)); assert(1 <= cntnr_lv_base->stats.trefcnt); assert(1 <= cntnr_lv_base->stats.crefcnt); /* Note we cannot assert cntnr_lv_base->tp_var here since the tp_var node may have already been freed and * cleared by unwind processing of the base var itself. We just have to undo our counts here and keep going. */ DBGRFCT((stderr, "\ntpUNWND_cntnr_node: Processing container at 0x"lvaddr"\n", cntnr_lv_base)); DECR_CREFCNT(cntnr_lv_base); DECR_BASE_REF_NOSYM(cntnr_lv_base, FALSE); } lvt_child = LV_GET_CHILD(node); if (NULL != lvt_child) /* Descend recursively down this tree as well */ als_prcs_tpunwnd_cntnr(lvt_child); } } /* This routine deletes the data pointed to by the lv_val and removes the container flag from the value making it just * a regular NULL/0 value. */ void als_prcs_kill_cntnr(lvTree *lvt) { lvTree *lvt_child; lvTreeNode *node; lv_val *cntnr_lv_base; assert(NULL != lvt); /* caller should not call if no subtree */ /* In the case of lv_killarray, the only option we have is to do post-order traversal since we are freeing * nodes in the tree as we traverse. But in this case, we dont change the tree structure so we are free to * choose any order. We choose in-order as that is faster than post-order. */ for (node = lvAvlTreeFirst(lvt); NULL != node; node = lvAvlTreeNext(node)) { if (node->v.mvtype & MV_ALIASCONT) { assert(lvt->base_lv->has_aliascont); assert(!LV_IS_BASE_VAR(node)); cntnr_lv_base = (lv_val *)node->v.str.addr; assert(NULL != cntnr_lv_base); assert(LV_IS_BASE_VAR(cntnr_lv_base)); node->v.mvtype &= ~MV_ALIASCONT; DECR_CREFCNT(cntnr_lv_base); DECR_BASE_REF_NOSYM(cntnr_lv_base, TRUE); } lvt_child = LV_GET_CHILD(node); if (NULL != lvt_child) /* Descend recursively down this tree as well */ als_prcs_kill_cntnr(lvt_child); } } /* Local routine! * This routine checks if the supplied container points to an lv_val that is already marked as having been processd in this pass. * If not, the lv_val is marked and processed recursively. */ STATICFNDEF void als_prcs_markreached_cntnr(lvTree *lvt) { lvTree *lvt_child; lvTreeNode *node; lv_val *cntnr_lv_base; assert(NULL != lvt); /* caller should not call if no subtree */ /* In the case of lv_killarray, the only option we have is to do post-order traversal since we are freeing * nodes in the tree as we traverse. But in this case, we dont change the tree structure so we are free to * choose any order. We choose in-order as that is faster than post-order. */ for (node = lvAvlTreeFirst(lvt); NULL != node; node = lvAvlTreeNext(node)) { if (node->v.mvtype & MV_ALIASCONT) { assert(lvt->base_lv->has_aliascont); assert(!LV_IS_BASE_VAR(node)); cntnr_lv_base = (lv_val *)node->v.str.addr; assert(NULL != cntnr_lv_base); assert(LV_IS_BASE_VAR(cntnr_lv_base)); MARK_REACHABLE(cntnr_lv_base); } lvt_child = LV_GET_CHILD(node); if (NULL != lvt_child) /* Descend recursively down this tree as well */ als_prcs_markreached_cntnr(lvt_child); } } /* Function to scan an lvval for containers pointing to other structures that need to be scanned in xnew pop processing. * This goes through the entire tree of lv nodes looking for containers and if it finds any, it finds the base var pointed * to by the container if it has not already been processed in this pass (as determined by lvtaskcycle). Processing includes * incrementing refcnts and creating an lv_xnew_ref entry for the base var so we can check it again when the symtab pops to * see if any containers were created in them that point to the symtab being popped. */ void als_prcs_xnewref_cntnr(lvTree *lvt) { lvTree *lvt_child; lvTreeNode *node; lv_val *cntnr_lv_base; lv_xnew_ref *xnewref; assert(NULL != lvt); /* caller should not call if no subtree */ /* In the case of lv_killarray, the only option we have is to do post-order traversal since we are freeing * nodes in the tree as we traverse. But in this case, we dont change the tree structure so we are free to * choose any order. We choose in-order as that is faster than post-order. */ for (node = lvAvlTreeFirst(lvt); NULL != node; node = lvAvlTreeNext(node)) { if (node->v.mvtype & MV_ALIASCONT) { assert(lvt->base_lv->has_aliascont); assert(!LV_IS_BASE_VAR(node)); cntnr_lv_base = (lv_val *)node->v.str.addr; assert(NULL != cntnr_lv_base); assert(LV_IS_BASE_VAR(cntnr_lv_base)); if (cntnr_lv_base->stats.lvtaskcycle != lvtaskcycle) { INCR_CREFCNT(cntnr_lv_base); INCR_TREFCNT(cntnr_lv_base); cntnr_lv_base->stats.lvtaskcycle = lvtaskcycle; if (NULL != xnewref_anchor) { /* Reuse entry from list */ xnewref = xnewref_anchor; xnewref_anchor = xnewref->next; } else { /* Malloc an entry. Note that these blocks are put back on the chain anchored at the * xnewref_anchor global in function "als_check_xnew_var_aliases". They are not freed * since xnews typically happen in subroutines for temporary periods making the * likelihood of block reuse high. Also they are small and typically few in number. */ xnewref = (lv_xnew_ref *)malloc(SIZEOF(lv_xnew_ref)); } xnewref->lvval = cntnr_lv_base; xnewref->next = curr_symval->xnew_ref_list; curr_symval->xnew_ref_list = xnewref; if (LV_HAS_CHILD(cntnr_lv_base)) XNEWREF_CNTNRS_IN_TREE(cntnr_lv_base); } } lvt_child = LV_GET_CHILD(node); if (NULL != lvt_child) /* Descend recursively down this tree as well */ als_prcs_xnewref_cntnr(lvt_child); } } /* Initialize ZWRite hash table structures used when ZWRiting in an aliased variable environment */ void als_zwrhtab_init(void) { zwr_zav_blk *zavb, *zavb_next; if (zwrhtab && zwrhtab->cleaned) return; if (NULL == zwrhtab) { /* none yet .. allocate and init one */ zwrhtab = (zwr_hash_table *)malloc(SIZEOF(zwr_hash_table)); zwrhtab->first_zwrzavb = NULL; init_hashtab_addr(&zwrhtab->h_zwrtab, ZWR_HTAB_INIT_SIZE, HASHTAB_COMPACT, HASHTAB_SPARE_TABLE); } else { /* Have one, reinitialize it */ assert(zwrhtab->first_zwrzavb); zavb = zwrhtab->first_zwrzavb; if (zavb) { for (zavb_next = zavb->next; zavb_next; zavb = zavb_next, zavb_next = zavb->next) /* Leave one block on queue if it exists .. get rid of others */ free(zavb); assert(zavb); zwrhtab->first_zwrzavb = zavb; } reinitialize_hashtab_addr(&zwrhtab->h_zwrtab); } if (NULL == zwrhtab->first_zwrzavb) zwrhtab->first_zwrzavb = (zwr_zav_blk *)malloc(SIZEOF(zwr_zav_blk) + (SIZEOF(zwr_alias_var) * ZWR_ZAV_BLK_CNT)); ZAV_BLK_INIT(zwrhtab->first_zwrzavb, NULL); zwrhtab->cleaned = TRUE; } /* Obtain a zwr_alias_var slot for the zalias hash table */ zwr_alias_var *als_getzavslot(void) { zwr_alias_var *zav; zwr_zav_blk *zavb; assert(zwrhtab); assert(zwrhtab->first_zwrzavb); zwrhtab->cleaned = FALSE; /* No longer in a clean/initialized state */ /* Check if a block can be allocated out of a zavb super block */ zavb = zwrhtab->first_zwrzavb; assert(zavb); if (zavb->zav_free >= zavb->zav_top) { /* This block is full too .. need a new one */ zavb = (zwr_zav_blk *)malloc(SIZEOF(zwr_zav_blk) + (SIZEOF(zwr_alias_var) * ZWR_ZAV_BLK_CNT)); ZAV_BLK_INIT(zavb, zwrhtab->first_zwrzavb); zwrhtab->first_zwrzavb = zavb; } assert(zavb->zav_free < zavb->zav_top); zav = zavb->zav_free++; zav->value_printed = FALSE; return zav; } /* See if lv_val is associated with a base named var in the current symval. * Scan the hash table for valid entries and see if any of them point to supplied lv_val. * If so, return the hash table entry which contains the var's name that is "lowest" which * necessitates a full scan of the hash table (which ZWrite processing is going to do several * times anyway. */ ht_ent_mname *als_lookup_base_lvval(lv_val *lvp) { ht_ent_mname *htep, *htep_top, *htep_loweq; lv_val *lvhtval; assert(LV_IS_BASE_VAR(lvp)); htep_loweq = NULL; htep = curr_symval->h_symtab.base; htep_top = curr_symval->h_symtab.base + curr_symval->h_symtab.size; assert(htep_top == curr_symval->h_symtab.top); for (; htep < htep_top; htep++) { if (HTENT_VALID_MNAME(htep, lv_val, lvhtval) && ('$' != *htep->key.var_name.addr) && (lvp == lvhtval)) { /* HT entry is valid and has a key that is not a $ZWRTAC type key and the lval matches * so we have a candidate to check for "lowest" alias name for given lv_val addr. */ if (htep_loweq) { /* See current champ higher than candidate, then get new champ */ if (0 < memvcmp(htep_loweq->key.var_name.addr, htep_loweq->key.var_name.len, htep->key.var_name.addr, htep->key.var_name.len)) htep_loweq = htep; } else /* First time thru, free-ride assignment */ htep_loweq = htep; } } return htep_loweq; } /* Routine to do a garbage collection on the lv_vals in the current symbol table in order to detect if * there is any "lost data" which are 2 or more base lv_vals that point to each other thus keeping their * reference counts non-zero and prevent them from being deleted but otherwise have no entry in the hash table * themselves nor are linked to by any combination of container var linked arrays that do have an entry in * the hash table -- in other words, they are totally orphaned with no way to retrieve them so are effectively * dead but are not able to be killed in an automated fashion. This routine will find and kill those blocks * returning a count of the lv_vals thus found and killed. * * Operation: * * 1) Run lv_blks which contain all lv_val structures in use for this symbol table. * 2) Record each base lv_val in our version of the array used by stp_gcol. Base lv_vals can be identified * by having a non-zero parent.sym field pointing to a block with type MV_SYM. There are 3 exceptions to * this: In UNIX, the zsearch_var, zsearch_dir1, and zsearch_dir2 fields contain lv_vals that should not be * released. Check for and avoid them. * 3) Increment lvtaskcycle with which we will mark lv_vals as having been marked accessible as we discover them. * 4) Go through the hashtable. Set the lvtaskcycle field to mark the lv_val "reachable". * 5) If the lv_val has descendants, run the decendant chain to look for container vars. * 6) The base lv_vals that container vars point to, if not already marked "reachable" will be so marked and * the search recursively invoked on the new var. * 7) Do the same by running the mv_stent chain marking the temporarily displaced vars for parameters and NEW's as * "reachable". * 8) Do the same by running the TP stack marking local variable copies made for this symbol table as reachable. * 9) Mark any pending return argument as "reachable". * 10) Once the "reachable" search is complete, run through the created list of lv_vals and locate any that were * not reachable. If they remain undeleted (deleted will have parent.sym field zeroed), delete them. * * Note this routine uses the same buffer structure that "stp_gcol" uses except it loads its array with lv_val* * instead of mstr*. An address is an address.. */ int als_lvval_gc(void) { int killcnt; lv_blk *lv_blk_ptr; ht_ent_mname *htep, *htep_top; lv_val *lvp, *lvlimit; lv_val **lvarraycur, **lvarray, **lvarraytop, **lvptr; mv_stent *mv_st_ent; tp_frame *tf; tp_var *restore_ent; lvTree *lvt_child; symval *sym; DEBUG_ONLY(uint4 savelvtaskcycle;) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(!suspend_lvgcol); DBGRFCT((stderr, "als_lvval_gc: Beginning lv_val garbage collection\n")); if (NULL == stp_array) /* Same initialization as is in stp_gcol_src.h */ stp_array = (mstr **)malloc((stp_array_size = STP_MAXITEMS) * SIZEOF(mstr *)); lvarraycur = lvarray = (lv_val **)stp_array; lvarraytop = lvarraycur + stp_array_size; /* Steps 1,2 - find all the base lv_vals and put in list */ for (lv_blk_ptr = curr_symval->lv_first_block; lv_blk_ptr; lv_blk_ptr = lv_blk_ptr->next) { for (lvp = (lv_val *)LV_BLK_GET_BASE(lv_blk_ptr), lvlimit = LV_BLK_GET_FREE(lv_blk_ptr, lvp); lvp < lvlimit; lvp++) { sym = LV_SYMVAL(lvp); assert((NULL == sym) || SYM_IS_SYMVAL(sym)); if ((NULL != sym) UNIX_ONLY(&& (TREF(zsearch_var) != lvp)) UNIX_ONLY(&& (TREF(zsearch_dir1) != lvp) && (TREF(zsearch_dir2) != lvp))) { /* Put it in the list */ assert(0 < lvp->stats.trefcnt); if (lvarraycur >= lvarraytop) { /* Need more room -- expand */ stp_expand_array(); lvarraycur = lvarray = (lv_val **)stp_array; lvarraytop = lvarraycur + stp_array_size; } *lvarraycur++ = lvp; } } } /* Step 3, increment lvtaskcycle to mark "reachable" lv_vals */ INCR_LVTASKCYCLE; DEBUG_ONLY(savelvtaskcycle = lvtaskcycle); /* Steps 4,5,6 - Find and mark reachable lv_vals */ DBGRFCT((stderr, "als_lvval_gc: Starting symtab scan\n")); htep = curr_symval->h_symtab.base; htep_top = curr_symval->h_symtab.base + curr_symval->h_symtab.size; assert(htep_top == curr_symval->h_symtab.top); for (; htep < htep_top; htep++) if (HTENT_VALID_MNAME(htep, lv_val, lvp)) { /* HT entry is valid. Note for purposes of this loop, we do NOT bypass $ZWRTAC type keys since * they are valid reachable variables even if hidden */ MARK_REACHABLE(lvp); } /* Step 7 - Run the mv_stent chain marking those vars as reachable. */ DBGRFCT((stderr, "als_lvval_gc: Starting mv_stent scan\n")); for (mv_st_ent = mv_chain; mv_st_ent; mv_st_ent = (mv_stent *)(mv_st_ent->mv_st_next + (char *)mv_st_ent)) { switch (mv_st_ent->mv_st_type) { /* The types processed here contain lv_vals we want to mark */ case MVST_NTAB: lvp = mv_st_ent->mv_st_cont.mvs_ntab.save_value; DBGRFCT((stderr, "als_lvval_gc: NTAB at 0x"lvaddr" has save value 0x"lvaddr"\n", mv_st_ent, lvp)); assert(NULL != lvp); break; case MVST_PVAL: /* Note the save_value in the PVAL types below can be zero since they are created in * op_bindparm with a NULL save_value value and later filled in by op_bindparm. It is * possible to trigger this code in between the push_parm call of the caller and the * op_bindparm call of the callee when tracing or with an outofband event. In that case, * we don't want that NULL save_value pointer ending our loop prematurely. */ lvp = mv_st_ent->mv_st_cont.mvs_pval.mvs_ptab.save_value; DBGRFCT((stderr, "als_lvval_gc: PVAL at 0x"lvaddr" has save value 0x"lvaddr"\n", mv_st_ent, lvp)); assert(NULL != mv_st_ent->mv_st_cont.mvs_pval.mvs_val); /* Mark created lv_val to hold current value as reachable as it may not (yet) be in the * hashtable if op_bindparm has not yet run. */ MARK_REACHABLE(mv_st_ent->mv_st_cont.mvs_pval.mvs_val); if (NULL == lvp) continue; /* Don't end loop prematurely */ break; case MVST_NVAL: lvp = mv_st_ent->mv_st_cont.mvs_nval.mvs_ptab.save_value; DBGRFCT((stderr, "als_lvval_gc: NVAL at 0x"lvaddr" has save value 0x"lvaddr"\n", mv_st_ent, lvp)); assert(NULL != mv_st_ent->mv_st_cont.mvs_nval.mvs_val); /* Mark created lv_val to hold current value as reachable as it may not (yet) be in the * hashtable if op_bindparm has not yet run. */ MARK_REACHABLE(mv_st_ent->mv_st_cont.mvs_nval.mvs_val); assert(NULL != lvp); break; case MVST_STAB: /* The symbol table is changing to be other than the table we are using so we can * stop the loop now. Exiting the switch with lvp NULL indicates that. */ DBGRFCT((stderr, "als_lvval_gc: STAB mv_stent at 0x"lvaddr" stops mv_stent scan\n", mv_st_ent)); lvp = NULL; break; default: DBGRFCT((stderr, "als_lvval_gc: Ignoring mv_stent type %d\n", mv_st_ent->mv_st_type)); continue; } if (NULL == lvp) break; MARK_REACHABLE(lvp); } /* Step 8 - Run the TP stack to see if there is anything we can mark reachable */ DBGRFCT((stderr, "als_lvval_gc: Starting TP stack scan\n")); for (tf = tp_pointer; (NULL != tf) && (tf->sym == curr_symval); tf = tf->old_tp_frame) { for (restore_ent = tf->vars; NULL != restore_ent; restore_ent = restore_ent->next) { /* Since TP keeps its own use count on these sorts of variables, we will mark both the * current and saved values in these blocks. This is because the "current value" could * be detached from the hash table at this point but is still viable while we hold a use * count on it. */ MARK_REACHABLE(restore_ent->current_value); MARK_REACHABLE(restore_ent->save_value); } } /* Step 9 - Mark any pending alias return argument as reachable */ if (NULL != alias_retarg) { /* There is a pending alias return arg (container). Find the lv it is pointing to and mark it and its progeny * as reachable. */ assert(0 != (MV_ALIASCONT & alias_retarg->mvtype)); lvp = (lv_val *)alias_retarg->str.addr; assert(LV_IS_BASE_VAR(lvp)); MARK_REACHABLE(lvp); } /* Step 10 - Run the list of base lv_vals we created earlier and see which ones were not marked with the current * cycle. Note they may have already been deleted after the first one gets deleted so we can check for that * by looking for a zeroed parent field. Note the object of this code is not to force-delete the vars as we * encounter them but by performing a deletion of their arrays, we will kill the interlinking container vars that * are keeping these vars alive. */ killcnt = 0; DBGRFCT((stderr, "\nals_lvval_gc: final orphaned lvval scan\n")); for (lvptr = lvarray; lvptr < lvarraycur; ++lvptr) { lvp = *lvptr; if (lvp->stats.lvtaskcycle != lvtaskcycle) { /* Have an orphaned lv_val */ DBGRFCT((stderr, "\nals_lvval_gc: lvval 0x"lvaddr" has been identified as orphaned\n", lvp)); ++killcnt; if (LV_SYMVAL(lvp)) { /* Var is still intact, kill it. Note that in this situation, since there are no hash table * entries pointing to us, our container refs and total refs should be equal. We can't * use the "regular" DECR macros because those get us into trouble. For example if this * var has a container pointing to another var who has a container pointing to us and it * is only those pointers keeping both vars alive, decrementing our counter causes it to * become zero which messes up the deletion of the other var's container since the refcnts * are already zero. What we will do instead is INCREASE the trefcnt to keep this var from * being deleted, then drive the kill of any array it has to spur these vars to go away. */ assert(LV_IS_BASE_VAR(lvp)); DBGRFCT((stderr, "\nals_lvval_gc: Working to release unreachable lvval 0x"lvaddr"\n", lvp)); assert(lvp->stats.trefcnt == lvp->stats.crefcnt); INCR_TREFCNT(lvp); lvt_child = LV_GET_CHILD(lvp); if (NULL != lvt_child) { assert(lvp == (lv_val *)LVT_PARENT(lvt_child)); LV_CHILD(lvp) = NULL; lv_killarray(lvt_child, FALSE); } DECR_BASE_REF_NOSYM(lvp, FALSE); /* Var might go away now, or later if need more deletes first */ } else DBGRFCT((stderr, "\nals_lvval_gc: Seems to have become released -- lvval 0x"lvaddr"\n", lvp)); } } DBGRFCT((stderr, "\nals_lvval_gc: final orphaned lvval scan completed\n")); # ifdef DEBUG /* The removal of a reference for each lv_val should have done it but let's go back and verify they all * went away. If not, then it is not a simple case of user silliness and we have a problem. */ for (lvptr = lvarray; lvptr < lvarraycur; ++lvptr) { lvp = *lvptr; if (lvp->stats.lvtaskcycle != lvtaskcycle && LV_SYMVAL(lvp)) /* Var is still intact, kill it */ assert(FALSE); } # endif assert(lvtaskcycle == savelvtaskcycle); DBGRFCT((stderr, "als_lvval_gc: GC complete -- recovered %d lv_vals\n", killcnt)); SPGC_since_LVGC = 0; return killcnt; } # ifdef DEBUG_ALIAS /* Routine to check lv_val monitoring. If any lv_vals that were created during the monitoring period still exist, emit a * message to that effect with the lv_val address. In this manner we hope to find lv_val leaks (if any) in various tests. * Note that this is a debugging (not debug build) only routine since its costs are non-trivial and is only enabled * when necessary. Other tests check for memory leaks so if they find one, this monitoring can be used to discover the * source so this is not needed for test coverage. */ void als_lvmon_output(void) { symval *lvlsymtab; lv_blk *lvbp; lv_val *lvp, *lvp_top; flush_pio(); for (lvlsymtab = curr_symval; lvlsymtab; lvlsymtab = lvlsymtab->last_tab) for (lvbp = curr_symval->lv_first_block; lvbp; lvbp = lvbp->next) for (lvp = (lv_val *)LV_BLK_GET_BASE(lvbp), lvp_top = LV_BLK_GET_FREE(lvbp, lvp); lvp < lvp_top; lvp++) if (lvp->lvmon_mark) { /* lv_val slot not used as an sbs and is marked. Report it */ FPRINTF(stderr, "als_lvmon_output: lv_val at 0x"lvaddr" is still marked\n", lvp); } FFLUSH(stderr); } # endif fis-gtm-V6.0-003/sr_port/alloc_reg.c0000644000032200000250000002105212201176154016124 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #include #include "cmd_qlf.h" #include "gtmdbglvl.h" #include "compiler.h" #include "mdq.h" #include "opcode.h" #include "alloc_reg.h" #include "cdbg_dump.h" GBLDEF int4 sa_temps[VALUED_REF_TYPES]; GBLDEF int4 sa_temps_offset[VALUED_REF_TYPES]; GBLREF int mvmax; GBLREF triple t_orig; GBLREF uint4 gtmDebugLevel; GBLREF command_qualifier cmd_qlf; LITDEF int4 sa_class_sizes[VALUED_REF_TYPES] = { 0 /* dummy for slot zero */ ,SIZEOF(mval*) /* TVAR_REF */ ,SIZEOF(mval) /* TVAL_REF */ ,SIZEOF(mint) /* TINT_REF */ ,SIZEOF(mval*) /* TVAD_REF */ ,SIZEOF(char*) /* TCAD_REF */ }; LITREF octabstruct oc_tab[]; #define MAX_TEMP_COUNT 1024 error_def(ERR_TMPSTOREMAX); STATICFNDCL void remove_backptr(triple *curtrip, oprtype *opnd, char (*tempcont)[MAX_TEMP_COUNT]); void alloc_reg(void) { triple *x, *y, *ref; tbp *b; oprtype *j; opctype opc, opx; char tempcont[VALUED_REF_TYPES][MAX_TEMP_COUNT], dest_type; int r, c, temphigh[VALUED_REF_TYPES]; unsigned int oct; int4 size; memset(&tempcont[0][0], 0, SIZEOF(tempcont)); memset(&temphigh[0], -1, SIZEOF(temphigh)); temphigh[TVAR_REF] = mvmax - 1; COMPDBG(PRINTF(" \n\n\n\n************************************ Begin alloc_reg scan *****************************\n");); dqloop(&t_orig, exorder, x) { COMPDBG(PRINTF(" ************************ Triple Start **********************\n");); COMPDBG(cdbg_dump_triple(x, 0);); opc = x->opcode; switch (opc) { case OC_NOOP: case OC_PARAMETER: continue; case OC_LINESTART: /* If the next triple is also a LINESTART, then this is a comment line. * Therefore eliminate this LINESTART */ opx = x->exorder.fl->opcode; if ((OC_LINESTART == opx) || (OC_LINEFETCH == opx)) { opc = x->opcode = OC_NOOP; COMPDBG(PRINTF(" ** Converting triple to NOOP (rsn 1) **\n");); continue; /* continue, because 'normal' NOOP continues from this switch */ } /* There is a special case in the case of NOLINE_ENTRY being specified. If a blank line is followed * by a line with a label and that label generates fetch information, the generated triple sequence * will be LINESTART (from blank line), ILIT (count from PREVIOUS fetch), LINEFETCH. We will detect * that sequence here and change the LINESTART to a NOOP. */ if (!(cmd_qlf.qlf & CQ_LINE_ENTRY) && (OC_ILIT == opx) && (NULL != x->exorder.fl->exorder.fl) && (OC_LINEFETCH == x->exorder.fl->exorder.fl->opcode)) { opc = x->opcode = OC_NOOP; COMPDBG(PRINTF(" ** Converting triple to NOOP (rsn 2) **\n");); continue; /* continue, because 'normal' NOOP continues from this switch */ } # ifndef DEBUG break; # endif case OC_LINEFETCH: # ifdef DEBUG for (c = temphigh[TVAL_REF]; 0 <= c; c--) assert(0 == tempcont[TVAL_REF][c]); /* check against leaking TVAL temps */ if (OC_LINESTART == opc) break; # endif case OC_FETCH: assert((TRIP_REF == x->operand[0].oprclass) && (OC_ILIT == x->operand[0].oprval.tref->opcode)); if (x->operand[0].oprval.tref->operand[0].oprval.ilit == mvmax) { x->operand[0].oprval.tref->operand[0].oprval.ilit = 0; x->operand[1].oprclass = NO_REF; } break; case OC_STO: /* If we are storing a literal e.g. s x="hi", don't call op_sto, because we do not * need to check if the literal is defined. OC_STOLIT will be an in-line copy. * Bypass this if we have been requested to not do inline literals. */ if ((cmd_qlf.qlf & CQ_INLINE_LITERALS) && (TRIP_REF == x->operand[1].oprclass) && (OC_LIT == x->operand[1].oprval.tref->opcode)) opc = x->opcode = OC_STOLIT; break; case OC_EQU: /* Check to see if the operation is a x="" or a ""=x, if so (and this is a very common case) * use special opcode OC_EQUNUL, which takes one argument and just checks length for zero */ if ((TRIP_REF == x->operand[0].oprclass) && (OC_LIT == x->operand[0].oprval.tref->opcode) && (0 == x->operand[0].oprval.tref->operand[0].oprval.mlit->v.str.len)) { x->operand[0] = x->operand[1]; x->operand[1].oprclass = NO_REF; opc = x->opcode = OC_EQUNUL; } else if ((TRIP_REF == x->operand[1].oprclass) && (OC_LIT == x->operand[1].oprval.tref->opcode) && (0 == x->operand[1].oprval.tref->operand[0].oprval.mlit->v.str.len)) { x->operand[1].oprclass = NO_REF; opc = x->opcode = OC_EQUNUL; } break; } if (OC_PASSTHRU == x->opcode) { COMPDBG(PRINTF(" *** OC_PASSTHRU opcode being NOOP'd\n");); remove_backptr(x, &x->operand[0], tempcont); x->opcode = OC_NOOP; continue; } if (NO_REF == (dest_type = x->destination.oprclass)) /* Note assignment */ { oct = oc_tab[opc].octype; if ((oct & OCT_VALUE) && (x->backptr.que.fl != &x->backptr) && !(oct & OCT_CGSKIP)) { if (!(oct & OCT_MVADDR) && (x->backptr.que.fl->que.fl == &x->backptr) && (OC_STO == (y = x->backptr.que.fl->bpt)->opcode) && (y->operand[1].oprval.tref == x) && (OC_VAR == y->operand[0].oprval.tref->opcode)) { x->destination = y->operand[0]; y->opcode = OC_NOOP; y->operand[0].oprclass = y->operand[1].oprclass = NO_REF; } else { oct &= OCT_VALUE | OCT_MVADDR; assert((OCT_MVAL == oct) || (OCT_MINT == oct) || ((OCT_MVADDR | OCT_MVAL) == oct) || (OCT_CDADDR == oct)); r = (OCT_MVAL == oct) ? TVAL_REF : (((OCT_MVADDR | OCT_MVAL) == oct) ? TVAD_REF : ((OCT_MINT == oct) ? TINT_REF : TCAD_REF)); for (c = 0; tempcont[r][c] && (MAX_TEMP_COUNT > c); c++) ; if (MAX_TEMP_COUNT <= c) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TMPSTOREMAX); tempcont[r][c] = 1; x->destination.oprclass = r; x->destination.oprval.temp = c; if (c > temphigh[r]) temphigh[r] = c; if (OC_CDADDR == x->opcode) x->opcode = OC_NOOP; } } } else if (TRIP_REF == dest_type) { assert(x->destination.oprval.tref->destination.oprclass); x->destination = x->destination.oprval.tref->destination; } for (j = x->operand, y = x; j < ARRAYTOP(y->operand); ) { /* Loop through all the parameters of the current opcode. For each parameter that requires an intermediate * temporary, decrement (this is what remove_backptr does) the "reference count" -- opcodes yet to be * processed that still need the intermediate result -- and if that number is zero, mark the temporary * available. We can then reuse the temp to hold the results of subsequent opcodes. Note that remove_backptr * is essentially the resolve_tref() in resolve_ref.c. resolve_tref increments the "reference count", * while remove_backptr decrements it. */ if (TRIP_REF == j->oprclass) { ref = j->oprval.tref; if (OC_PARAMETER == ref->opcode) { y = ref; j = y->operand; continue; } remove_backptr(y, j, tempcont); } j++; } } for (r = 0; VALUED_REF_TYPES > r; r++) sa_temps[r] = temphigh[r] + 1; sa_temps_offset[TVAR_REF] = sa_temps[TVAR_REF] * sa_class_sizes[TVAR_REF]; size = sa_temps[TVAL_REF] * sa_class_sizes[TVAL_REF]; sa_temps_offset[TVAL_REF] = size; /* Since we need to align the temp region to the largest types, align even int temps to SIZEOF(char*) */ size += ROUND_UP2(sa_temps[TINT_REF] *sa_class_sizes[TINT_REF], SIZEOF(char *)); sa_temps_offset[TINT_REF] = size; size += sa_temps[TVAD_REF] * sa_class_sizes[TVAD_REF]; sa_temps_offset[TVAD_REF] = size; size += sa_temps[TCAD_REF] * sa_class_sizes[TCAD_REF]; sa_temps_offset[TCAD_REF] = size; } void remove_backptr(triple *curtrip, oprtype *opnd, char (*tempcont)[MAX_TEMP_COUNT]) { triple *ref; tbp *b; int r; assert(TRIP_REF == opnd->oprclass); ref = opnd->oprval.tref; while (OC_PASSTHRU == opnd->oprval.tref->opcode) { ref = ref->operand[0].oprval.tref; opnd = &ref->operand[0]; assert(TRIP_REF == opnd->oprclass); } r = ref->destination.oprclass; if (NO_REF != r) { dqloop(&ref->backptr, que, b) { if (b->bpt == curtrip) { dqdel(b, que); break; } } if ((ref->backptr.que.fl == &ref->backptr) && (TVAR_REF != r)) tempcont[r][ref->destination.oprval.temp] = 0; } } fis-gtm-V6.0-003/sr_port/alloc_reg.h0000644000032200000250000000105412201176154016131 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef ALLOC_REG_INCLUDED #define ALLOC_REG_INCLUDED void alloc_reg(void); #endif /* ALLOC_REG_INCLUDED */ fis-gtm-V6.0-003/sr_port/anticipatory_freeze.h0000644000032200000250000003210012201176154020244 0ustar librarygtc/**************************************************************** * * * Copyright 2012, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef _ANTICIPATORY_FREEZE_H #define _ANTICIPATORY_FREEZE_H #ifdef UNIX #include "gtm_time.h" /* needed for GET_CUR_TIME */ #include "gdsroot.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "repl_msg.h" /* needed for gtmsource.h */ #include "gtmsource.h" /* needed for jnlpool_addrs typedef */ #include "sleep_cnt.h" /* needed for SLEEP_INSTFREEZEWAIT macro */ #include "wait_for_disk_space.h" /* needed by DB_LSEEKWRITE macro for prototype */ #include "gtmimagename.h" /* needed for IS_GTM_IMAGE */ boolean_t is_anticipatory_freeze_needed(sgmnt_addrs *csa, int msg_id); void set_anticipatory_freeze(sgmnt_addrs *csa, int msg_id); boolean_t init_anticipatory_freeze_errors(void); /* Define function pointers to certain functions to avoid executables like gtmsecshr from unnecessarily * linking with these functions (which causes the database/replication stuff to be pulled in). */ typedef boolean_t (*is_anticipatory_freeze_needed_t)(sgmnt_addrs *csa, int msgid); typedef void (*set_anticipatory_freeze_t)(sgmnt_addrs *csa, int msg_id); GBLREF is_anticipatory_freeze_needed_t is_anticipatory_freeze_needed_fnptr; GBLREF set_anticipatory_freeze_t set_anticipatory_freeze_fnptr; GBLREF boolean_t pool_init; GBLREF boolean_t mupip_jnl_recover; #ifdef DEBUG GBLREF uint4 lseekwrite_target; #endif error_def(ERR_MUINSTFROZEN); error_def(ERR_MUINSTUNFROZEN); error_def(ERR_MUNOACTION); error_def(ERR_REPLINSTFREEZECOMMENT); error_def(ERR_REPLINSTFROZEN); error_def(ERR_REPLINSTUNFROZEN); error_def(ERR_TEXT); #define ENABLE_FREEZE_ON_ERROR \ { \ if (ANTICIPATORY_FREEZE_AVAILABLE) \ { /* Set anticipatory freeze function pointers to be used later (in send_msg and rts_error) */ \ is_anticipatory_freeze_needed_fnptr = &is_anticipatory_freeze_needed; \ set_anticipatory_freeze_fnptr = &set_anticipatory_freeze; \ } \ } #define CHECK_IF_FREEZE_ON_ERROR_NEEDED(CSA, MSG_ID, FREEZE_NEEDED, FREEZE_MSG_ID) \ { \ GBLREF jnlpool_addrs jnlpool; \ DCL_THREADGBL_ACCESS; \ \ SETUP_THREADGBL_ACCESS; \ if (!FREEZE_NEEDED && ANTICIPATORY_FREEZE_AVAILABLE && (NULL != is_anticipatory_freeze_needed_fnptr)) \ { /* NOT gtmsecshr */ \ if (IS_REPL_INST_UNFROZEN && (*is_anticipatory_freeze_needed_fnptr)((sgmnt_addrs *)CSA, MSG_ID)) \ { \ FREEZE_NEEDED = TRUE; \ FREEZE_MSG_ID = MSG_ID; \ } \ } \ } #define FREEZE_INSTANCE_IF_NEEDED(CSA, FREEZE_NEEDED, FREEZE_MSG_ID) \ { \ GBLREF jnlpool_addrs jnlpool; \ \ if (FREEZE_NEEDED) \ { \ assert(NULL != set_anticipatory_freeze_fnptr); \ (*set_anticipatory_freeze_fnptr)((sgmnt_addrs *)CSA, FREEZE_MSG_ID); \ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_REPLINSTFROZEN, 1, \ jnlpool.repl_inst_filehdr->inst_info.this_instname); \ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_REPLINSTFREEZECOMMENT, 1, jnlpool.jnlpool_ctl->freeze_comment); \ } \ } #define CLEAR_ANTICIPATORY_FREEZE(FREEZE_CLEARED) \ { \ GBLREF jnlpool_addrs jnlpool; \ \ if (IS_REPL_INST_FROZEN) \ { \ jnlpool.jnlpool_ctl->freeze = 0; \ FREEZE_CLEARED = TRUE; \ } \ } #define REPORT_INSTANCE_UNFROZEN(FREEZE_CLEARED) \ { \ GBLREF jnlpool_addrs jnlpool; \ \ if (FREEZE_CLEARED) \ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_REPLINSTUNFROZEN, 1, \ jnlpool.repl_inst_filehdr->inst_info.this_instname); \ } #define AFREEZE_MASK 0x01 #define ANTICIPATORY_FREEZE_AVAILABLE (0 != (TREF(gtm_custom_errors)).len) #define INSTANCE_FREEZE_HONORED(CSA) (DBG_ASSERT(NULL != CSA) \ ((NULL != jnlpool.jnlpool_ctl) \ && ((REPL_ALLOWED(((sgmnt_addrs *)CSA)->hdr)) \ || mupip_jnl_recover /* recover or rollback */ \ || ((sgmnt_addrs *)CSA)->nl->onln_rlbk_pid ))) #define ANTICIPATORY_FREEZE_ENABLED(CSA) (INSTANCE_FREEZE_HONORED(CSA) \ && ANTICIPATORY_FREEZE_AVAILABLE \ && (((sgmnt_addrs *)CSA)->hdr->freeze_on_fail)) #define IS_REPL_INST_FROZEN ((NULL != jnlpool.jnlpool_ctl) && jnlpool.jnlpool_ctl->freeze) #define IS_REPL_INST_UNFROZEN ((NULL != jnlpool.jnlpool_ctl) && !jnlpool.jnlpool_ctl->freeze) #define INST_FROZEN_COMMENT "PID %d encountered %s; Instance frozen" #define MSGID_TO_ERRMSG(MSG_ID, ERRMSG) \ { \ const err_ctl *ctl; \ \ ctl = err_check(MSG_ID); \ assert(NULL != ctl); \ GET_MSG_INFO(MSG_ID, ctl, ERRMSG); \ } #define GENERATE_INST_FROZEN_COMMENT(BUF, BUF_LEN, MSG_ID) \ { \ GBLREF uint4 process_id; \ const err_msg *msginfo; \ \ MSGID_TO_ERRMSG(MSG_ID, msginfo); \ SNPRINTF(BUF, BUF_LEN, INST_FROZEN_COMMENT, process_id, msginfo->tag); \ } /* This is a version of the macro which waits for the instance freeze to be lifted off assuming the process has * already attached to the journal pool. We need to wait for the freeze only if the input database cares about * anticipatory freeze. Examples of those databases that dont care are non-replicated databases, databases with * "freeze_on_fail" field set to FALSE in the file header etc. Hence the use of ANTICIPATORY_FREEZE_ENABLED below. * Note: Do not use "hiber_start" as that uses timers and if we are already in a timer handler now, nested timers * wont work. Since SHORT_SLEEP allows a max of 1000, we use 500 (half a second) for now. */ #define WAIT_FOR_REPL_INST_UNFREEZE(CSA) \ { \ gd_region *reg; \ char *time_ptr, time_str[CTIME_BEFORE_NL + 2]; /* for GET_CUR_TIME macro */ \ now_t now; \ DCL_THREADGBL_ACCESS; \ \ SETUP_THREADGBL_ACCESS; \ assert(NULL != CSA); \ if (INSTANCE_FREEZE_HONORED(CSA)) \ { \ reg = ((sgmnt_addrs *)CSA)->region; \ if (!IS_GTM_IMAGE) \ { \ GET_CUR_TIME; \ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_MUINSTFROZEN, 5, CTIME_BEFORE_NL, time_ptr, \ jnlpool.repl_inst_filehdr->inst_info.this_instname, DB_LEN_STR(reg)); \ } \ WAIT_FOR_REPL_INST_UNFREEZE_NOCSA; \ if (!IS_GTM_IMAGE) \ { \ GET_CUR_TIME; \ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_MUINSTUNFROZEN, 5, CTIME_BEFORE_NL, time_ptr, \ jnlpool.repl_inst_filehdr->inst_info.this_instname, DB_LEN_STR(reg)); \ } \ } \ } /* This is a safer version of the WAIT_FOR_REPL_INST_UNFREEZE macro, which waits for the instance freeze * to be lifted off but is not sure if the process has access to the journal pool yet. * If it does not, then it assumes the instance is not frozen. */ #define WAIT_FOR_REPL_INST_UNFREEZE_SAFE(CSA) \ { \ GBLREF jnlpool_addrs jnlpool; \ \ assert(NULL != CSA); \ if (IS_REPL_INST_FROZEN) \ WAIT_FOR_REPL_INST_UNFREEZE(CSA); \ } /* Below are similar macros like the above but with no CSA to specifically check for */ #define WAIT_FOR_REPL_INST_UNFREEZE_NOCSA \ { \ GBLREF jnlpool_addrs jnlpool; \ GBLREF volatile int4 exit_state; \ GBLREF int4 exi_condition; \ GBLREF int4 forced_exit_err; \ \ assert(NULL != jnlpool.jnlpool_ctl); \ /* If this region is not replicated, do not care for instance freezes */ \ while (jnlpool.jnlpool_ctl->freeze) \ { \ if (exit_state != 0) \ { \ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err); \ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err); \ exit(-exi_condition); \ } \ SHORT_SLEEP(SLEEP_INSTFREEZEWAIT); \ DEBUG_ONLY(CLEAR_FAKE_ENOSPC_IF_MASTER_DEAD); \ } \ } #define WAIT_FOR_REPL_INST_UNFREEZE_NOCSA_SAFE \ { \ GBLREF jnlpool_addrs jnlpool; \ \ if (IS_REPL_INST_FROZEN) \ WAIT_FOR_REPL_INST_UNFREEZE_NOCSA; \ } /* GTM_DB_FSYNC/GTM_JNL_FSYNC are similar to GTM_FSYNC except that we dont do the fsync * (but instead hang) if we detect the instance is frozen. We proceed with the fsync once the freeze clears. * CSA is a parameter indicating which database it is that we want to fsync. * GTM_REPL_INST_FSYNC is different in that we currently dont care about instance freeze for replication * instance file writes. */ #define GTM_DB_FSYNC(CSA, FD, RC) \ { \ GBLREF jnlpool_addrs jnlpool; \ node_local_ptr_t cnl; \ \ assert((NULL != CSA) || (NULL == jnlpool.jnlpool_ctl)); \ if (NULL != CSA) \ { \ WAIT_FOR_REPL_INST_UNFREEZE_SAFE(CSA); \ cnl = (CSA)->nl; \ if (NULL != cnl) \ INCR_GVSTATS_COUNTER((CSA), cnl, n_db_fsync, 1); \ } \ GTM_FSYNC(FD, RC); \ } #define GTM_JNL_FSYNC(CSA, FD, RC) \ { \ GBLREF jnlpool_addrs jnlpool; \ node_local_ptr_t cnl; \ \ assert((NULL != CSA) || (NULL == jnlpool.jnlpool_ctl)); \ if (NULL != CSA) \ { \ WAIT_FOR_REPL_INST_UNFREEZE_SAFE(CSA); \ cnl = (CSA)->nl; \ if (NULL != cnl) \ INCR_GVSTATS_COUNTER((CSA), cnl, n_jnl_fsync, 1); \ } \ GTM_FSYNC(FD, RC); \ } #define GTM_REPL_INST_FSYNC(FD, RC) GTM_FSYNC(FD, RC) #define LSEEKWRITE_IS_TO_NONE 0 #define LSEEKWRITE_IS_TO_DB 1 #define LSEEKWRITE_IS_TO_JNL 2 #ifdef DEBUG #define FAKE_ENOSPC(CSA, FAKE_WHICH_ENOSPC, LSEEKWRITE_TARGET, LCL_STATUS) \ { \ GBLREF jnlpool_addrs jnlpool; \ if (NULL != CSA) \ { \ if (WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC)) \ { /* This test case is only used by mupip */ \ gtm_wbox_input_test_case_count++; \ if ((0 != gtm_white_box_test_case_count) \ && (gtm_white_box_test_case_count <= gtm_wbox_input_test_case_count)) \ { \ LCL_STATUS = ENOSPC; \ if (gtm_white_box_test_case_count == gtm_wbox_input_test_case_count) \ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, \ LEN_AND_LIT("Turning on fake ENOSPC for exit status test")); \ } \ } else if (!IS_DSE_IMAGE /*DSE does not freeze so let it work as normal */ \ && ((NULL != jnlpool.jnlpool_ctl) && (NULL != ((sgmnt_addrs *)CSA)->nl)) \ && ((sgmnt_addrs *)CSA)->nl->FAKE_WHICH_ENOSPC) \ { \ LCL_STATUS = ENOSPC; \ lseekwrite_target = LSEEKWRITE_TARGET; \ } \ } \ } void clear_fake_enospc_if_master_dead(void); #define CLEAR_FAKE_ENOSPC_IF_MASTER_DEAD clear_fake_enospc_if_master_dead() #else #define FAKE_ENOSPC(CSA, FAKE_ENOSPC, LSEEKWRITE_TARGET, LCL_STATUS) {} #endif #define DB_LSEEKWRITE(csa, db_fn, fd, new_eof, buff, size, status) \ DO_LSEEKWRITE(csa, db_fn, fd, new_eof, buff, size, status, fake_db_enospc, LSEEKWRITE_IS_TO_DB) #define JNL_LSEEKWRITE(csa, jnl_fn, fd, new_eof, buff, size, status) \ DO_LSEEKWRITE(csa, jnl_fn, fd, new_eof, buff, size, status, fake_jnl_enospc, LSEEKWRITE_IS_TO_JNL) #define DO_LSEEKWRITE(csa, fnptr, fd, new_eof, buff, size, status, FAKE_WHICH_ENOSPC, LSEEKWRITE_TARGET) \ { \ int lcl_status; \ \ if (NULL != csa) \ WAIT_FOR_REPL_INST_UNFREEZE_SAFE(csa); \ LSEEKWRITE(fd, new_eof, buff, size, lcl_status); \ FAKE_ENOSPC(csa, FAKE_WHICH_ENOSPC, LSEEKWRITE_TARGET, lcl_status); \ if (ENOSPC == lcl_status) \ { \ wait_for_disk_space(csa, (char *)fnptr, fd, (off_t)new_eof, (char *)buff, (size_t)size, &lcl_status); \ assert((NULL == csa) || (NULL == ((sgmnt_addrs *)csa)->nl) || !((sgmnt_addrs *)csa)->nl->FAKE_WHICH_ENOSPC \ || (ENOSPC != lcl_status)); \ } \ status = lcl_status; \ } /* Currently, writes to replication instance files do NOT trigger instance freeze behavior. * Neither does a pre-existing instance freeze affect replication instance file writes. * Hence this is defined as simple LSEEKWRITE. */ #define REPL_INST_LSEEKWRITE LSEEKWRITE #define REPL_INST_AVAILABLE (repl_inst_get_name((char *)replpool_id.instfilename, &full_len, SIZEOF(replpool_id.instfilename), \ return_on_error)) #else /* #ifdef UNIX */ # define ANTICIPATORY_FREEZE_AVAILABLE FALSE # define ANTICIPATORY_FREEZE_ENABLED(CSA) FALSE # define REPL_INST_AVAILABLE FALSE # define WAIT_FOR_REPL_INST_UNFREEZE # define WAIT_FOR_REPL_INST_UNFREEZE_SAFE #endif /* #ifdef UNIX */ #endif /* #ifndef _ANTICIPATORY_FREEZE_H */ fis-gtm-V6.0-003/sr_port/arit.h0000644000032200000250000000674212201176154015152 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* arit.h : defines constants for arithmetic operations. gdsroot.h has a definition for the MAX_NUM_SUBSC_LEN that depends on the number of significant digits available. If it changes from 18, the define must be updated */ #define NUM_DEC_DG_1L 9 /* Number of decimal digits in a int4 */ #define NUM_DEC_DG_2L 18 /* Number of decimal digits in two longs */ #define EXP_IDX_BIAL (9+MV_XBIAS) /* Max. biased exponent index within a int4 */ #define EXP_IDX_BIAQ (18+MV_XBIAS) /* Max. biased exponent index within two longs */ #define EXPLO (-42+MV_XBIAS) /* Min. biased exponent */ #define EXPHI (48+MV_XBIAS) /* Max. biased exponent */ /* Note: The above values for EXPLO and EXPHI set up a range of 20 thru 109 which still leaves room for expansion * in the 7-bit exponent whose full range is 0 thru 127. One might be tempted to increase EXPLO/EXPHI to accommodate * the available range but should not because these values also affect how numeric subscripts are stored in the database. * * The entire numeric range currently supported by GT.M along with how it represents them internally as well as * inside the database (the first byte of the numeric subscript) is captured in the table below. * * -------------------------|---------------------------------------------------------------------------------------- * Numeric value | ... [-1E46, -1E-43] ... [0] ... [1E-43, 1E46] ... * mval.e representation | ... [ 109, 20] ... [0] ... [ 20, 109] ... * mval.sgn representation | ... [ 1, 1] ... [0] ... [ 0, 0] ... * | | | | | | | | * | | | | | | | | * | | | | | | | | * | v v v v v v v * subscript representation | [0x00, 0x11] [0x12, 0x6b] [0x6c,0x7F] [0x80] [0x81, 0x93] [0x94, 0xED] [0xEE, 0xFF] * in database | * -------------------------|---------------------------------------------------------------------------------------- * * Any increase in EXPHI will encroach the currently unused interval [0x00,0x11] and has to be done with caution * as a few of those are used for different purposes (0x01 to represent a null subscript in standard null collation, * 0x02 to be used for spanning node subscripts etc.) */ #define EXP_INT_OVERF (7+MV_XBIAS) /* Upper bound on MV_INT numbers */ #define EXP_INT_UNDERF (-3+MV_XBIAS) /* Lower bound on MV_INT numbers (includes * integers & fractions upto 3 decimal places */ #define MANT_LO 100000000 /* mantissa.1 >= MANT_LO */ #define MANT_HI 1000000000 /* mantissa.1 < MANT_HI , mantissa.0 < MANT_HI */ #define INT_HI 1000000 /* -INT_HI < mv_int < INT_HI */ fis-gtm-V6.0-003/sr_port/asc2i.c0000644000032200000250000000175212201176154015203 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" GBLREF seq_num seq_num_zero; GBLREF seq_num seq_num_minus_one; int4 asc2i(uchar_ptr_t p, int4 len) { uchar_ptr_t c; int4 ret; ret = 0; for (c = p + len; c > p; p++) { if (*p > '9' || *p < '0') return -1; ret = ret * 10; ret += *p - '0'; } return ret; } qw_num asc2l(uchar_ptr_t p, int4 len) { uchar_ptr_t c; qw_num ret; QWASSIGN(ret, seq_num_zero); for (c = p + len; c > p; p++) { if (*p > '9' || *p < '0') return seq_num_minus_one; QWMULBYDW(ret, ret, 10); QWINCRBYDW(ret, *p - '0'); } return ret; } fis-gtm-V6.0-003/sr_port/asc_hex2i.c0000644000032200000250000000257012201176154016046 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" LITREF unsigned char lower_to_upper_table[]; unsigned int asc_hex2i(uchar_ptr_t p, int len) { uchar_ptr_t c; unsigned char ch; int ret; ret = 0; for (c = p + len; c > p; p++) { if (('0' <= *p) && ('9' >= *p)) ret = (ret << 4) + (*p - '0'); else { ch = lower_to_upper_table[*p]; if (('A' <= ch) && ('F' >= ch)) ret = (ret << 4) + ch - 'A' + 10; else return (unsigned int)-1; } } return ret; } #ifndef VMS /* Routine identical to asc_hex2i() but with 8 byte accumulator and return type */ gtm_uint64_t asc_hex2l(uchar_ptr_t p, int len) { uchar_ptr_t c; unsigned char ch; gtm_uint64_t ret; ret = 0; for (c = p + len; c > p; p++) { if (('0' <= *p) && ('9' >= *p)) ret = (ret << 4) + (*p - '0'); else { ch = lower_to_upper_table[*p]; if (('A' <= ch) && ('F' >= ch)) ret = (ret << 4) + ch - 'A' + 10; else return (gtm_uint64_t)-1; } } return ret; } #endif fis-gtm-V6.0-003/sr_port/aswp.h0000644000032200000250000000153112201176154015154 0ustar librarygtc/**************************************************************** * * * Copyright 2005 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef ASWP_H_INCLUDED #define ASWP_H_INCLUDED #ifdef __hppa int aswp3(sm_int_ptr_t /* location */, int4 /* value */, sm_global_latch_ptr_t /* latch */); #define ASWP(A,B,C) aswp3((sm_int_ptr_t)(A), B, C) #else int aswp(sm_int_ptr_t /* location */, int4 /* value */); int aswp_secshr(sm_int_ptr_t /* location */, int4 /* value */); #define ASWP(A,B,C) aswp((sm_int_ptr_t)(A), B) #endif #endif fis-gtm-V6.0-003/sr_port/azl_geturxlab.c0000644000032200000250000000140212201176154017035 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "urx.h" bool azl_geturxlab (addr, rp) char *addr; urx_rtnref *rp; { urx_labref *lp; assert (rp->lab); for (lp = rp->lab; lp; lp = lp->next) { urx_addr *ap; for (ap = lp->addr; ap; ap = ap->next) if (addr == (char *)ap->addr) break; if (ap) return TRUE; } return FALSE; } fis-gtm-V6.0-003/sr_port/azl_geturxrtn.c0000644000032200000250000000160112201176154017103 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2004 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "urx.h" GBLREF urx_rtnref urx_anchor; bool azl_geturxrtn(char *addr, mstr *rname, urx_rtnref **rp) { assert(urx_anchor.len == 0); for (*rp = urx_anchor.next; *rp; *rp = (*rp)->next) { urx_addr *ap; for (ap = (*rp)->addr; ap; ap = ap->next) if (addr == (char *)ap->addr) break; if (ap) { rname->len = (*rp)->len; rname->addr = (char *)&(*rp)->name[0]; return TRUE; } } return FALSE; } fis-gtm-V6.0-003/sr_port/backup_block.c0000644000032200000250000000714512201176154016623 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_stdio.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gdsblk.h" #include "shmpool.h" #include "memcoherency.h" #include "mupipbckup.h" GBLREF uint4 process_id; boolean_t backup_block(sgmnt_addrs *csa, block_id blk, cache_rec_ptr_t backup_cr, sm_uc_ptr_t backup_blk_p) { uint4 bsiz; int4 required; shmpool_buff_hdr_ptr_t sbufh_p; shmpool_blk_hdr_ptr_t sblkh_p; boolean_t ret = TRUE, is_bg; sgmnt_data_ptr_t csd; sm_uc_ptr_t bkp_src_blk; csd = csa->hdr; is_bg = (dba_bg == csd->acc_meth); assert(is_bg || (dba_mm == csd->acc_meth)); /* Should have EITHER backup cr (BG mode) or buffer pointer (MM mode) */ assert((is_bg && (NULL != backup_cr) && (NULL == backup_blk_p)) || (!is_bg && (NULL == backup_cr) && (NULL != backup_blk_p))); if (is_bg) { /* Get buffer address from the cache record */ VMS_ONLY(assert(0 == backup_cr->shmpool_blk_off)); assert(backup_cr->in_cw_set);/* ensure the buffer has been pinned (from preemption in db_csh_getn) */ backup_blk_p = GDS_ANY_REL2ABS(csa, backup_cr->buffaddr); } bsiz = ((blk_hdr_ptr_t)(backup_blk_p))->bsiz; sbufh_p = csa->shmpool_buffer; assert(bsiz <= sbufh_p->blk_size); /* Obtain block from shared memory pool. If we can't get the block, then backup will be effectively terminated. */ sblkh_p = shmpool_blk_alloc(csa->region, SHMBLK_BACKUP); if (((shmpool_blk_hdr_ptr_t)-1L) == sblkh_p) return FALSE; /* Backup died for whatever reason. Backup failure already dealt with in shmpool_blk_alloc() */ /* Fill the block we have been assigned in before marking it valid */ sblkh_p->blkid = blk; if (is_bg) { assert(NULL != backup_cr); sblkh_p->use.bkup.ondsk_blkver = backup_cr->ondsk_blkver; assert(((blk_hdr_ptr_t)backup_blk_p)->bsiz >= SIZEOF(blk_hdr)); } else /* For MM version, no dynamic conversions take place so just record block as we know it is */ sblkh_p->use.bkup.ondsk_blkver = csd->desired_db_format; bkp_src_blk = backup_blk_p; # ifdef GTM_CRYPT /* If the database is encrypted, the old_block will be in the encrypted twin buffer. Fetch it from the encrypted * twin counter part and write that to the backup buffer instead. */ if (csd->is_encrypted) { DBG_ENSURE_PTR_IS_VALID_GLOBUFF(csa, csd, backup_blk_p); bkp_src_blk = GDS_ANY_ENCRYPTGLOBUF(backup_blk_p, csa); DBG_ENSURE_PTR_IS_VALID_ENCTWINGLOBUFF(csa, csd, bkp_src_blk); } # endif /* Adjust bsiz to be within database block size range. Asserts above will ensure this IS the case for DBG. */ if (bsiz < SIZEOF(blk_hdr)) bsiz = SIZEOF(blk_hdr); else if (bsiz > sbufh_p->blk_size) bsiz = sbufh_p->blk_size; /* Copy block information to data portion of shmpool block just following header */ memcpy((sblkh_p + 1), bkp_src_blk, bsiz); /* Need a write coherency fence here as we want to make sure the above info is stored and * reflected to other processors before we mark the block valid. */ SHM_WRITE_MEMORY_BARRIER; sblkh_p->valid_data = TRUE; /* And another write barrier to advertise its cleanliness to other processors */ SHM_WRITE_MEMORY_BARRIER; return TRUE; } fis-gtm-V6.0-003/sr_port/base_frame.c0000644000032200000250000000345112201176176016270 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "error.h" /* For DBGEHND() */ #include #include "stack_frame.h" GBLREF unsigned char *stacktop, *stackwarn, *msp; GBLREF stack_frame *frame_pointer; error_def(ERR_STACKCRIT); error_def(ERR_STACKOFLOW); void base_frame(rhdtyp *base_address) { void gtm_ret_code(); /* This is an external which points to code without an entry mask */ unsigned char *msp_save; stack_frame *fp; if ((INTPTR_T)msp & 1) /* synchronize mumps stack on even boundary */ msp--; if ((INTPTR_T)msp & 2) msp -= 2; #ifdef GTM64 if ((INTPTR_T)msp & 4) msp -= 4; #endif /* GTM64 */ msp_save = msp; msp -= SIZEOF(stack_frame) + SIZEOF(stack_frame *); if (msp <= stackwarn) { if (msp <= stacktop) { msp = msp_save; rts_error(VARLSTCNT(1) ERR_STACKOFLOW); } else rts_error(VARLSTCNT(1) ERR_STACKCRIT); } *(stack_frame **)((stack_frame *)msp + 1) = frame_pointer; frame_pointer = fp = (stack_frame *)msp; memset(fp, 0, SIZEOF(stack_frame)); fp->ctxt = GTM_CONTEXT(gtm_ret_code); fp->mpc = CODE_ADDRESS(gtm_ret_code); fp->rvector = base_address; fp->temps_ptr = (unsigned char *)fp; fp->vartab_len = 0; fp->vartab_ptr = (char *)fp; fp->type = SFT_COUNT; fp->ret_value = NULL; fp->dollar_test = -1; DBGEHND((stderr, "base_frame: New base frame allocated at 0x"lvaddr"\n", fp)); } fis-gtm-V6.0-003/sr_port/bg_update.h0000644000032200000250000000142512201176154016136 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __BG_UPDATE_H__ #define __BG_UPDATE_H__ enum cdb_sc bg_update(cw_set_element *cs, trans_num ctn, trans_num effective_tn, sgm_info *si); enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si); enum cdb_sc bg_update_phase2(cw_set_element *cs, trans_num ctn, trans_num effective_tn, sgm_info *si); #endif fis-gtm-V6.0-003/sr_port/bit_clear.c0000644000032200000250000000137412201176154016126 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "bit_clear.h" static unsigned char bit_clear_mask[8] = {127, 191, 223, 239, 247, 251, 253, 254}; uint4 bit_clear (uint4 bit, sm_uc_ptr_t base) { uint4 retval; sm_uc_ptr_t ptr; ptr = base + bit / 8; retval = (1 << (bit & 7)) & *ptr; *ptr &= ~(1 << (bit & 7)); return retval != 0; } fis-gtm-V6.0-003/sr_port/bit_clear.h0000644000032200000250000000112012201176154016120 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef BIT_CLEAR_DEFINED /* Declare parms for bit_clear.c */ uint4 bit_clear (uint4 bit, sm_uc_ptr_t base); #define BIT_CLEAR_DEFINED #endif fis-gtm-V6.0-003/sr_port/bit_set.c0000644000032200000250000000124012201176154015623 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "bit_set.h" uint4 bit_set (uint4 bit, sm_uc_ptr_t base) { int4 retval; sm_uc_ptr_t ptr; ptr = base + bit / 8; retval = (1 << (bit & 7)) & *ptr; *ptr |= 1 << (bit & 7); return retval != 0; } fis-gtm-V6.0-003/sr_port/bit_set.h0000644000032200000250000000111012201176154015624 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef BIT_SET_DEFINED /* Declare parms for bit_set.c */ uint4 bit_set (uint4 bit, sm_uc_ptr_t base); #define BIT_SET_DEFINED #endif fis-gtm-V6.0-003/sr_port/bm_find_blk.c0000644000032200000250000000773312201176154016435 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gdsbml.h" #define MAX_FFS_SIZE 32 /* Returns the location of the first set bit in the field. */ /* The search starts at the hint and does not wrap */ int4 bm_find_blk(int4 hint, sm_uc_ptr_t base_addr, int4 total_bits, boolean_t *used) { int4 bits; sm_uc_ptr_t ptr, top; unsigned char valid; assert(hint < total_bits); total_bits *= BML_BITS_PER_BLK; /* Currently bm_find_blk has been coded to assume that if "hint" is * non-zero then it is less than total_bits. We better assert that. */ if (hint) { ptr = base_addr + (hint * BML_BITS_PER_BLK) / 8; top = base_addr + (total_bits + 7) / 8 - 1; if (ptr == top) { bits = total_bits % 8; if (bits == 6) valid = *ptr & 63; else if (bits == 4) valid = *ptr & 15; else if (bits == 2) valid = *ptr & 3; else valid = *ptr; } else valid = *ptr; switch (hint % (8 / BML_BITS_PER_BLK)) { case 0: break; case 1: valid = valid & 252; break; case 2: valid = valid & 240; break; case 3: valid = valid & 192; break; } if (valid) { if (valid & 1) { if (valid & 2) *used = TRUE; else *used = FALSE; return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK)); } else if (valid & 4) { if (valid & 8) *used = TRUE; else *used = FALSE; return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 1); } else if (valid & 16) { if (valid & 32) *used = TRUE; else *used = FALSE; return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 2); } else { if (valid & 128) *used = TRUE; else *used = FALSE; return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 3); } } ptr++; } else ptr = base_addr; for (top = base_addr + (total_bits +7) / 8 - 1; ptr < top; ptr++) { if (*ptr) { if (*ptr & 1) { if (*ptr & 2) *used = TRUE; else *used = FALSE; return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK)); } else if (*ptr & 4) { if (*ptr & 8) *used = TRUE; else *used = FALSE; return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 1); } else if (*ptr & 16) { if (*ptr & 32) *used = TRUE; else *used = FALSE; return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 2); } else { if (*ptr & 128) *used = TRUE; else *used = FALSE; return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 3); } } } if ((ptr == top) && *ptr) /* Special processing for last byte--may be only partially valid , if had hint may */ { bits = total_bits % 8; /* have already done last byte, then ptr will be greater than top */ if (bits == 6) valid = *ptr & 63; else if (bits == 4) valid = *ptr & 15; else if (bits == 2) valid = *ptr & 3; else valid = *ptr; if (valid) { if (valid & 1) { if (valid & 2) *used = TRUE; else *used = FALSE; return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK)); } else if (valid & 4) { if (valid & 8) *used = TRUE; else *used = FALSE; return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 1); } else if (valid & 16) { if (valid & 32) *used = TRUE; else *used = FALSE; return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 2); } else { if (valid & 128) *used = TRUE; else *used = FALSE; return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 3); } } } return -1; } fis-gtm-V6.0-003/sr_port/bm_getfree.c0000644000032200000250000002540412201176154016301 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /************************************************************************************** * * MODULE NAME: BM_GETFREE.C * * CALLING SEQUENCE: block_id bm_getfree(hint, blk_used, cw_work, cs, cw_depth_ptr) * * DESCRIPTION: Takes a block id as a hint and tries to find a * free block, looking first at the hint, then in the same local * bitmap, and finally in every local map. If it finds a free block, * it looks for the bitmap in the working set, puts it in the working * set if it is not there, and updates the map used, and marks it with * the transaction number, and updates the boolean * pointed to by blk_used to indicate if the free block had been used previously. * * HISTORY: * ***************************************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "cdb_sc.h" #include "gdsroot.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsbml.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsfhead.h" #include "min_max.h" #include "gdsblkops.h" #include "filestruct.h" #include "gdscc.h" #include "gdskill.h" /* needed for tp.h */ #include "jnl.h" /* needed for tp.h */ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* needed for ua_list for ENSURE_UPDATE_ARRAY_SPACE macro */ #include "iosp.h" #include "bmm_find_free.h" /* Include prototypes */ #include "t_qread.h" #include "t_write_map.h" #include "bit_clear.h" #include "send_msg.h" #include "bm_getfree.h" #include "gdsfilext.h" GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF char *update_array, *update_array_ptr; GBLREF gd_region *gv_cur_region; GBLREF unsigned char rdfail_detail; GBLREF uint4 dollar_tlevel; GBLREF uint4 update_array_size, cumul_update_array_size; GBLREF unsigned int t_tries; error_def(ERR_DBBADFREEBLKCTR); error_def(ERR_DBMBMINCFREFIXED); block_id bm_getfree(block_id orig_hint, boolean_t *blk_used, unsigned int cw_work, cw_set_element *cs, int *cw_depth_ptr) { cw_set_element *cs1; sm_uc_ptr_t bmp; block_id bml, hint, hint_cycled, hint_limit; block_id_ptr_t b_ptr; int cw_set_top, depth, lcnt; unsigned int local_maps, map_size, n_decrements = 0, total_blks; trans_num ctn; int4 free_bit, offset; uint4 space_needed; uint4 status; srch_blk_status blkhist; total_blks = (dba_mm == cs_data->acc_meth) ? cs_addrs->total_blks : cs_addrs->ti->total_blks; if (orig_hint >= total_blks) /* for TP, hint can be > total_blks */ orig_hint = 1; hint = orig_hint; hint_cycled = DIVIDE_ROUND_UP(total_blks, BLKS_PER_LMAP); hint_limit = DIVIDE_ROUND_DOWN(orig_hint, BLKS_PER_LMAP); local_maps = hint_cycled + 2; /* for (up to) 2 wraps */ for (lcnt = 0; lcnt <= local_maps; lcnt++) { bml = bmm_find_free(hint / BLKS_PER_LMAP, (sm_uc_ptr_t)MM_ADDR(cs_data), local_maps); if ((NO_FREE_SPACE == bml) || (bml >= hint_cycled)) { /* if no free space or might have looped to original map, extend */ if ((NO_FREE_SPACE != bml) && (hint_limit < hint_cycled)) { hint_cycled = hint_limit; hint = 1; continue; } if (SS_NORMAL != (status = GDSFILEXT(cs_data->extension_size, total_blks, TRANS_IN_PROG_TRUE))) return (status); if (dba_mm == cs_data->acc_meth) return (FILE_EXTENDED); hint = total_blks; total_blks = cs_addrs->ti->total_blks; hint_cycled = DIVIDE_ROUND_UP(total_blks, BLKS_PER_LMAP); local_maps = hint_cycled + 2; /* for (up to) 2 wraps */ /* * note that you can make an optimization of not going back over the whole database and going over * only the extended section. but since it is very unlikely that a free block won't be found * in the extended section and the fact that we are starting from the extended section in either * approach and the fact that we have a GTMASSERT to check that we don't have a lot of * free blocks while doing an extend and the fact that it is very easy to make the change to do * a full-pass, the full-pass solution is currently being implemented */ lcnt = -1; /* allow it one extra pass to ensure that it can take advantage of the entension */ n_decrements++; /* used only for debugging purposes */ continue; } bml *= BLKS_PER_LMAP; if (ROUND_DOWN2(hint, BLKS_PER_LMAP) != bml) { /* not within requested map */ if ((bml < hint) && (hint_cycled)) /* wrap? - second one should force an extend for sure */ hint_cycled = (hint_limit < hint_cycled) ? hint_limit: 0; hint = bml + 1; /* start at beginning */ } if (ROUND_DOWN2(total_blks, BLKS_PER_LMAP) == bml) map_size = (total_blks - bml); else map_size = BLKS_PER_LMAP; if (dollar_tlevel) { depth = cw_work; cw_set_top = *cw_depth_ptr; if (depth < cw_set_top) tp_get_cw(cs, cw_work, &cs1); for (; depth < cw_set_top; depth++, cs1 = cs1->next_cw_set) { /* do tp front to back because list is more efficient than tp_get_cw and forward pointers exist */ if (bml == cs1->blk) { TRAVERSE_TO_LATEST_CSE(cs1); break; } } if (depth >= cw_set_top) { assert(cw_set_top == depth); depth = 0; } } else { for (depth = *cw_depth_ptr - 1; depth >= cw_work; depth--) { /* do non-tp back to front, because of adjacency */ if (bml == (cs + depth)->blk) { cs1 = cs + depth; break; } } if (depth < cw_work) { assert(cw_work - 1 == depth); depth = 0; } } if (0 == depth) { ctn = cs_addrs->ti->curr_tn; if (!(bmp = t_qread(bml, (sm_int_ptr_t)&blkhist.cycle, &blkhist.cr))) return MAP_RD_FAIL; if ((BM_SIZE(BLKS_PER_LMAP) != ((blk_hdr_ptr_t)bmp)->bsiz) || (LCL_MAP_LEVL != ((blk_hdr_ptr_t)bmp)->levl)) { assert(CDB_STAGNATE > t_tries); rdfail_detail = cdb_sc_badbitmap; return MAP_RD_FAIL; } offset = 0; } else { bmp = cs1->old_block; b_ptr = (block_id_ptr_t)(cs1->upd_addr); b_ptr += cs1->reference_cnt - 1; offset = *b_ptr + 1; } if (offset < map_size) { free_bit = bm_find_blk(offset, (sm_uc_ptr_t)bmp + SIZEOF(blk_hdr), map_size, blk_used); if (MAP_RD_FAIL == free_bit) return MAP_RD_FAIL; } else free_bit = NO_FREE_SPACE; if (NO_FREE_SPACE != free_bit) break; if ((hint = bml + BLKS_PER_LMAP) >= total_blks) /* if map is full, start at 1st blk in next map */ { /* wrap - second one should force an extend for sure */ hint = 1; if (hint_cycled) hint_cycled = (hint_limit < hint_cycled) ? hint_limit: 0; } if ((0 == depth) && cs_addrs->now_crit) /* if it's from the cw_set, its state is murky */ { assert(FALSE); send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(3) ERR_DBMBMINCFREFIXED, 1, bml); bit_clear(bml / BLKS_PER_LMAP, MM_ADDR(cs_data)); /* repair master map error */ } } /* If not in the final retry, it is possible that free_bit is >= map_size, e.g., if the buffer holding the bitmap block * gets recycled with a non-bitmap block in which case the bit that bm_find_blk returns could be greater than map_size. * But, this should never happen in final retry. */ if ((map_size <= (uint4)free_bit) && (CDB_STAGNATE <= t_tries)) { /* Bad free bit. */ assert((NO_FREE_SPACE == free_bit) && (lcnt > local_maps)); /* All maps full, should have extended */ assertpro(FALSE); } if (0 != depth) { b_ptr = (block_id_ptr_t)(cs1->upd_addr); b_ptr += cs1->reference_cnt++; *b_ptr = free_bit; } else { space_needed = (BLKS_PER_LMAP + 1) * SIZEOF(block_id); if (dollar_tlevel) { ENSURE_UPDATE_ARRAY_SPACE(space_needed); /* have brackets for "if" for macros */ } BLK_ADDR(b_ptr, space_needed, block_id); memset(b_ptr, 0, space_needed); *b_ptr = free_bit; blkhist.blk_num = bml; blkhist.buffaddr = bmp; /* cycle and cr have already been assigned from t_qread */ t_write_map(&blkhist, (uchar_ptr_t)b_ptr, ctn, 1); /* last parameter 1 is what cs->reference_cnt gets set to */ } return bml + free_bit; } /* This routine returns whether the free_blocks counter in the file-header is ok (TRUE) or not (FALSE). * If not, it corrects it. This assumes cs_addrs, cs_data and gv_cur_region to point to the region of interest. * It also assumes that the master-map is correct and finds out non-full local bitmaps and counts the number of * free blocks in each of them and sums them up to determine the perceived correct free_blocks count. * The reason why this is ok is that even if the master-map incorrectly reports a local bitmap as full, our new free_blocks * count will effectively make the free space in that local-bitmap invisible and make a gdsfilext necessary and valid. * A later mupip integ will scavenge that invisible space for us. The worst that can therefore happen is that we will transiently * not be using up existing space. But we will always ensure that the free_blocks counter goes in sync with the master-map. */ boolean_t is_free_blks_ctr_ok(void) { boolean_t blk_used; block_id bml, free_bit, free_bml, maxbitsthismap; cache_rec_ptr_t cr; int cycle; sm_uc_ptr_t bmp; unsigned int local_maps, total_blks, free_blocks; assert(&FILE_INFO(gv_cur_region)->s_addrs == cs_addrs && cs_addrs->hdr == cs_data && cs_addrs->now_crit); total_blks = (dba_mm == cs_data->acc_meth) ? cs_addrs->total_blks : cs_addrs->ti->total_blks; local_maps = DIVIDE_ROUND_UP(total_blks, BLKS_PER_LMAP); for (free_blocks = 0, free_bml = 0; free_bml < local_maps; free_bml++) { bml = bmm_find_free((uint4)free_bml, (sm_uc_ptr_t)MM_ADDR(cs_data), local_maps); if (bml < free_bml) break; free_bml = bml; bml *= BLKS_PER_LMAP; if (!(bmp = t_qread(bml, (sm_int_ptr_t)&cycle, &cr)) || (BM_SIZE(BLKS_PER_LMAP) != ((blk_hdr_ptr_t)bmp)->bsiz) || (LCL_MAP_LEVL != ((blk_hdr_ptr_t)bmp)->levl)) { assert(FALSE); /* In pro, we will simply skip counting this local bitmap. */ continue; } assert(free_bml <= (local_maps - 1)); maxbitsthismap = (free_bml != (local_maps - 1)) ? BLKS_PER_LMAP : total_blks - bml; for (free_bit = 0; free_bit < maxbitsthismap; free_bit++) { free_bit = bm_find_blk(free_bit, (sm_uc_ptr_t)bmp + SIZEOF(blk_hdr), maxbitsthismap, &blk_used); assert(NO_FREE_SPACE <= free_bit); if (0 > free_bit) break; free_blocks++; } } assert(cs_addrs->ti->free_blocks == free_blocks); if (cs_addrs->ti->free_blocks != free_blocks) { send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_DBBADFREEBLKCTR, 4, DB_LEN_STR(gv_cur_region), cs_addrs->ti->free_blocks, free_blocks); cs_addrs->ti->free_blocks = free_blocks; return FALSE; } return TRUE; } fis-gtm-V6.0-003/sr_port/bm_getfree.h0000644000032200000250000000130012201176154016273 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef BM_GETFREE_INCLUDED #define BM_GETFREE_INCLUDED block_id bm_getfree(block_id orig_hint, boolean_t *blk_used, unsigned int cw_work, cw_set_element *cs, int *cw_depth_ptr); boolean_t is_free_blks_ctr_ok(void); #endif /* BM_GETFREE_INCLUDED */ fis-gtm-V6.0-003/sr_port/bm_setmap.c0000644000032200000250000000660212201176154016150 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "cdb_sc.h" #include "gdsroot.h" #include "gdsblk.h" #include "gdsbml.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdscc.h" #include "filestruct.h" #include "jnl.h" #include "gdsblkops.h" /* for CHECK_AND_RESET_UPDATE_ARRAY macro */ /* Include prototypes */ #include "t_qread.h" #include "t_end.h" #include "t_retry.h" #include "t_begin_crit.h" #include "t_write_map.h" #include "gvcst_map_build.h" #include "mm_read.h" GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF char *update_array, *update_array_ptr; GBLREF cw_set_element cw_set[]; GBLREF unsigned char rdfail_detail; GBLREF jnl_format_buffer *non_tp_jfb_ptr; void bm_setmap(block_id bml, block_id blk, int4 busy) { sm_uc_ptr_t bmp; trans_num ctn; srch_hist alt_hist; srch_blk_status blkhist; /* block-history to fill in for t_write_map which uses "blk_num", "buffaddr", "cr", "cycle" */ cw_set_element *cse; int lbm_status; /* local bitmap status of input "blk" i.e. BUSY or FREE or RECYCLED */ int4 reference_cnt; uint4 bitnum; error_def(ERR_DSEFAIL); t_begin_crit(ERR_DSEFAIL); ctn = cs_addrs->ti->curr_tn; if (!(bmp = t_qread(bml, &blkhist.cycle, &blkhist.cr))) t_retry((enum cdb_sc)rdfail_detail); blkhist.blk_num = bml; blkhist.buffaddr = bmp; alt_hist.h[0].blk_num = 0; /* Need for calls to T_END for bitmaps */ CHECK_AND_RESET_UPDATE_ARRAY; /* reset update_array_ptr to update_array */ bitnum = blk - bml; /* Find out current status in order to determine if there is going to be a state transition */ assert(ROUND_DOWN2(blk, cs_data->bplmap) == bml); GET_BM_STATUS(bmp, bitnum, lbm_status); switch(lbm_status) { case BLK_BUSY: reference_cnt = busy ? 0 : -1; break; case BLK_FREE: case BLK_MAPINVALID: case BLK_RECYCLED: assert(BLK_MAPINVALID != lbm_status); reference_cnt = busy ? 1 : 0; break; default: assert(FALSE); break; } if (reference_cnt) { /* Initialize update array with non-zero bitnum only if reference_cnt is non-zero. */ assert(bitnum); *((block_id_ptr_t)update_array_ptr) = bitnum; update_array_ptr += SIZEOF(block_id); } /* Terminate update array unconditionally with zero bitnum. */ *((block_id_ptr_t)update_array_ptr) = 0; update_array_ptr += SIZEOF(block_id); t_write_map(&blkhist, (uchar_ptr_t)update_array, ctn, reference_cnt); if (JNL_ENABLED(cs_data)) { cse = (cw_set_element *)(&cw_set[0]); cse->new_buff = (unsigned char *)non_tp_jfb_ptr->buff; memcpy(cse->new_buff, bmp, ((blk_hdr_ptr_t)bmp)->bsiz); gvcst_map_build((uint4 *)cse->upd_addr, (uchar_ptr_t)cse->new_buff, cse, cs_addrs->ti->curr_tn); cse->done = TRUE; } /* Call t_end till it succeeds or aborts (error will be reported) */ while ((trans_num)0 == t_end(&alt_hist, NULL, TN_NOT_SPECIFIED)) ; return; } fis-gtm-V6.0-003/sr_port/bm_update.h0000644000032200000250000000110712201176154016141 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __BM_UPDATE_H__ #define __BM_UPDATE_H__ void bm_update(cw_set_element *cs, sm_uc_ptr_t lclmap, boolean_t is_mm); #endif fis-gtm-V6.0-003/sr_port/bml_busy.c0000644000032200000250000000210712201176154016011 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsbml.h" /* Include prototypes */ #include "bit_clear.h" #include "wbox_test_init.h" GBLREF boolean_t dse_running; uint4 bml_busy(uint4 setbusy, sm_uc_ptr_t map) { uint4 ret, ret1; setbusy *= BML_BITS_PER_BLK; ret = bit_clear(setbusy, map); ret1 = bit_clear(setbusy + 1, map); /* In case of a valid snapshot, assert that only a RECYCLED or FREE block gets marked as BUSY (dse is an exception). */ assert((ret && ret1) || (ret && !ret1) || dse_running || (WBTEST_INVALID_SNAPSHOT_EXPECTED == gtm_white_box_test_case_number)); return ret; } fis-gtm-V6.0-003/sr_port/bml_find_busy.c0000644000032200000250000000666312201176154017024 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gdsbml.h" #include "bml_find_busy.h" #define MAX_FFS_SIZE 32 /* Returns the location of the first clear bit in the field. */ /* The search starts at the hint and wraps if necessary. */ int4 bml_find_busy(int4 hint, uchar_ptr_t base_addr, int4 total_blks) { uchar_ptr_t ptr, top; unsigned char valid; int4 bits, hint_pos, total_bits, ret_val; hint_pos = hint * BML_BITS_PER_BLK; total_bits = total_blks * BML_BITS_PER_BLK; if (hint_pos >= total_bits) hint_pos = 0; hint_pos = hint_pos / 8; for (ptr = base_addr + hint_pos, top = base_addr + (total_bits + 7) / 8 - 1; ptr < top; ptr++) { if ((*ptr & 0x3) == 0) { ret_val = (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK)); if (ret_val >= hint) return ret_val; } if ((*ptr & 0xc) == 0) { ret_val = (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 1); if (ret_val >= hint) return ret_val; } if ((*ptr & 0x30) == 0) { ret_val = (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 2); if (ret_val >= hint) return ret_val; } if ((*ptr & 0xc0) == 0) { ret_val = (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 3); if (ret_val >= hint) return ret_val; } } bits = total_bits % 8; if (bits == 6) valid = *ptr | 0xc0; else if (bits == 4) valid = *ptr | 0xf0; else if (bits == 2) valid = *ptr | 0xfc; else valid = *ptr; if ((valid & 0x3) == 0) { ret_val = (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK)); if (ret_val >= hint) return ret_val; } if ((valid & 0xc) == 0) { ret_val = (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 1); if (ret_val >= hint) return ret_val; } if ((valid & 0x30) == 0) { ret_val = (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 2); if (ret_val >= hint) return ret_val; } if ((valid & 0xc0) == 0) { ret_val = (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 3); if (ret_val >= hint && ret_val <= total_blks) return ret_val; } for (ptr = base_addr, top = base_addr + hint_pos; ptr < top; ptr++) { if ((*ptr & 0x3) == 0) { return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK)); } else if ((*ptr & 0xc) == 0) { return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 1); } else if ((*ptr & 0x30) == 0) { return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 2); } else if ((*ptr & 0xc0) == 0) { return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 3); } } bits = hint % 4; if (bits == 3) valid = *ptr | 0xc0; else if (bits == 2) valid = *ptr | 0xf0; else if (bits == 1) valid = *ptr | 0xfc; else valid = *ptr; if ((valid & 0x3) == 0) return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK)); if ((valid & 0xc) == 0) return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 1); if ((valid & 0x30) == 0) return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 2); if ((valid & 0xc0) == 0) return (int4)((ptr - base_addr) * (8 / BML_BITS_PER_BLK) + 3); return -1; } fis-gtm-V6.0-003/sr_port/bml_find_busy.h0000644000032200000250000000110612201176154017014 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __BML_FIND_BUSY_H__ #define __BML_FIND_BUSY_H__ int4 bml_find_busy(int4 hint, uchar_ptr_t base_addr, int4 total_blks); #endif fis-gtm-V6.0-003/sr_port/bml_find_free.c0000644000032200000250000000426312201176154016755 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2008 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gdsbml.h" #define RETURN_IF_FREE(valid, ptr, base_addr) \ { \ int4 bits; \ \ if (valid) \ { \ if (valid > THREE_BLKS_BITMASK) \ bits = 3; \ else if (valid > TWO_BLKS_BITMASK) \ bits = 2; \ else if (valid > ONE_BLK_BITMASK) \ bits = 1; \ else \ bits = 0; \ return (int4)((ptr - base_addr) * (BITS_PER_UCHAR / BML_BITS_PER_BLK) + bits); \ } \ } /* Returns the location of the first set bit in the field. The search starts at the hint and wraps if necessary. * If a non-null update array is passed, that is also taken into account while figuring out if any free block is available. */ int4 bml_find_free(int4 hint, uchar_ptr_t base_addr, int4 total_bits) { uchar_ptr_t ptr, top; unsigned char valid; int4 bits; hint *= BML_BITS_PER_BLK; hint = hint / BITS_PER_UCHAR; total_bits *= BML_BITS_PER_BLK; if (hint > total_bits) hint = 0; for (ptr = base_addr + hint, top = base_addr + DIVIDE_ROUND_UP(total_bits, BITS_PER_UCHAR) - 1; ptr < top; ptr++) { valid = *ptr; RETURN_IF_FREE(valid, ptr, base_addr); } if (*ptr) /* Special processing for last byte as may be only partially valid */ { bits = total_bits % BITS_PER_UCHAR; if (bits == 6) valid = *ptr & THREE_BLKS_BITMASK; else if (bits == 4) valid = *ptr & TWO_BLKS_BITMASK; else if (bits == 2) valid = *ptr & ONE_BLK_BITMASK; else valid = *ptr; RETURN_IF_FREE(valid, ptr, base_addr); } if (hint) { for (ptr = base_addr, top = base_addr + hint; ptr < top; ptr++) { valid = *ptr; RETURN_IF_FREE(valid, ptr, base_addr); } } return NO_FREE_SPACE; } fis-gtm-V6.0-003/sr_port/bml_free.c0000644000032200000250000000172712201176154015757 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsbml.h" /* Include prototypes */ #include "bit_set.h" #include "bit_clear.h" GBLREF boolean_t dse_running; uint4 bml_free(uint4 setfree, sm_uc_ptr_t map) { uint4 ret, ret1; setfree *= BML_BITS_PER_BLK; ret = bit_set(setfree, map); ret1 = bit_clear(setfree + 1, map); /* Assert that only a BUSY or RECYCLED block gets marked as FREE (dse is an exception) */ assert((!ret && !ret1) || (ret && ret1) || dse_running); return ret; } fis-gtm-V6.0-003/sr_port/bml_init.c0000644000032200000250000000550412201176154015776 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2008 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #ifdef UNIX #include /* for DSK_WRITE macro */ #elif defined(VMS) #include "efn.h" /* for DSK_WRITE macro */ #else #error UNSUPPORTED PLATFORM #endif #include "gdsroot.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsbml.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF jnl_gbls_t jgbl; int4 bml_init(block_id bml) { blk_hdr_ptr_t ptr; uint4 size; uint4 status; trans_num blktn; size = BM_SIZE(cs_data->bplmap); /* Allocate full block .. bml_newmap will set the write size, dsk_write will write part or all of it as appropriate. */ ptr = (blk_hdr_ptr_t)malloc(cs_addrs->hdr->blk_size); /* We are about to create a local bitmap. Setting its block transaction number to the current database transaction * number gives us a clear history of when this bitmap got created. There are two exceptions. * 1) If before-image journaling, it implies the possibility of using backward recovery/rollback both of which can * take the database to a transaction number MUCH BEFORE the current database transaction number. In that case, the * recovered database will have DBTNTOOLG integrity errors since the bitmap block's transaction number will be greater * than the post-recovery database transaction number. Since we have no control over what transaction number backward * recovery can take the database to, we set the bitmap block transaction number to 0 (the least possible) for the * before-image journaling case. * 2) If in forward recovery, then the database current transaction number is not incremented in gdsfilext (the caller * of this function) so we have to create the local bitmap blocks with curr_tn-1 in order to avoid a DBTNTOOLG error. */ if (JNL_ENABLED(cs_data) && cs_addrs->jnl && cs_addrs->jnl->jnl_buff && cs_addrs->jnl->jnl_buff->before_images) blktn = 0; else if (jgbl.forw_phase_recovery && !JNL_ENABLED(cs_data)) /* forward recovery */ blktn = cs_data->trans_hist.curr_tn - 1; else blktn = cs_data->trans_hist.curr_tn; bml_newmap(ptr, size, blktn); /* status holds the status of any error return from dsk_write */ DSK_WRITE_NOCACHE(gv_cur_region, bml, (sm_uc_ptr_t)ptr, cs_data->desired_db_format, status); free(ptr); return status; } fis-gtm-V6.0-003/sr_port/bml_newmap.c0000644000032200000250000000177112201176154016324 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsbml.h" #include "gdsdbver.h" void bml_newmap(blk_hdr_ptr_t ptr, uint4 size, trans_num curr_tn) { sm_uc_ptr_t bptr; /* --- similar logic exists in mupip_restore.c, which need to pick up any new updates here --- */ ptr->bver = GDSVCURR; ptr->bsiz = size; ptr->levl = LCL_MAP_LEVL; ptr->tn = curr_tn; bptr = (sm_uc_ptr_t)ptr + SIZEOF(blk_hdr); size -= SIZEOF(blk_hdr); *bptr++ = THREE_BLKS_FREE; memset(bptr, FOUR_BLKS_FREE, size - 1); } fis-gtm-V6.0-003/sr_port/bml_recycled.c0000644000032200000250000000152012201176154016617 0ustar librarygtc/**************************************************************** * * * Copyright 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsbml.h" /* Include prototypes */ #include "bit_set.h" GBLREF boolean_t dse_running; uint4 bml_recycled(uint4 setfree, sm_uc_ptr_t map) { uint4 ret, ret1; setfree *= BML_BITS_PER_BLK; ret = bit_set(setfree, map); ret1 = bit_set(setfree + 1, map); assert((!ret && !ret1) || dse_running); return ret; } fis-gtm-V6.0-003/sr_port/bml_status_check.c0000644000032200000250000000502612201176154017512 0ustar librarygtc/**************************************************************** * * * Copyright 2007, 2008 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdskill.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gdsblk.h" #include "gdsbml.h" #include "gdscc.h" #include "mm_read.h" #include "bml_status_check.h" #define MAX_FFS_SIZE 32 GBLREF sgmnt_addrs *cs_addrs; /* Checks that a block that we have acquired is marked RECYCLED/FREE in the database * and that an existing block that we are updating is marked BUSY in the database. * For BG, the check is done only if the bitmap block is available in the cache AND is not being concurrently updated. */ void bml_status_check(cw_set_element *cs) { block_id bmlblk, blk; cache_rec_ptr_t bmlcr; blk_hdr_ptr_t bmlbuff; boolean_t is_mm; int4 bml_status; is_mm = (dba_mm == cs_addrs->hdr->acc_meth); assert(gds_t_create != cs->mode); if ((gds_t_acquired == cs->mode) || (gds_t_write == cs->mode)) { bmlblk = ROUND_DOWN2(cs->blk, BLKS_PER_LMAP); assert(IS_BITMAP_BLK(bmlblk)); blk = cs->blk - bmlblk; assert(blk); if (!is_mm) { bmlcr = db_csh_get(bmlblk); bmlbuff = ((NULL != bmlcr) && (CR_NOTVALID != (sm_long_t)bmlcr) && (0 > bmlcr->read_in_progress) && !bmlcr->in_tend) ? (blk_hdr_ptr_t)GDS_REL2ABS(bmlcr->buffaddr) : NULL; } else { bmlbuff = (blk_hdr_ptr_t)mm_read(bmlblk); /* mm_read would have incremented the GVSTATS n_dsk_read counter. But we dont want that to happen * because this function is invoked only in debug builds and yet we want the same counter * value for both pro and dbg builds. So undo that action immediately. */ INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_dsk_read, (gtm_uint64_t)-1);/* note the -1 causes the undo */ assert(NULL != bmlbuff); } if (NULL != bmlbuff) { assert(LCL_MAP_LEVL == bmlbuff->levl); assert(BM_SIZE(cs_addrs->hdr->bplmap) == bmlbuff->bsiz); GET_BM_STATUS(bmlbuff, blk, bml_status); assert(BLK_MAPINVALID != bml_status); assert((gds_t_acquired != cs->mode) || (BLK_BUSY != bml_status)); assert((gds_t_acquired == cs->mode) || (BLK_BUSY == bml_status)); } } } fis-gtm-V6.0-003/sr_port/bml_status_check.h0000644000032200000250000000106112201176154017512 0ustar librarygtc/**************************************************************** * * * Copyright 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __BML_STATUS_CHECK_H__ #define __BML_STATUS_CHECK_H__ void bml_status_check(cw_set_element *cs); #endif fis-gtm-V6.0-003/sr_port/bmm_find_free.c0000644000032200000250000000254012201176154016752 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gdsbml.h" #include "min_max.h" #include "gtm_ffs.h" #include "bmm_find_free.h" #define MAX_FFS_SIZE 32 /* Returns the location of the first set bit in the field. */ /* The search starts at the hint and wraps if necessary. */ int4 bmm_find_free(uint4 hint, uchar_ptr_t base_addr, uint4 total_bits) { int4 answer, width; uint4 start, top; if (hint >= total_bits) hint = 0; for (start = hint, top = total_bits; top; start = 0, top = hint, hint = 0) { /* one or two passes through outer loop; second is a wrap to the beginning */ for (width = MIN(top, ROUND_DOWN2(start, MAX_FFS_SIZE) + MAX_FFS_SIZE) - start; width > 0; start += width, width = MIN(top - start, MAX_FFS_SIZE)) { answer = gtm_ffs(start, base_addr, width); if (NO_FREE_SPACE != answer) return answer; } } assert(NO_FREE_SPACE == answer); return NO_FREE_SPACE; } fis-gtm-V6.0-003/sr_port/bmm_find_free.h0000644000032200000250000000110712201176154016755 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __BMM_FIND_FREE_H__ #define __BMM_FIND_FREE_H__ int4 bmm_find_free(uint4 hint, uchar_ptr_t base_addr, uint4 total_bits); #endif fis-gtm-V6.0-003/sr_port/bmm_init.c0000644000032200000250000000145212201176154015775 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gdsbt.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsfhead.h" #include "gdsbml.h" GBLREF sgmnt_data *cs_data; void bmm_init(void) { assert(cs_data && cs_data->master_map_len); memset(MM_ADDR(cs_data), BMP_EIGHT_BLKS_FREE, MASTER_MAP_SIZE(cs_data)); return; } fis-gtm-V6.0-003/sr_port/bool_expr.c0000644000032200000250000000160612201176154016171 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" /* needed by INCREMENT_EXPR_DEPTH */ #include "compiler.h" #include "opcode.h" int bool_expr(boolean_t op, oprtype *addr) { oprtype x; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; INCREMENT_EXPR_DEPTH; if (!eval_expr(&x)) { DECREMENT_EXPR_DEPTH; return FALSE; } assert(TRIP_REF == x.oprclass); coerce(&x, OCT_BOOL); bx_tail(x.oprval.tref, op, addr); DECREMENT_EXPR_DEPTH; return TRUE; } fis-gtm-V6.0-003/sr_port/break.h0000644000032200000250000000116112201176154015265 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #define BREAK_MASK (1 << 0) #define ZBREAK_MASK (1 << 1) #define DEVBREAK_MASK (1 << 2) #define ZSTBREAK_MASK (1 << 3) #define TRIGGER_ZBREAK_REMOVED_MASK (1 << 4) fis-gtm-V6.0-003/sr_port/bt_get.c0000644000032200000250000000256012201176154015444 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* This function returns a pointer to the bt_rec entry or 0 if not found. */ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsbgtr.h" /* for the BG_TRACE_PRO macros */ GBLREF sgmnt_addrs *cs_addrs; bt_rec_ptr_t bt_get(int4 block) /* block = block # to get */ { register sgmnt_addrs *csa; bt_rec_ptr_t bt; int lcnt; csa = cs_addrs; assert(csa->now_crit); bt = csa->bt_header + (block % csa->hdr->bt_buckets); assert(bt->blk == BT_QUEHEAD); for (lcnt = csa->hdr->n_bts; lcnt > 0; lcnt--) { bt = (bt_rec_ptr_t)((sm_uc_ptr_t) bt + bt->blkque.fl); if (bt->blk == block) return bt; if (bt->blk == BT_QUEHEAD) return NULL; } SET_TRACEABLE_VAR(csa->nl->wc_blocked, TRUE); BG_TRACE_PRO_ANY(csa, wc_blocked_bt_get); return NULL; /* actually should return BT_INVALID or some such value but callers check only for NULL */ } fis-gtm-V6.0-003/sr_port/bt_init.c0000644000032200000250000000175712201176154015637 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" void bt_init(sgmnt_addrs *csa) { sgmnt_data_ptr_t csd; csd = csa->hdr; csa->ti = &csd->trans_hist; if (dba_mm != csd->acc_meth) { /* BT structures are NOT maintained for MM */ csa->bt_header = (bt_rec_ptr_t)((sm_uc_ptr_t) csd + csa->nl->bt_header_off); csa->bt_base = (bt_rec_ptr_t)((sm_uc_ptr_t) csd + csa->nl->bt_base_off); csa->th_base = (th_rec_ptr_t)((sm_uc_ptr_t) csd + csa->nl->th_base_off); } return; } fis-gtm-V6.0-003/sr_port/bt_malloc.c0000644000032200000250000000255312201176154016136 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" void bt_malloc(sgmnt_addrs *csa) { unsigned int n; sgmnt_data_ptr_t csd; csd = csa->hdr; /* check that the file header is quad word aligned */ if ((-(SIZEOF(uint4) * 2) & (sm_long_t)csd) != (sm_long_t)csd) GTMASSERT; if ((-(SIZEOF(uint4) * 2) & SIZEOF_FILE_HDR(csd)) != SIZEOF_FILE_HDR(csd)) GTMASSERT; csa->nl->bt_header_off = (n = (uint4)(SIZEOF_FILE_HDR(csd))); csa->nl->th_base_off = (n += csd->bt_buckets * SIZEOF(bt_rec)); /* hash table */ csa->nl->th_base_off += SIZEOF(que_ent); /* tnque comes after fl and bl of blkque */ csa->nl->bt_base_off = (n += SIZEOF(bt_rec)); /* th_queue anchor referenced above */ assert((n += (csd->n_bts * SIZEOF(bt_rec))) == (SIZEOF_FILE_HDR(csd)) + (BT_SIZE(csd))); /* DON'T use n after this */ bt_init(csa); bt_refresh(csa, TRUE); return; } fis-gtm-V6.0-003/sr_port/bt_put.c0000644000032200000250000001101412201176154015467 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdskill.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdscc.h" #include "filestruct.h" #include "gdsbgtr.h" #include "send_msg.h" #include "relqop.h" #include "wcs_recover.h" #include "wcs_get_space.h" #include "jnl.h" #include "wbox_test_init.h" #ifdef DEBUG static int4 entry_count = 0; #endif GBLREF volatile boolean_t in_wcs_recover; /* TRUE if in "wcs_recover" */ GBLREF uint4 process_id; GBLREF jnl_gbls_t jgbl; error_def(ERR_BTFAIL); error_def(ERR_WCBLOCKED); bt_rec_ptr_t bt_put(gd_region *reg, int4 block) { bt_rec_ptr_t bt, q0, q1, hdr; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; cache_rec_ptr_t cr; th_rec_ptr_t th; trans_num lcl_tn; uint4 lcnt; csa = (sgmnt_addrs *)&FILE_INFO(reg)->s_addrs; csd = csa->hdr; assert(csa->now_crit || csd->clustered); assert(dba_mm != csa->hdr->acc_meth); lcl_tn = csa->ti->curr_tn; hdr = csa->bt_header + (block % csd->bt_buckets); assert(BT_QUEHEAD == hdr->blk); for (lcnt = 0, bt = (bt_rec_ptr_t)((sm_uc_ptr_t)hdr + hdr->blkque.fl); ; bt = (bt_rec_ptr_t)((sm_uc_ptr_t)bt + bt->blkque.fl), lcnt++) { if (BT_QUEHEAD == bt->blk) { /* there is no matching bt */ assert(bt == hdr); bt = (bt_rec_ptr_t)((sm_uc_ptr_t)(csa->th_base) + csa->th_base->tnque.fl - SIZEOF(th->tnque)); if (CR_NOTVALID != bt->cache_index) { /* the oldest bt is still valid */ assert(!in_wcs_recover); cr = (cache_rec_ptr_t)GDS_ANY_REL2ABS(csa, bt->cache_index); if (cr->dirty) { /* get it written so it can be reused */ BG_TRACE_PRO_ANY(csa, bt_put_flush_dirty); if (FALSE == wcs_get_space(reg, 0, cr)) { assert(csa->nl->wc_blocked); /* only reason we currently know * why wcs_get_space could fail */ assert(gtm_white_box_test_case_enabled); BG_TRACE_PRO_ANY(csa, wcb_bt_put); send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_bt_put"), process_id, &lcl_tn, DB_LEN_STR(reg)); return NULL; } } bt->cache_index = CR_NOTVALID; cr->bt_index = 0; } q0 = (bt_rec_ptr_t)((sm_uc_ptr_t)bt + bt->blkque.fl); q1 = (bt_rec_ptr_t)remqt((que_ent_ptr_t)q0); if (EMPTY_QUEUE == (sm_long_t)q1) rts_error(VARLSTCNT(3) ERR_BTFAIL, 1, 1); bt->blk = block; bt->killtn = lcl_tn; insqt((que_ent_ptr_t)bt, (que_ent_ptr_t)hdr); th = (th_rec_ptr_t)remqh((que_ent_ptr_t)csa->th_base); assertpro(EMPTY_QUEUE != (sm_long_t)th); break; } if (bt->blk == block) { /* bt_put should never be called twice for the same block with the same lcl_tn. This is because * t_end/tp_tend update every block only once as part of each update transaction. Assert this. * The two exceptions are * a) Forward journal recovery which simulates a 2-phase M-kill where the same block * could get updated in both phases (example bitmap block gets updated for blocks created * within the TP transaction as well as for blocks that are freed up in the 2nd phase of * the M-kill) with the same transaction number. This is because although GT.M would have * updated the same block with different transaction numbers in the two phases, forward * recovery will update it with the same tn and instead increment the db tn on seeing the * following INCTN journal record(s). * b) Cache recovery (wcs_recover). It could call bt_put more than once for the same block * and potentially with the same tn. This is because the state of the queues is questionable * and there could be more than one cache record for a given block number. */ assert(in_wcs_recover || (bt->tn < lcl_tn) || (jgbl.forw_phase_recovery && !JNL_ENABLED(csa))); q0 = (bt_rec_ptr_t)((sm_uc_ptr_t)bt + bt->tnque.fl); th = (th_rec_ptr_t)remqt((que_ent_ptr_t)((sm_uc_ptr_t)q0 + SIZEOF(th->tnque))); assertpro(EMPTY_QUEUE != (sm_long_t)th); break; } if (0 == bt->blkque.fl) rts_error(VARLSTCNT(3) ERR_BTFAIL, 1, 2); if (lcnt >= csd->n_bts) rts_error(VARLSTCNT(3) ERR_BTFAIL, 1, 3); } insqt((que_ent_ptr_t)th, (que_ent_ptr_t)csa->th_base); bt->tn = lcl_tn; return bt; } fis-gtm-V6.0-003/sr_port/bt_refresh.c0000644000032200000250000000314012201176154016316 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "longset.h" #include "relqop.h" /* Refresh the database cache records in the shared memory. If init = TRUE, do the longset and initialize all the forward and * backward links. If init = FALSE, reset only the needed fields. */ void bt_refresh(sgmnt_addrs *csa, boolean_t init) { sgmnt_data_ptr_t csd; bt_rec_ptr_t ptr, top, bt1; csd = csa->hdr; assert(dba_bg == csd->acc_meth); if (init) longset((uchar_ptr_t)csa->bt_header, (csd->bt_buckets + csd->n_bts + 1) * SIZEOF(bt_rec), 0); for (ptr = csa->bt_header, top = ptr + csd->bt_buckets + 1; ptr < top; ptr++) ptr->blk = BT_QUEHEAD; for (ptr = csa->bt_base, bt1 = csa->bt_header, top = ptr + csd->n_bts; ptr < top ; ptr++, bt1++) { ptr->blk = BT_NOTVALID; ptr->cache_index = CR_NOTVALID; ptr->tn = ptr->killtn = 0; if (init) { insqt((que_ent_ptr_t)ptr, (que_ent_ptr_t)bt1); insqt((que_ent_ptr_t)((sm_uc_ptr_t)ptr + (2 * SIZEOF(sm_off_t))), (que_ent_ptr_t)csa->th_base); } } SET_OLDEST_HIST_TN(csa, csa->ti->curr_tn - 1); csa->ti->mm_tn = 0; return; } fis-gtm-V6.0-003/sr_port/buddy_list.c0000644000032200000250000001437712201176154016353 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "buddy_list.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "relqop.h" #define MAX_MEM_SIZE_IN_BITS 63 /* the unreachable maximum size of memory (in bits) */ void initialize_list(buddy_list *list, int4 elemSize, int4 initAlloc) { int4 i, maxPtrs; int4 temp; if (!initAlloc) initAlloc = 1; assert(0 < elemSize); assert(0 < initAlloc); elemSize = ROUND_UP2(elemSize, 8) ; /* make it 8 byte aligned */ temp = initAlloc; while (temp & (temp - 1)) /* floor it to a perfect power of 2 */ temp = temp & (temp - 1); if (initAlloc != temp) initAlloc = temp << 1; for (i = 0; initAlloc >> i; i++); list->initAllocBits = i - 1; list->elemSize = elemSize; list->initAlloc = initAlloc; list->cumulMaxElems = initAlloc; list->nElems = 0; /* Note: size_t typecast done below to enable 64-bit arithmetic so sizes > 4GB can be allocated */ list->ptrArray = (char **)malloc((size_t)SIZEOF(char *) * (MAX_MEM_SIZE_IN_BITS + 2)); /* +2 = +1 for holding the NULL pointer and +1 for ptrArray[0] */ memset(list->ptrArray, 0, SIZEOF(char *) * (MAX_MEM_SIZE_IN_BITS + 2)); list->ptrArrayCurr = list->ptrArray; /* Note: size_t typecast done below to enable 64-bit arithmetic so sizes > 4GB can be allocated */ list->nextFreePtr = list->ptrArray[0] = (char *)malloc((size_t)initAlloc * elemSize); list->free_que = NULL; /* initialize the list to have no free element queue */ DEBUG_ONLY(list->used_free_last_n_elements = FALSE;) DEBUG_ONLY(list->used_free_element = FALSE;) } /* Any changes to this routine need corresponding changes to the VERIFY_LIST_IS_REINITIALIZED macro (defined in buddy_list.h) */ void reinitialize_list(buddy_list *list) { assert(list); list->nElems = 0; list->cumulMaxElems = list->initAlloc; list->ptrArrayCurr = list->ptrArray; list->nextFreePtr = list->ptrArray[0]; list->free_que = NULL; /* reset the list to have no free element queue */ DEBUG_ONLY(list->used_free_last_n_elements = FALSE;) DEBUG_ONLY(list->used_free_element = FALSE;) } boolean_t free_last_n_elements(buddy_list *list, int4 num) { int4 rowElemsMax, rowElemsLeft, numLeft, nElems; char **ptrArrayCurr; assert(list); assert(!list->used_free_element); DEBUG_ONLY(list->used_free_last_n_elements = TRUE;) nElems = list->nElems; if (nElems >= num) { ptrArrayCurr = list->ptrArrayCurr; numLeft = num; rowElemsLeft = (int4)(list->nextFreePtr - ptrArrayCurr[0]) / list->elemSize; rowElemsMax = nElems - rowElemsLeft; while (numLeft >= rowElemsLeft && ptrArrayCurr != list->ptrArray) { assert(0 == rowElemsMax % list->initAlloc); numLeft -= rowElemsLeft; list->cumulMaxElems -= rowElemsMax; if (rowElemsMax != list->initAlloc) rowElemsMax = rowElemsMax >> 1; rowElemsLeft = rowElemsMax; ptrArrayCurr--; assert(rowElemsMax >= list->initAlloc); } list->nElems = nElems - num; list->ptrArrayCurr = ptrArrayCurr; list->nextFreePtr = ptrArrayCurr[0] + list->elemSize * (rowElemsLeft - numLeft); assert(list->ptrArrayCurr >= list->ptrArray); return TRUE; } else return FALSE; } char *get_new_element(buddy_list *list, int4 nElements) { char *retPtr; char **ptrArrayCurr; int4 cumulMaxElems, nElems, elemSize; if (0 >= nElements) { assert(FALSE); return NULL; } nElems = list->nElems; cumulMaxElems = list->cumulMaxElems; elemSize = list->elemSize; if (nElems + nElements <= cumulMaxElems) { retPtr = list->nextFreePtr; list->nextFreePtr += nElements * elemSize; list->nElems = nElems + nElements; } else { do { ptrArrayCurr = ++list->ptrArrayCurr; /* Note: size_t typecast done below to enable 64-bit arithmetic so sizes > 4GB can be allocated */ if (!(retPtr = *ptrArrayCurr)) retPtr = *ptrArrayCurr = (char *)malloc((size_t)cumulMaxElems * elemSize); nElems = cumulMaxElems; cumulMaxElems *= 2; } while (nElems + nElements > cumulMaxElems); list->nElems = nElems + nElements; list->nextFreePtr = retPtr + elemSize * nElements; list->cumulMaxElems = cumulMaxElems; } return retPtr; } char *get_new_free_element(buddy_list *list) { char *elem; assert(!list->used_free_last_n_elements); DEBUG_ONLY(list->used_free_element = TRUE;) /* Assert that each element has enough space to store a pointer. This will be used to maintain the singly linked list * of freed up elements in the buddy list. The head of this list will be list->free_que. */ assert(SIZEOF(char *) <= list->elemSize); elem = list->free_que; if (NULL != elem) { list->free_que = *(char **)elem; assert(elem != list->free_que); return elem; } return get_new_element(list, 1); } void free_element(buddy_list *list, char *elem) { assert(!list->used_free_last_n_elements); DEBUG_ONLY(list->used_free_element = TRUE;) assert(elem); assert(elem != list->free_que); /* Add it to the singly linked list of freed up elements in the buddy_list */ *(char **)elem = list->free_que; list->free_que = elem; } char *find_element(buddy_list *list, int4 index) { char **ptrArrayCurr; int4 i, initAllocBits; if (index > list->nElems) return NULL; initAllocBits = list->initAllocBits; for (i = initAllocBits; index >> i; i++); i = i - initAllocBits; return list->ptrArray[i] + list->elemSize * (index - list->initAlloc * (i ? 1 << (i-1) : 0)); } void cleanup_list(buddy_list *list) { char **curr; assert(list); if (!list || !(curr = list->ptrArray)) return; while(*curr) { free(*curr); curr++; } free(list->ptrArray); } fis-gtm-V6.0-003/sr_port/buddy_list.h0000644000032200000250000001047212201176154016350 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __BUDDY_LIST_H__ #define __BUDDY_LIST_H__ /* This is a general purpose structure used for storing a list of similar-sized structure-elements with the need for * efficiently accessing the element once we know its index. * It maintains an array of pointers "ptrArray". * The first and second pointers i.e. ptrArray[0] and ptrArray[1] point to an array containing "initAlloc" elements. * Every other pointer ptrArray[i] points to an array containing double-the-number-of-elements * as the array pointed to by ptrArray[i-1]. * This also provides for iterating through the list of elements. */ typedef struct buddy_list_struct { char **ptrArray; /* the array of pointers */ int4 elemSize; /* the size of each structure-element */ int4 initAlloc; /* the number of structures in the ptrArray[0] and ptrArray[1] */ int4 initAllocBits; /* number of bits corresponding to initAlloc */ int4 nElems; /* the current number of elements used up in the total array */ int4 cumulMaxElems; /* the maximum number of elements that can be held from the first upto the current array */ char **ptrArrayCurr; /* = &ptrArray[i] where i is the current array index in use for allocation */ char *nextFreePtr; /* pointer to the next free element in the current array. Initially = ptrArray[0] */ char *free_que; /* pointer to the singly linked list of freed-up elements */ # ifdef DEBUG /* The following two debug-only variables are present to avoid mixing of usage of the functions "free_last_n_elements" * and "get_new_free_element"/"free_element()" in the same buddy list. This is because they both use completely * different schemes to free up elements (one reduces the # of elements in the buddy list whereas the other does not * touch the # of elements but maintains an internal singly linked list of freed up elements) and they cannot coexist. */ boolean_t used_free_last_n_elements; /* TRUE if "free_last_n_elements" was called in this buddy_list */ boolean_t used_free_element; /* TRUE if "get_new_free_element" or "free_element" was called */ # endif } buddy_list; void initialize_list(buddy_list *list, int4 elemSize, int4 initAlloc); char *get_new_element(buddy_list *list, int4 nElements); char *find_element(buddy_list *list, int4 index); void cleanup_list(buddy_list *list); void reinitialize_list(buddy_list *list); /* used for reusing already allocated storage */ boolean_t free_last_n_elements(buddy_list *list, int4 num); /* to free up the last contiguous "num" elements */ void free_element(buddy_list *list, char *elem); /* to free up an element and reuse it later */ char *get_new_free_element(buddy_list *list); /* gets a freed-up element if available otherwise gets a new one */ #define CAREFUL_FREEUP_BUDDY_LIST(list) \ { \ if (NULL != list) \ FREEUP_BUDDY_LIST(list); \ } #define FREEUP_BUDDY_LIST(list) \ { \ assert(list); \ if (NULL != list) \ { \ cleanup_list(list); \ free(list); \ } \ } #define VERIFY_LIST_IS_REINITIALIZED(list) \ { /* The following code verifies the same fields initialized by the \ * function "reinitialize_list". Any changes to one should be reflected \ * in the other. \ */ \ assert((0 == list->nElems) || process_exiting); \ assert((list->cumulMaxElems == list->initAlloc) || process_exiting); \ assert((list->ptrArrayCurr == list->ptrArray) || process_exiting); \ assert((list->nextFreePtr == list->ptrArray[0])|| process_exiting); \ assert((NULL == list->free_que) || process_exiting); \ } #define REINITIALIZE_LIST(LST) \ { \ buddy_list *lcllist; \ \ lcllist = LST; \ assert((NULL == lcllist->free_que) || lcllist->nElems); \ if (lcllist->nElems) \ reinitialize_list(lcllist); \ else \ { /* No need to reinitialize. Verify \ * that list is already initialized */ \ VERIFY_LIST_IS_REINITIALIZED(lcllist); \ } \ } #endif fis-gtm-V6.0-003/sr_port/bx_boolop.c0000644000032200000250000003013012201176176016161 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "cmd_qlf.h" #include "compiler.h" #include "opcode.h" #include "mdq.h" #include "mmemory.h" #include #include "fullbool.h" LITREF octabstruct oc_tab[]; GBLREF boolean_t run_time; GBLREF command_qualifier cmd_qlf; #define STOTEMP_IF_NEEDED(REF0, I, T1, OPND) \ { /* Input: \ * --- REF0: a boolean triple, which may have either 1 input (OC_COBOOL) or 2 (other opcodes). \ * --- I: whichever operand of REF0 we are STOTEMPing \ * --- T1: STOTEMP triple. NOOPed if not needed \ * --- OPND: operand referring to value we need need to pass as input into boolean operation \ * If OPND refers to a variable (OC_VAR), we need to STOTEMP it to protect it from subsequent side effects. \ * If it refers to a literal, and dynamic literals are enabled, we need to insert an OC_LITC anyway. Doing it \ * here in bx_boolop is convenient and ensures the OC_LITC is not skipped at run time. \ */ \ assert(TRIP_REF == OPND.oprclass); \ switch (OPND.oprval.tref->opcode) \ { \ case OC_VAR: \ T1->opcode = OC_STOTEMP; \ T1->operand[0] = OPND; \ REF0->operand[I] = put_tref(T1); \ break; \ case OC_LIT: \ if (!run_time && (cmd_qlf.qlf & CQ_DYNAMIC_LITERALS)) \ { \ T1->opcode = OC_LITC; \ T1->operand[0] = OPND; \ REF0->operand[I] = put_tref(T1); \ break; \ } \ default: \ T1->opcode = OC_NOOP; \ T1->operand[0].oprclass = NO_REF; \ REF0->operand[I] = put_tref(OPND.oprval.tref); \ } \ } void bx_boolop(triple *t, boolean_t jmp_type_one, boolean_t jmp_to_next, boolean_t sense, oprtype *addr) { boolean_t expr_fini; oprtype *adj_addr, *i, *p; tbp *tripbp; triple *ref0, *ref1, *ref2, *t0, *t1; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(((1 & sense) == sense) && ((1 & jmp_to_next) == jmp_to_next) && ((1 & jmp_type_one) == jmp_type_one)); assert((TRIP_REF == t->operand[0].oprclass) && (TRIP_REF == t->operand[1].oprclass)); if (jmp_to_next) { p = (oprtype *)mcalloc(SIZEOF(oprtype)); *p = put_tjmp(t); } else p = addr; if (!TREF(saw_side_effect) || ((OLD_SE == TREF(side_effect_handling)) && (GTM_BOOL == TREF(gtm_fullbool)))) { /* nice simple short circuit */ assert(NULL == TREF(boolchain_ptr)); bx_tail(t->operand[0].oprval.tref, jmp_type_one, p); bx_tail(t->operand[1].oprval.tref, sense, addr); t->opcode = OC_NOOP; t->operand[0].oprclass = t->operand[1].oprclass = NO_REF; return; } /* got a side effect and don't want them short circuited */ /* This code violates info hiding big-time and relies on the original technique of setting up a jump ladder * then it changes the jumps into stotemps and creates a new ladder using the saved evaluations * for the relocated jumps to use for controlling conditional transfers, When the stotemps reference mvals, * they are optimized away when possible. The most interesting part is getting the addresses for the new jump * operands (targets) - see comment below. In theory we could turn this technique on and off around each side effect, * but that's even more complicated, requiring additional instructions, and we don't predict the typical boolean * expression has enough subexpressions to justify the extra trouble, although the potential pay-back would be to * avoid unnecessary global references - again, not expecting that many in a typical boolean expresion. */ assert(TREF(shift_side_effects)); if (expr_fini = (NULL == TREF(boolchain_ptr))) /* NOTE assignment */ { /* initialize work on boolean section of the AST */ TREF(boolchain_ptr) = &(TREF(boolchain)); dqinit(TREF(boolchain_ptr), exorder); t0 = t->exorder.fl; if (NULL == TREF(bool_targ_ptr)) { /* first time - set up anchor */ TREF(bool_targ_ptr) = &(TREF(bool_targ_anchor)); /* mcalloc won't persist over multiple complies */ dqinit(TREF(bool_targ_ptr), que); } else /* queue should be empty */ assert((TREF(bool_targ_ptr) == (TREF(bool_targ_ptr))->que.fl) && (TREF(bool_targ_ptr) == (TREF(bool_targ_ptr))->que.bl)); /* ex_tail wraps bools that produce a value with OC_BOOLINIT (clr) and OC_BOOLFINI (set) */ assert((OC_BOOLFINI != t0->opcode) || ((OC_COMVAL == t0->exorder.fl->opcode) && (TRIP_REF == t0->operand[0].oprclass))); } for (i = t->operand; i < ARRAYTOP(t->operand); i++) { assert(NULL != TREF(boolchain_ptr)); t1 = i->oprval.tref; if (&(t->operand[0]) == i) bx_tail(t1, jmp_type_one, p); /* do normal transform */ else { /* operand[1] */ bx_tail(t1, sense, addr); /* do normal transform */ if (!expr_fini) break; /* only need to relocate last operand[1] */ } if (OC_NOOP == t1->opcode) { /* the technique of sprinkling noops means fishing around for the actual instruction */ do { t1 = t1->exorder.bl; assert(TREF(curtchain) != t1->exorder.bl); } while (OC_NOOP == t1->opcode); if ((oc_tab[t1->opcode].octype & OCT_JUMP) && (OC_JMPTSET != t1->opcode) && (OC_JMPTCLR != t1->opcode)) t1 = t1->exorder.bl; if (OC_NOOP == t1->opcode) { for (t1 = i->oprval.tref; OC_NOOP == t1->opcode; t1 = t1->exorder.fl) assert(TREF(curtchain) != t1->exorder.fl); } } assert(OC_NOOP != t1->opcode); assert((oc_tab[t1->exorder.fl->opcode].octype & OCT_JUMP) ||(OC_JMPTSET != t1->exorder.fl->opcode) || (OC_JMPTCLR != t1->exorder.fl->opcode)); ref0 = maketriple(t1->opcode); /* copy operation for place in new ladder */ ref1 = (TREF(boolchain_ptr))->exorder.bl; /* common setup for above op insert */ switch (t1->opcode) { /* time to subvert original jump ladder entry */ case OC_COBOOL: /* insert COBOOL and copy of following JMP in boolchain; overlay them with STOTEMP and NOOP */ assert(TRIP_REF == t1->operand[0].oprclass); dqins(ref1, exorder, ref0); if (oc_tab[t1->operand[0].oprval.tref->opcode].octype & OCT_MVAL) { /* do we need a STOTEMP? */ STOTEMP_IF_NEEDED(ref0, 0, t1, t1->operand[0]); } else { /* make it an mval instead of COBOOL now */ t1->opcode = OC_COMVAL; ref0->operand[0] = put_tref(t1); /* new COBOOL points to this OC_COMVAL */ } t1 = t1->exorder.fl; ref0 = maketriple(t1->opcode); /* create new jmp on result of coerce */ ref0->operand[0] = t1->operand[0]; t1->opcode = OC_NOOP; /* wipe out original jmp */ t1->operand[0].oprclass = NO_REF; break; case OC_CONTAIN: case OC_EQU: case OC_FOLLOW: case OC_NUMCMP: case OC_PATTERN: case OC_SORTS_AFTER: /* insert copies of orig OC and following JMP in boolchain & overly originals with STOTEMPs */ assert(TRIP_REF == t1->operand[0].oprclass); assert(TRIP_REF == t1->operand[1].oprclass); dqins(ref1, exorder, ref0); STOTEMP_IF_NEEDED(ref0, 0, t1, t1->operand[0]); ref1 = t1; t1 = t1->exorder.fl; ref2 = maketriple(t1->opcode); /* copy jmp */ ref2->operand[0] = t1->operand[0]; STOTEMP_IF_NEEDED(ref0, 1, t1, ref1->operand[1]); if (OC_NOOP == ref1->opcode) /* does op[0] need cleanup? */ ref1->operand[0].oprclass = ref1->operand[1].oprclass = NO_REF; ref0 = ref2; break; case OC_JMPTSET: case OC_JMPTCLR: /* move copy of jmp to boolchain and NOOP it */ ref0->operand[0] = t1->operand[0]; /* new jmpt gets old target */ ref2 = maketriple(OC_NOOP); /* insert a NOOP in new chain inplace of COBOOL */ dqins(ref1, exorder, ref2); t1->opcode = OC_NOOP; /* wipe out original jmp */ t1->operand[0].oprclass = NO_REF; break; default: assertpro(FALSE); } assert((OC_STOTEMP == t1->opcode) || (OC_NOOP == t1->opcode) || (OC_COMVAL == t1->opcode) || (OC_LITC == t1->opcode)); assert(oc_tab[ref0->opcode].octype & OCT_JUMP); ref1 = (TREF(boolchain_ptr))->exorder.bl; dqins(ref1, exorder, ref0); /* common insert for new jmp */ } assert(oc_tab[t->opcode].octype & OCT_BOOL); t->opcode = OC_NOOP; /* wipe out the original boolean op */ t->operand[0].oprclass = t->operand[1].oprclass = NO_REF; tripbp = &t->jmplist; /* borrow jmplist to track jmp targets */ assert(NULL == tripbp->bpt); assert((tripbp == tripbp->que.fl) && (tripbp == tripbp->que.bl)); tripbp->bpt = jmp_to_next ? (TREF(boolchain_ptr))->exorder.bl : ref0; /* point op triple at op[1] position or op[0] */ dqins(TREF(bool_targ_ptr), que, tripbp); /* queue jmplist for clean-up */ if (!expr_fini) return; /* time to deal with new jump ladder */ assert(NULL != TREF(boolchain_ptr)); assert(NULL != TREF(bool_targ_ptr)); assert(TREF(bool_targ_ptr) != (TREF(bool_targ_ptr))->que.fl); assert(t0->exorder.bl == t); assert(t0 == t->exorder.fl); dqadd(t, TREF(boolchain_ptr), exorder); /* insert the new jump ladder */ ref0 = (TREF(boolchain_ptr))->exorder.bl->exorder.fl; t0 = t->exorder.fl; if (ref0 == TREF(curtchain)) { /* add a safe target */ newtriple(OC_NOOP); ref0 = (TREF(curtchain))->exorder.bl; } assert((OC_COBOOL == t0->opcode) ||(OC_JMPTSET != t0->opcode) || (OC_JMPTCLR != t0->opcode)) ; t0 = t0->exorder.fl; assert(oc_tab[t0->opcode].octype & OCT_JUMP); for (; (t0 != ref0) && oc_tab[t0->opcode].octype & OCT_JUMP; t0 = t0->exorder.fl) { /* process replacement jmps */ adj_addr = &t0->operand[0]; assert(INDR_REF == adj_addr->oprclass); if (NULL != (t1 = (adj_addr = adj_addr->oprval.indr)->oprval.tref)) { /* need to adjust target; NOTE assignments above */ if (OC_BOOLFINI != t1->opcode) { /* not past the end of the new chain */ assert(TJMP_REF == adj_addr->oprclass); if ((t == t1) || (t1 == ref0)) ref1 = ref0; /* adjust to end of boolean expression */ else { /* old target should have jmplist entry */ /* from the jmp jmplisted in the old target we move past the next * test (or NOOP) and jmp which correspond to the old target and pick * the subsequent test (or NOOP) and jmp which correspond to those that originally followed * the logic after the old target and are therefore the appropriate new target for this jmp */ assert(OC_NOOP == t1->opcode); assert(&(t1->jmplist) != t1->jmplist.que.fl); assert(NULL != t1->jmplist.bpt); assert(oc_tab[t1->jmplist.bpt->opcode].octype & OCT_JUMP); ref1 = t1->jmplist.bpt->exorder.fl; assert((oc_tab[ref1->opcode].octype & OCT_BOOL) || (OC_NOOP == ref1->opcode)); assert(oc_tab[ref1->exorder.fl->opcode].octype & OCT_JUMP); ref1 = ref1->exorder.fl->exorder.fl; assert((oc_tab[ref1->opcode].octype & OCT_BOOL) || (OC_BOOLFINI == ref1->opcode) || ((OC_NOOP == ref1->opcode) && ((OC_JMPTCLR == ref1->exorder.fl->opcode) || (OC_JMPTSET == ref1->exorder.fl->opcode) || (TREF(curtchain) == ref1->exorder.fl)))); } t0->operand[0] = put_tjmp(ref1); /* no indrection simplifies later interations */ } } t0 = t0->exorder.fl; if ((OC_BOOLFINI == t0->opcode) || (TREF(curtchain) == t0->exorder.fl)) break; assert((oc_tab[t0->opcode].octype & OCT_BOOL) || (OC_JMPTSET == t0->exorder.fl->opcode) || (OC_JMPTCLR == t0->exorder.fl->opcode)); } dqloop(TREF(bool_targ_ptr), que, tripbp) /* clean up borrowed jmplist entries */ { dqdel(tripbp, que); tripbp->bpt = NULL; } assert((TREF(bool_targ_ptr) == (TREF(bool_targ_ptr))->que.fl) && (TREF(bool_targ_ptr) == (TREF(bool_targ_ptr))->que.bl)); TREF(boolchain_ptr) = NULL; if (TREF(expr_start) != TREF(expr_start_orig)) { /* inocculate against an unwanted GVRECTARG */ ref0 = maketriple(OC_NOOP); dqins(TREF(expr_start), exorder, ref0); TREF(expr_start) = ref0; } return; } fis-gtm-V6.0-003/sr_port/bx_relop.c0000644000032200000250000000127412201176154016013 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "mdq.h" void bx_relop(triple *t, opctype cmp, opctype tst, oprtype *addr) { triple *ref; ref = maketriple(tst); ref->operand[0] = put_indr(addr); dqins(t, exorder, ref); t->opcode = cmp; return; } fis-gtm-V6.0-003/sr_port/bx_tail.c0000644000032200000250000000627012201176154015624 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "mdq.h" #include "mmemory.h" LITREF octabstruct oc_tab[]; /* structure of jmps is as follows: * * sense OC_AND OC_OR * * TRUE op1 op1 * jmpf next jmpt addr * op2 op2 * jmpt addr jmpt addr * * FALSE op1 op1 * jmpf addr jmpt next * op2 op2 * jmpf addr jmpf addr **/ void bx_tail(triple *t, boolean_t sense, oprtype *addr) /* * triple *t; triple to be processed *boolean_t sense; code to be generated is jmpt or jmpf *oprtype *addr; address to jmp */ { triple *ref; oprtype *p; assert((1 & sense) == sense); assert(oc_tab[t->opcode].octype & OCT_BOOL); assert(TRIP_REF == t->operand[0].oprclass); assert((TRIP_REF == t->operand[1].oprclass) || (NO_REF == t->operand[1].oprclass)); switch (t->opcode) { case OC_COBOOL: ex_tail(&t->operand[0]); if (OC_GETTRUTH == t->operand[0].oprval.tref->opcode) { dqdel(t->operand[0].oprval.tref, exorder); t->opcode = sense ? OC_JMPTSET : OC_JMPTCLR; t->operand[0] = put_indr(addr); return; } ref = maketriple(sense ? OC_JMPNEQ : OC_JMPEQU); ref->operand[0] = put_indr(addr); dqins(t, exorder, ref); return; case OC_COM: bx_tail(t->operand[0].oprval.tref, !sense, addr); t->opcode = OC_NOOP; t->operand[0].oprclass = NO_REF; return; case OC_NEQU: sense = !sense; /* caution: fall through */ case OC_EQU: bx_relop(t, OC_EQU, sense ? OC_JMPNEQ : OC_JMPEQU, addr); break; case OC_NPATTERN: sense = !sense; /* caution: fall through */ case OC_PATTERN: bx_relop(t, OC_PATTERN, sense ? OC_JMPNEQ : OC_JMPEQU, addr); break; case OC_NFOLLOW: sense = !sense; /* caution: fall through */ case OC_FOLLOW: bx_relop(t, OC_FOLLOW, sense ? OC_JMPGTR : OC_JMPLEQ, addr); break; case OC_NSORTS_AFTER: sense = !sense; /* caution: fall through */ case OC_SORTS_AFTER: bx_relop(t, OC_SORTS_AFTER, sense ? OC_JMPGTR : OC_JMPLEQ, addr); break; case OC_NCONTAIN: sense = !sense; /* caution: fall through */ case OC_CONTAIN: bx_relop(t, OC_CONTAIN, sense ? OC_JMPNEQ : OC_JMPEQU, addr); break; case OC_NGT: sense = !sense; /* caution: fall through */ case OC_GT: bx_relop(t, OC_NUMCMP, sense ? OC_JMPGTR : OC_JMPLEQ, addr); break; case OC_NLT: sense = !sense; /* caution: fall through */ case OC_LT: bx_relop(t, OC_NUMCMP, sense ? OC_JMPLSS : OC_JMPGEQ, addr); break; case OC_NAND: sense = !sense; /* caution: fall through */ case OC_AND: bx_boolop(t, FALSE, sense, sense, addr); return; case OC_NOR: sense = !sense; /* caution: fall through */ case OC_OR: bx_boolop(t, TRUE, !sense, sense, addr); return; default: GTMASSERT; } for (p = t->operand ; p < ARRAYTOP(t->operand); p++) if (TRIP_REF == p->oprclass) ex_tail(p); return; } fis-gtm-V6.0-003/sr_port/cache.h0000644000032200000250000000407712201176154015255 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CACHE_H #define CACHE_H /* Macros to add debugging to objcode cache for indirects. To enable, uncomment line below */ /*#define DEBUG_CACHE */ #ifdef DEBUG_CACHE # define DBGCACHE(x) DBGFPF(x) #else # define DBGCACHE(x) #endif typedef struct { mstr str; uint4 code; } icode_str; /* For indirect code source. */ typedef struct cache_ent { mstr obj; icode_str src; int refcnt; /* Number of indirect source code pointing to same cache entry */ int zb_refcnt; /* Number of zbreak action entry pointing to same cache entry */ } cache_entry; /* Following is the indirect routine header build as part of an indirect code object */ typedef struct ihead_struct { cache_entry *indce; int4 vartab_off; int4 vartab_len; int4 temp_mvals; int4 temp_size; int4 fixup_vals_off; /* literal mval table offset */ int4 fixup_vals_num; /* literal mval table's mval count */ } ihdtyp; #define ICACHE_TABLE_INIT_SIZE 64 /* Use 1K memory initially */ #define ICACHE_SIZE ROUND_UP2(SIZEOF(cache_entry), NATIVE_WSIZE) /* We allow cache_table to grow till we hit memory or entry maximums. If more memory is needed, we do compaction. * Current default limits (overrideable by environment variable): 128 entries, 128KB of object code on all platforms * except IA64 architecture which gets 256KB due to its less compact instruction forms. */ #define MAX_CACHE_MEMSIZE (IA64_ONLY(256) NON_IA64_ONLY(128)) #define MAX_CACHE_ENTRIES 128 void indir_lits(ihdtyp *ihead); void cache_init(void); mstr *cache_get(icode_str *indir_src); void cache_put(icode_str *src, mstr *object); void cache_table_rebuild(void); void cache_stats(void); #endif fis-gtm-V6.0-003/sr_port/cache_cleanup.c0000644000032200000250000000273212201176176016757 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "objlabel.h" #include "cache.h" #include "hashtab_objcode.h" #include #include "stack_frame.h" #include "cache_cleanup.h" GBLREF hash_table_objcode cache_table; GBLREF int indir_cache_mem_size; void cache_cleanup(stack_frame *sf) { ihdtyp *irtnhdr; cache_entry *csp; INTPTR_T *vp; boolean_t deleted; assert(sf->ctxt); vp = (INTPTR_T *)sf->ctxt; vp--; if ((GTM_OMAGIC << 16) + OBJ_LABEL == *vp) /* Validate backward linkage */ { /* Frame is one of ours */ vp--; irtnhdr = (ihdtyp *)((char *)vp + *vp); csp = irtnhdr->indce; assert(NULL != csp); assert(0 < csp->refcnt); csp->refcnt--; /* This usage of this cache entry is done */ /* We want to keep the entry around with the hope that it will be accessed again. * When we keep too many entries or entries are using too much memory cache_put will call cache_table_rebuild() * to make space removing elements with csp->refcnt == 0 and csp->zb_refcnt == 0 */ } else GTMASSERT; /* Not sure when this could happen */ } fis-gtm-V6.0-003/sr_port/cache_cleanup.h0000644000032200000250000000212312201176154016752 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2004 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CACHE_CLEANUP_DEFINED #define CACHE_CLEANUP_DEFINED #define IF_INDR_FRAME_CLEANUP_CACHE_ENTRY(frame_pointer) \ { \ /* See if unwinding an indirect frame*/ \ if (frame_pointer->flags & SFF_INDCE) \ cache_cleanup(frame_pointer); \ } #define IF_INDR_FRAME_CLEANUP_CACHE_ENTRY_AND_UNMARK(frame_pointer) \ { \ /* See if unwinding an indirect frame*/ \ if (frame_pointer->flags & SFF_INDCE) \ { \ cache_cleanup(frame_pointer); \ frame_pointer->flags &= SFF_INDCE_OFF; \ } \ } void cache_cleanup(stack_frame *sf); #endif fis-gtm-V6.0-003/sr_port/cache_get.c0000644000032200000250000000207012201176154016076 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2004 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "cache.h" #include "hashtab_objcode.h" GBLREF int cache_hits, cache_fails; GBLREF hash_table_objcode cache_table; /* cache_get - get cached indirect object code corresponding to input source and code from cache_table. * * If object code exists in cache, return pointer to object code mstr * otherwise, return NULL. */ mstr *cache_get(icode_str *indir_src) { cache_entry *csp; ht_ent_objcode *tabent; if (NULL != (tabent = lookup_hashtab_objcode(&cache_table, indir_src))) { cache_hits++; return &(((cache_entry *)tabent->value)->obj); } else { cache_fails++; return NULL; } } fis-gtm-V6.0-003/sr_port/cache_init.c0000644000032200000250000000140012201176154016256 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "cache.h" #include "hashtab_objcode.h" #include "hashtab.h" GBLREF hash_table_objcode cache_table; GBLREF int indir_cache_mem_size; void cache_init(void) { init_hashtab_objcode(&cache_table, ICACHE_TABLE_INIT_SIZE, HASHTAB_COMPACT, HASHTAB_SPARE_TABLE); indir_cache_mem_size = 0; } fis-gtm-V6.0-003/sr_port/cache_put.c0000644000032200000250000000755212201176176016145 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "cache.h" #include "hashtab_objcode.h" #include "cachectl.h" #include "cacheflush.h" #include #include "gtm_text_alloc.h" #include "io.h" GBLREF hash_table_objcode cache_table; GBLREF int indir_cache_mem_size; GBLREF uint4 max_cache_memsize; /* Maximum bytes used for indirect cache object code */ GBLREF uint4 max_cache_entries; /* Maximum number of cached indirect compilations */ void cache_put(icode_str *src, mstr *object) { cache_entry *csp; int i, fixup_cnt; mval *fix_base, *fix; var_tabent *var_base, *varent; ht_ent_objcode *tabent; boolean_t added; indir_cache_mem_size += (ICACHE_SIZE + object->len); if (indir_cache_mem_size > max_cache_memsize || cache_table.count > max_cache_entries) cache_table_rebuild(); csp = (cache_entry *)GTM_TEXT_ALLOC(ICACHE_SIZE + object->len); csp->obj.addr = (char *)csp + ICACHE_SIZE; csp->refcnt = csp->zb_refcnt = 0; csp->src = *src; csp->obj.len = object->len; memcpy(csp->obj.addr, object->addr, object->len); ((ihdtyp *)(csp->obj.addr))->indce = csp; /* Set backward link to this cache entry */ added = add_hashtab_objcode(&cache_table, &csp->src, csp, &tabent); assert(added); DBGCACHE((stdout, "cache_put: Added to cache lookaside %d bytes - (%d/%d/%d %d/%d) code: %d src: %.*s\n", ICACHE_SIZE + object->len, cache_table.count, cache_table.size, max_cache_entries, indir_cache_mem_size, max_cache_memsize, src->code, src->str.len, src->str.addr)); DBGCACHE((stdout, "cache_put: *** updated entry: 0x"lvaddr" value: 0x"lvaddr"\n\n", tabent, tabent->value)); /* Do address fixup on the literals that preceed the code */ fixup_cnt = ((ihdtyp *)(csp->obj.addr))->fixup_vals_num; if (fixup_cnt) { /* Do address fixups for literals in indirect code. This is done by making them point * to the literals that are still resident in the stringpool. The rest of the old object * code will be garbage collected but these literals will be salvaged. The reason to point * to the stringpool version instead of in the copy we just created is that if an assignment * to a local variable from an indirect string literal were to occur, only the mval is copied. * So then there would be a local variable mval pointing into our malloc'd storage instead of * the stringpool. If the cache entry were recycled to hold a different object, the local * mval would then be pointing at garbage. By pointing these literals to their stringpool * counterparts, we save having to (re)copy them to the stringpool where they will be handled * safely and correctly. */ fix_base = (mval *)((unsigned char *)csp->obj.addr + ((ihdtyp *)(csp->obj.addr))->fixup_vals_off); for (fix = fix_base, i = 0 ; i < fixup_cnt ; i++, fix++) { if (MV_IS_STRING(fix)) /* if string, place in string pool */ fix->str.addr = (INTPTR_T)fix->str.addr + object->addr; } } fixup_cnt = ((ihdtyp *)(csp->obj.addr))->vartab_len; if (fixup_cnt) { /* Do address fix up of local variable name which is in stringpool */ var_base = (var_tabent *)((unsigned char *)csp->obj.addr + ((ihdtyp *)(csp->obj.addr))->vartab_off); for (varent = var_base, i = 0; i < fixup_cnt; i++, varent++) varent->var_name.addr = (INTPTR_T) varent->var_name.addr + object->addr; } *object = csp->obj; /* Update location of object code for comp_indr */ cacheflush(csp->obj.addr, csp->obj.len, BCACHE); } fis-gtm-V6.0-003/sr_port/cache_stats.c0000644000032200000250000000246512201176154016465 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* Print cacheing stats for indirect code */ #include "mdef.h" #include "gtm_stdio.h" #include "cache.h" #include "hashtab_objcode.h" GBLREF int cache_hits, cache_fails; GBLREF hash_table_objcode cache_table; void cache_stats(void) { int total_attempts, ace; ht_ent_objcode *tabent, *topent; cache_entry *csp; total_attempts = cache_hits + cache_fails; FPRINTF(stderr,"\nIndirect code cache performance -- Hits: %d, Fails: %d, Hit Ratio: %d%%\n", cache_hits, cache_fails, total_attempts ? ((100 * cache_hits) / (cache_hits + cache_fails)) : 0); ace = 0; /* active cache entries */ for (tabent = cache_table.base, topent = cache_table.top; tabent < topent; tabent++) { if (HTENT_VALID_OBJCODE(tabent, cache_entry, csp)) { if (csp->refcnt || csp->zb_refcnt) ++ace; } } FPRINTF(stderr,"Indirect cache entries currently marked active: %d\n", ace); } fis-gtm-V6.0-003/sr_port/cache_table_rebuild.c0000644000032200000250000000320512201176154020115 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_stdio.h" #include "io.h" #include "min_max.h" #include "cache.h" #include "hashtab_objcode.h" #include "cachectl.h" #include "gtm_text_alloc.h" #include "error.h" GBLREF hash_table_objcode cache_table; GBLREF int indir_cache_mem_size; error_def(ERR_MEMORY); error_def(ERR_VMSMEMORY); void cache_table_rebuild() { ht_ent_objcode *tabent, *topent; cache_entry *csp; DBGCACHE((stdout, "cache_table_rebuild: Rebuilding indirect lookaside cache\n")); for (tabent = cache_table.base, topent = cache_table.top; tabent < topent; tabent++) { if (HTENT_VALID_OBJCODE(tabent, cache_entry, csp)) { if ((0 == csp->refcnt) && (0 == csp->zb_refcnt)) { ((ihdtyp *)(csp->obj.addr))->indce = NULL; indir_cache_mem_size -= (ICACHE_SIZE + csp->obj.len); GTM_TEXT_FREE(csp); delete_hashtab_ent_objcode(&cache_table, tabent); } } } /* Only do compaction processing if we are not processing a memory type error (which * involves allocating a smaller table with storage we don't have. */ if (COMPACT_NEEDED(&cache_table) && error_condition != UNIX_ONLY(ERR_MEMORY) VMS_ONLY(ERR_VMSMEMORY)) compact_hashtab_objcode(&cache_table); } fis-gtm-V6.0-003/sr_port/cachectl.h0000644000032200000250000000124312201176154015750 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* cachectl.h - values used as parameters to cacheflush * * ICACHE - flush instruction cache * DCACHE - flush data cache * BCACHE - flush both caches */ #define ICACHE 0x1 #define DCACHE 0x2 #define BCACHE (ICACHE|DCACHE) fis-gtm-V6.0-003/sr_port/cacheflush.c0000644000032200000250000000236212201176154016305 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* cacheflush stub * * Most hardware platforms on which GT.M is implemented use separate * instruction and data caches. It is necessary to flush these caches * whenever we generate code in a data region in order to make sure * the generated code gets written from the data cache to memory and * subsequently loaded from memory into the instruction cache. * * Input: addr starting address of region to flush * nbytes size, in bytes, of region to flush * cache_select flag indicating whether to flus * I-cache, D-cache, or both * * This stub is for those platforms that don't use separate data and * instruction caches. */ #include "mdef.h" #include "cacheflush.h" int cacheflush (void *addr, long nbytes, int cache_select) { return 0; /* incr_link requires a zero return value for success */ } fis-gtm-V6.0-003/sr_port/cacheflush.h0000644000032200000250000000106512201176154016311 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __CACHEFLUSH_H__ #define __CACHEFLUSH_H__ int cacheflush (void *addr, long nbytes, int cache_select); #endif fis-gtm-V6.0-003/sr_port/caller_id.c0000644000032200000250000000177612201176154016126 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* Stub for caller_id routine called from CRIT_TRACE macro to return the return address of our caller allowing CRIT_TRACE (used in various semaphore routines) to determine who was calling those semaphore routines and for what purpose and when. This is a system dependent type of operation and is generally implemented in assembly language. This stub is so we continue to function on those platforms we have not yet implemented this function. */ #include "mdef.h" #include "caller_id.h" caddr_t caller_id(void) { return (caddr_t)((INTPTR_T)-1); } fis-gtm-V6.0-003/sr_port/caller_id.h0000644000032200000250000000104612201176154016121 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef _CALLER_ID_H__ #define _CALLER_ID_H__ #include caddr_t caller_id(void); #endif fis-gtm-V6.0-003/sr_port/callg.h0000644000032200000250000000131412201176154015263 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CALLG_H #define CALLG_H typedef struct gparam_list_struct { intszofptr_t n; void *arg[MAX_ACTUALS]; } gparam_list; typedef INTPTR_T (*callgfnptr)(intszofptr_t cnt, ...); INTPTR_T callg(callgfnptr, gparam_list *); void callg_signal(void *); #endif fis-gtm-V6.0-003/sr_port/callg_signal.c0000644000032200000250000000115712201176154016620 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "lv_val.h" /* needed by "callg.h" */ #include "callg.h" void callg_signal(void *arg) { (void)callg((callgfnptr) rts_error, (void *)arg); } fis-gtm-V6.0-003/sr_port/ccp.h0000644000032200000250000002065612201176154014760 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2005 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CCP_H #define CCP_H /* requires gdsroot */ enum { CCP_VALBLK_TRANS_HIST, CCP_VALBLK_JNL_ADDR, CCP_VALBLK_EPOCH_TN, CCP_VALBLK_LST_ADDR }; typedef struct ccp_wait_struct { struct ccp_wait_struct *next; uint4 pid; } ccp_wait; typedef struct { ccp_wait *first,**last; } ccp_wait_head; typedef struct { short cond; unsigned short length; int4 lockid; } ccp_iosb; typedef struct mem_list_struct { char *addr; uint4 pages; struct mem_list_struct *next; struct mem_list_struct *prev; bool free; } mem_list; typedef struct ccp_db_header_struct { struct sgmnt_data_struct *glob_sec; /* address of file header */ struct gd_region_struct *greg; /* address like gv_cur_region */ struct sgmnt_addrs_struct *segment; /* like cs_addrs */ struct ccp_db_header_struct *next; /* pointer to next db_header in list */ mem_list *mem_ptr; /* memory control structure */ vms_lock_sb wm_iosb; /* iosb for write mode $enq*/ vms_lock_sb flush_iosb; /* iosb for 'buffers flushed' $enq*/ vms_lock_sb lock_iosb; /* iosb for MUMPS LOCK $enq*/ vms_lock_sb refcnt_iosb; /* iosb for reference count of gtm process in database $enq*/ ccp_iosb qio_iosb; /* iosb for $QIO used during file opens and misc operations*/ ccp_wait_head write_wait; /* list of pid's to wake upon entering write mode */ ccp_wait_head flu_wait; /* list of pid's to wake upon prior machine finishing flush */ ccp_wait_head exitwm_wait; /* list of pid's to wake after finishing exitwm */ ccp_wait_head reopen_wait; /* list of pid's to wake upon finishing close */ trans_num last_write_tn; /* t.n. for last write on this node */ trans_num master_map_start_tn; /* t.n. for last master map update*/ trans_num tick_tn; /* t.n. as of last clock tick*/ uint4 last_lk_sequence; /* sequence for last lock update */ short unsigned wc_rover; /* used when flushing dirty buffers so that we don't have to start at the beginning each time */ struct ccp_db_header_struct *tick_timer_id; /* unique values to use as timer id and pointer to db */ struct ccp_db_header_struct *quantum_timer_id; struct ccp_db_header_struct *stale_timer_id; struct ccp_db_header_struct *wmcrit_timer_id; struct ccp_db_header_struct *close_timer_id; struct ccp_db_header_struct *exitwm_timer_id; struct ccp_db_header_struct *extra_tick_id; date_time start_wm_time; /* Time entered write mode */ unsigned char drop_lvl; unsigned int quantum_expired : 1; /* quantum is up*/ unsigned int tick_in_progress : 1; /* the tick timer is running*/ unsigned int wmexit_requested: 1; /* we have received a request to relinquish write mode*/ unsigned int write_mode_requested: 1; /* processing to get write mode has commenced*/ unsigned int dirty_buffers_acquired : 1; /* set to zero when write mode is entered, and to one when ENQ on dirty buffers is acquired*/ unsigned int filler : 1; unsigned int stale_in_progress : 1; /* stale timer active */ unsigned int blocking_ast_received : 1; /* an exitwm blocking ast has been received */ unsigned int remote_wakeup : 1; /* wakeup needed for processes blocked on mumps locks */ unsigned int extra_tick_started : 1; /* started timer for extra tick prior to write mode release */ unsigned int extra_tick_done : 1; /* extra tick done */ unsigned int close_region : 1; /* closing region */ } ccp_db_header; typedef union { gds_file_id file_id; struct gd_region_struct *reg; ccp_db_header *h; struct FAB *fab; struct { unsigned char len; unsigned char txt[23]; } str; struct { gds_file_id fid; unsigned short cycle; } exreq; /* exit write mode request */ struct { unsigned short channel; unsigned char *context; } mbx; } ccp_action_aux_value; /* types used to discriminate ccp_action_aux_value union members */ #define CCTVNUL 0 /* no value */ #define CCTVSTR 1 /* string */ #define CCTVMBX 2 /* mailbox id */ #define CCTVFIL 3 /* file id */ #define CCTVDBP 4 /* data_base header pointer */ #define CCTVFAB 5 /* pointer to a FAB */ #define CCP_TABLE_ENTRY(A,B,C,D) A, typedef enum { #include "ccpact_tab.h" CCPACTION_COUNT } ccp_action_code; #undef CCP_TABLE_ENTRY typedef struct { ccp_action_code action; uint4 pid; ccp_action_aux_value v; } ccp_action_record; typedef struct { int4 fl; int4 bl; } ccp_relque; typedef struct { ccp_relque q; date_time request_time, process_time; ccp_action_record value; }ccp_que_entry; #define CCP_MBX_NAME "GTM$CCP$MBX" #define CCP_PRC_NAME "GT.CX_CONTROL" #define CCP_LOG_NAME "GTM$CCPLOG:CCPERR.LOG" enum ccp_state_code { CCST_CLOSED, /* Data base is closed */ CCST_OPNREQ, /* A request to open the data base is being processed */ CCST_RDMODE, /* The data base is in READ mode, all buffers have been written to disk */ CCST_WRTREQ, /* A Write Mode request on our machine is being processed */ CCST_WRTGNT, /* Write mode has been granted, but the last machine's dirty buffers are not available */ CCST_DRTGNT, /* Write mode has been granted and the dirty buffers are available */ CCST_WMXREQ, /* Another machine has requested write mode */ CCST_WMXGNT /* We have relinquished write mode, and are writing dirty buffers */ }; #define CCST_MASK_CLOSED (1 << CCST_CLOSED) #define CCST_MASK_OPNREQ (1 << CCST_OPNREQ) #define CCST_MASK_RDMODE (1 << CCST_RDMODE) #define CCST_MASK_WRTREQ (1 << CCST_WRTREQ) #define CCST_MASK_WRTGNT (1 << CCST_WRTGNT) #define CCST_MASK_DRTGNT (1 << CCST_DRTGNT) #define CCST_MASK_WMXREQ (1 << CCST_WMXREQ) #define CCST_MASK_WMXGNT (1 << CCST_WMXGNT) #define CCST_MASK_OPEN (~(CCST_MASK_CLOSED | CCST_MASK_OPNREQ)) #define CCST_MASK_WRITE_MODE (CCST_MASK_WRTGNT | CCST_MASK_DRTGNT) #define CCST_MASK_HAVE_DIRTY_BUFFERS (CCST_MASK_DRTGNT | CCST_MASK_WMXREQ | CCST_MASK_WMXGNT | CCST_MASK_RDMODE) #define CCP_SEGMENT_STATE(X,Y) (((1 << ((X)->ccp_state)) & (Y)) != 0) #define CCP_CLOSE_REGION 0 #define CCP_OPEN_REGION 1 #ifdef VMS #define CCP_FID_MSG(X,Y) (ccp_sendmsg(Y, &FILE_INFO(X)->file_id)) #else #define CCP_FID_MSG(X,Y) #endif bool ccp_act_request(ccp_action_record *rec); bool ccp_priority_request(ccp_action_record *rec); short ccp_sendmsg(ccp_action_code action, ccp_action_aux_value *aux_value); ccp_action_record *ccp_act_select(void); ccp_db_header *ccp_get_reg_by_fab(struct FAB *fb); ccp_db_header *ccp_get_reg(gds_file_id *name); void ccp_exit(void); void ccp_init(void); void ccp_quemin_adjust(char oper); void ccp_staleness(ccp_db_header **p); short ccp_sendmsg(ccp_action_code action, ccp_action_aux_value *aux_value); unsigned char *ccp_format_querec(ccp_que_entry *inrec, unsigned char *outbuf, unsigned short outbuflen); void cce_ccp_ch(); void cce_get_return_channel(ccp_action_aux_value *p); void cce_dbdump(void); void ccp_act_complete(void); void ccp_act_init(void); void ccp_add_reg(ccp_db_header *d); void ccp_close1(ccp_db_header *db); void ccp_dump(void); void ccp_ewmwtbf_interrupt(ccp_db_header **p); void ccp_exitwm1a(ccp_db_header *db); void ccp_exitwm1(ccp_db_header *db); void ccp_exitwm2a(ccp_db_header *db); void ccp_exitwm2(ccp_db_header *db); void ccp_exitwm3(ccp_db_header *db); void ccp_exitwm_attempt(ccp_db_header *db); void ccp_exitwm_blkast(ccp_db_header **pdb); void ccp_extra_tick(ccp_db_header **p); void ccp_gotdrt_tick(ccp_db_header *db); void ccp_lkdowake_blkast(ccp_db_header *db); void ccp_lkrqwake1(ccp_db_header *db); void ccp_mbx_start(void); void ccp_opendb1a(struct FAB *fb); void ccp_opendb1(ccp_db_header *db); void ccp_opendb1e(struct FAB *fb); void ccp_opendb2(ccp_db_header *db); void ccp_opendb3b(ccp_db_header *db); void ccp_opendb3c(ccp_db_header *db); void ccp_opendb3(ccp_db_header *db); void ccp_opendb(ccp_action_record *rec); void ccp_pndg_proc_add(ccp_wait_head *list, int4 pid); void ccp_pndg_proc_wake(ccp_wait_head *list); void ccp_request_write_mode(ccp_db_header *db); void ccp_reqwm_interrupt(ccp_db_header **pdb); void ccp_rundown(void); void ccp_signal_cont(uint4 arg1, ...); void ccp_tick_interrupt(ccp_db_header **p); void ccp_tick_start(ccp_db_header *db); void ccp_tr_checkdb(void); void ccp_writedb4a(ccp_db_header *db); void ccp_writedb4(ccp_db_header *db); void ccp_writedb5(ccp_db_header *db); #endif fis-gtm-V6.0-003/sr_port/ccp_cluster_lock_wake.h0000644000032200000250000000107312201176154020530 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __CCP_CLUSTER_LOCK_WAKE_H__ #define __CCP_CLUSTER_LOCK_WAKE_H__ void ccp_cluster_lock_wake(gd_region *reg); #endif fis-gtm-V6.0-003/sr_port/ccpact.h0000644000032200000250000000176312201176154015446 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* * CCPACT.H is now obsolete; the code has been moved into CCP.H. * The file can be NIXed once all inclusions of it have been removed. */ #if 0 #define CCP_TABLE_ENTRY(A,B,C,D) A, enum action_code_enum { #include "ccpact_tab.h" CCPACTION_COUNT }; #undef CCP_TABLE_ENTRY /* ccpact_tab auxvalue types to discriminate unions */ #define CCTVNUL 0 /* no value */ #define CCTVSTR 1 /* string */ #define CCTVMBX 2 /* mailbox id */ #define CCTVFIL 3 /* file id */ #define CCTVDBP 4 /* data_base header pointer */ #define CCTVFAB 5 /* pointer to a FAB */ #endif fis-gtm-V6.0-003/sr_port/ccpact_tab.h0000644000032200000250000000524412201176154016272 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* CCP_TABLE_ENTRY (transaction routine auxvalue transaction enum, name, type, priority ) */ CCP_TABLE_ENTRY (CCTR_CHECKDB, ccp_tr_checkdb, CCTVNUL, CCPR_NOR) /* check files to see if still being accessed */ CCP_TABLE_ENTRY (CCTR_CLOSE, ccp_tr_close, CCTVFIL, CCPR_NOR) /* notify that process no longer has interest in region */ CCP_TABLE_ENTRY (CCTR_CLOSEJNL, ccp_tr_closejnl, CCTVDBP, CCPR_HI) /* journal file close due to oper ast */ CCP_TABLE_ENTRY (CCTR_DEBUG, ccp_tr_debug, CCTVSTR, CCPR_HI) /* request that ccp go into debug mode */ CCP_TABLE_ENTRY (CCTR_EWMWTBF, ccp_tr_ewmwtbf, CCTVDBP, CCPR_HI) /* exit write mode, wait for buffers to be written out */ CCP_TABLE_ENTRY (CCTR_EXITWM, ccp_tr_exitwm, CCTVFIL, CCPR_NOR) /* relinquish write mode */ CCP_TABLE_ENTRY (CCTR_EXWMREQ, ccp_tr_exwmreq, CCTVDBP, CCPR_NOR) /* request to relinquish write mode */ CCP_TABLE_ENTRY (CCTR_FLUSHLK, ccp_tr_flushlk, CCTVFIL, CCPR_NOR) /* wait for prior machine's flush to finish */ CCP_TABLE_ENTRY (CCTR_GOTDRT, ccp_tr_gotdrt, CCTVDBP, CCPR_HI) /* got enq for dirty buffers acquired */ CCP_TABLE_ENTRY (CCTR_LKRQWAKE, ccp_tr_lkrqwake, CCTVFIL, CCPR_NOR) /* request wake up lock wait procs whole cluster*/ CCP_TABLE_ENTRY (CCTR_NULL, ccp_tr_null, CCTVNUL, CCPR_NOR) /* noop */ CCP_TABLE_ENTRY (CCTR_OPENDB1, ccp_tr_opendb1, CCTVFAB, CCPR_HI) /* data base open, second phase */ CCP_TABLE_ENTRY (CCTR_OPENDB1A, ccp_tr_opendb1a, CCTVFAB, CCPR_HI) /* step two of first phase of opening */ CCP_TABLE_ENTRY (CCTR_OPENDB1B, ccp_tr_opendb1b, CCTVDBP, CCPR_HI) /* deadlock detected getting locks, retry */ CCP_TABLE_ENTRY (CCTR_OPENDB1E, ccp_tr_opendb1e, CCTVFAB, CCPR_HI) /* error opening database */ CCP_TABLE_ENTRY (CCTR_OPENDB3, ccp_tr_opendb3, CCTVDBP, CCPR_HI) /* data base open, third phase */ CCP_TABLE_ENTRY (CCTR_OPENDB3A, ccp_tr_opendb3a, CCTVDBP, CCPR_HI) /* journal file opening */ CCP_TABLE_ENTRY (CCTR_QUEDUMP, ccp_tr_quedump, CCTVSTR, CCPR_HI) /* request dump of queues */ CCP_TABLE_ENTRY (CCTR_STOP, ccp_tr_stop, CCTVNUL, CCPR_NOR) /* operator stop */ CCP_TABLE_ENTRY (CCTR_WRITEDB, ccp_tr_writedb, CCTVFIL, CCPR_NOR) /* request write mode */ CCP_TABLE_ENTRY (CCTR_WRITEDB1, ccp_tr_writedb1, CCTVDBP, CCPR_HI) /* request write mode - ENQ was granted */ fis-gtm-V6.0-003/sr_port/cdb_sc.h0000644000032200000250000000234612201176154015424 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2003 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CDB_SC #define CDB_SC /********************************* WARNING: *********************************** * Several of these codes are concurrently defined in GVCST_BLK_SEARCH.MAR, * * GVCST_SEARCH.MAR, MUTEX.MAR, and MUTEX_STOPREL.MAR. If their positions * * are changed here, their definitions must be modified there as well! * ********************************************************************************/ enum cdb_sc { #define CDB_SC_NUM_ENTRY(code, value) code = value, #define CDB_SC_UCHAR_ENTRY(code, is_wcs_code, value) code = value, #define CDB_SC_LCHAR_ENTRY(code, is_wcs_code, value) code = value, #include "cdb_sc_table.h" #undef CDB_SC_NUM_ENTRY #undef CDB_SC_UCHAR_ENTRY #undef CDB_SC_LCHAR_ENTRY }; #define FUTURE_READ 0 /* used by dsk_read and t_qread */ #endif fis-gtm-V6.0-003/sr_port/cdb_sc_table.h0000644000032200000250000002346612201176154016601 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* New entries should be added at the end to maintain backward compatibility */ /* Note: This is an exception where we have 132+ characters in a line */ /* * CDB_SC_NUM_ENTRY(code, value) * CDB_SC_UCHAR_ENTRY(code, is_wcs_code, value) * CDB_SC_LCHAR_ENTRY(code, is_wcs_code, value) * * is_wcs_code is TRUE if the cdb_sc code is a cache-related failure code. * * cdb_sc codes with numeric values are internally generated codes which is never displayed to the user and hence * can never imply a database cache related problem. hence the macro CDB_SC_NUM_ENTRY has no is_wcs_code parameter. * * Currently the failure codes considered as cache failure codes are as follows. * cdb_sc_losthist, * cdb_sc_lostcr, * cdb_sc_cacheprob, * cdb_sc_lostbefor * cdb_sc_cyclefail, * cdb_sc_lostbmlhist, * cdb_sc_lostbmlcr, * cdb_sc_crbtmismatch, * cdb_sc_bmlmod and cdb_sc_blkmod need to be added here, but they present an interesting problem. This is because * if the database has an integrity error, we will get a cdb_sc_blkmod/bmlmod error for every transaction that reads * the block with the BLKTNTOOLG integrity error in which case we do not want to set wc_blocked and cause indefinite * cache-recoveries. But to do that we need to do a wcs_verify() after setting wc_blocked and if no problems are * detected, we should unset wc_blocked. that is a little tricky and is deferred until it is considered worthy. */ CDB_SC_NUM_ENTRY( cdb_sc_normal, 0) /* 0 success */ CDB_SC_NUM_ENTRY( cdb_sc_endtree, 1) /* 1 gvcst_lftsib or gvcst_rtsib searched past end of tree */ CDB_SC_NUM_ENTRY( cdb_sc_delete_parent, 2) /* 2 gvcst_kill_blk succeeded, but signals gvcst_kill * that block was completely deleted */ CDB_SC_NUM_ENTRY( cdb_sc_nolock, 3) /* 3 mutex_lockwim was unable to obtain a lock */ CDB_SC_NUM_ENTRY( cdb_sc_needcrit, 4) /* 4 on 4th attempt and need crit for this region -- restart transaction * no penalty */ CDB_SC_NUM_ENTRY( cdb_sc_helpedout, 5) /* 5 wcs_blocked when t_tries >= CDB_STAGNATE */ CDB_SC_NUM_ENTRY( cdb_sc_gbloflow, 6) /* 6 t_end or tp_tend found database full and could not be extended */ CDB_SC_NUM_ENTRY( cdb_sc_oprnotneeded, 7) /* 7 reorg operation was not required */ CDB_SC_NUM_ENTRY( cdb_sc_starrecord, 8) /* 8 star record was found while reading the block */ CDB_SC_NUM_ENTRY( cdb_sc_extend, 9) /* 9 extend requested when none seemed needed - from gdsfilext */ CDB_SC_NUM_ENTRY( cdb_sc_jnlclose, 10) /* 10 journal file has been closed */ CDB_SC_UCHAR_ENTRY(cdb_sc_rmisalign1, FALSE, 'A') /* 'A' gvcst_get found record misaligned */ CDB_SC_UCHAR_ENTRY(cdb_sc_keyoflow, FALSE, 'B') /* 'B' gvcst_expand_key or gvcst_search (3) found key overflow */ CDB_SC_UCHAR_ENTRY(cdb_sc_rmisalign, FALSE, 'C') /* 'C' Record misaligned from nearly everyone */ CDB_SC_UCHAR_ENTRY(cdb_sc_r2small, FALSE, 'D') /* 'D' gvcst_expand_key found record too small */ CDB_SC_UCHAR_ENTRY(cdb_sc_losthist, TRUE, 'E') /* 'E' t_end/tp_tend (mm/bg) - tn could not be verified from history */ CDB_SC_UCHAR_ENTRY(cdb_sc_mapfail, FALSE, 'F') /* 'F' t_end or op_tcommit (from bm_getfree) failed to acquire new block */ CDB_SC_UCHAR_ENTRY(cdb_sc_lostcr, TRUE, 'G') /* 'G' gvcst_...sib, t_end/tp_tend/tp_hist - found cache buffer modified */ CDB_SC_UCHAR_ENTRY(cdb_sc_mkblk, FALSE, 'H') /* 'H' Composing a local block failed, from gvcst_kill(3) gvcst_put(14) */ CDB_SC_UCHAR_ENTRY(cdb_sc_rdfail, FALSE, 'I') /* 'I' t_qread found block number requested is outside size of file * as described by fileheader */ CDB_SC_UCHAR_ENTRY(cdb_sc_badlvl, FALSE, 'J') /* 'J' gvcst_search found a child block didn't have the next block level * below its parent */ CDB_SC_UCHAR_ENTRY(cdb_sc_cacheprob, TRUE, 'K') /* 'K' db_csh_get, ... found a cache control problem */ CDB_SC_UCHAR_ENTRY(cdb_sc_blkmod, FALSE, 'L') /* 'L' t_end, or tp_tend found block modified */ CDB_SC_UCHAR_ENTRY(cdb_sc_uperr, FALSE, 'M') /* 'M' t_ch received an unpredicatable error */ CDB_SC_UCHAR_ENTRY(cdb_sc_comfail, FALSE, 'N') /* 'N' Commit failed used in t_end_sysops (8) by (?) */ CDB_SC_UCHAR_ENTRY(cdb_sc_lostbefor, TRUE, 'O') /* 'O' t_end or tp_tend found the before image needed for journaling was * removed from the cache */ CDB_SC_UCHAR_ENTRY(cdb_sc_committfail, FALSE, 'P') /* 'P' t_commit_cleanup found a partially committed block split */ CDB_SC_UCHAR_ENTRY(cdb_sc_dbccerr, FALSE, 'Q') /* 'Q' mutex found (in 1 of 3 places) an interlock instruction failure * in critical mechanism */ CDB_SC_UCHAR_ENTRY(cdb_sc_critreset, FALSE, 'R') /* 'R' mutex found (in 1 of 6 places) that the segment crit crash count * has been incremented */ CDB_SC_UCHAR_ENTRY(cdb_sc_maxlvl, FALSE, 'S') /* 'S' t_write_root or gvcst_search found maximum legal block level for * database exceeded */ CDB_SC_UCHAR_ENTRY(cdb_sc_blockflush, FALSE, 'T') /* 'T' t_end (hist, or bitmap) found an to update a buffer that is being * flushed (GT.CX) */ CDB_SC_UCHAR_ENTRY(cdb_sc_cyclefail, TRUE, 'U') /* 'U' t_end or tp_tend found a buffer in read(only) set was overwritten * though tn static */ CDB_SC_UCHAR_ENTRY(cdb_sc_optrestart, FALSE, 'V') /* 'V' TP restart explicitly signaled by the TRESTART command */ CDB_SC_UCHAR_ENTRY(cdb_sc_future_read, FALSE, 'W') /* 'W' dsk_read return to t_qread indicated block transaction exceeds * curr_tn (GT.CX) */ CDB_SC_UCHAR_ENTRY(cdb_sc_badbitmap, FALSE, 'X') /* 'X' bm_getfree found bitmap had bad size or level */ CDB_SC_UCHAR_ENTRY(cdb_sc_badoffset, FALSE, 'Y') /* 'Y' gvcst_blk_search (in gvcst_search_blk or gvcst_search_tail) found * a bad record offset */ CDB_SC_UCHAR_ENTRY(cdb_sc_blklenerr, FALSE, 'Z') /* 'Z' gvcst_blk_search (in gvcst_search_blk or gvcst_search_tail) reached * the end with no match */ CDB_SC_LCHAR_ENTRY(cdb_sc_bmlmod, FALSE, 'a') /* 'a' t_end or tp_tend (mm or bg) found bit_map modified */ CDB_SC_LCHAR_ENTRY(cdb_sc_lostbmlhist, TRUE, 'b') /* 'b' t_end or tp_tend (bg) - tn could not be verified from history */ CDB_SC_LCHAR_ENTRY(cdb_sc_lostbmlcr, TRUE, 'c') /* 'c' t_end or tp_tend (bg) - found cache buffer modified */ CDB_SC_LCHAR_ENTRY(cdb_sc_lostoldblk, FALSE, 'd') /* 'd' t_qread or op_tcommit (tp and before image) - old_block of a used * block is NULL */ CDB_SC_LCHAR_ENTRY(cdb_sc_blknumerr, FALSE, 'e') /* 'e' t_qread or op_tcommit - block number is impossible */ CDB_SC_LCHAR_ENTRY(cdb_sc_blksplit, FALSE, 'f') /* 'f' recompute_upd_array recognized that the block needs to be split */ CDB_SC_LCHAR_ENTRY(cdb_sc_toomanyrecompute, FALSE, 'g') /* 'g' more than 25% of the blocks in read-set need to be recomputed */ CDB_SC_LCHAR_ENTRY(cdb_sc_jnlstatemod, FALSE, 'h') /* 'h' csd->jnl_state changed or csd->jnl_before_image changed since start * of the transaction */ CDB_SC_LCHAR_ENTRY(cdb_sc_needlock, FALSE, 'i') /* 'i' on final retry and need to wait for M-lock - restart transaction * - allow for max of 16 such restarts */ CDB_SC_LCHAR_ENTRY(cdb_sc_bkupss_statemod, FALSE, 'j') /* 'j' t_end/tp_tend found that either online-backup-in-progress or * snapshot state changed since start of transaction */ CDB_SC_LCHAR_ENTRY(cdb_sc_crbtmismatch, TRUE, 'k') /* 'k' cr->blk and bt->blk does not match */ CDB_SC_LCHAR_ENTRY(cdb_sc_phase2waitfail, TRUE, 'l') /* 'l' wcs_phase2_commit_wait timed out when called from t_qread */ CDB_SC_LCHAR_ENTRY(cdb_sc_inhibitkills, FALSE, 'm') /* 'm' t_end/tp_tend found inhibit_kills counter greater than zero */ CDB_SC_LCHAR_ENTRY(cdb_sc_triggermod, FALSE, 'n') /* 'n' csd->db_trigger_cycle changed since start of of transaction */ CDB_SC_LCHAR_ENTRY(cdb_sc_onln_rlbk1, FALSE, 'o') /* 'o' csa->onln_rlbk_cycle changed since start of transaction */ CDB_SC_LCHAR_ENTRY(cdb_sc_onln_rlbk2, FALSE, 'p') /* 'p' csa->db_onln_rlbkd_cycle changed since start of transaction */ CDB_SC_LCHAR_ENTRY(cdb_sc_truncate, FALSE, 'q') /* 'q' t_qread tried to read a block beyond the end of a database * that has been concurrently truncated */ CDB_SC_LCHAR_ENTRY(cdb_sc_gvtrootmod, FALSE, 'r') /* 'r' gvcst_kill found a need to redo the gvcst_root_search */ CDB_SC_LCHAR_ENTRY(cdb_sc_instancefreeze, FALSE, 's') /* 's' instance freeze detected in t_end/tp_tend, requires retry */ CDB_SC_LCHAR_ENTRY(cdb_sc_gvtrootmod2, FALSE, 't') /* 't' t_end/tp_tend detected root blocks moved by reorg */ CDB_SC_LCHAR_ENTRY(cdb_sc_spansize, FALSE, 'u') /* 'u' chunks of spanning node don't add up */ CDB_SC_LCHAR_ENTRY(cdb_sc_restarted, FALSE, 'v') /* 'v' return value indicating t_retry has already happened */ CDB_SC_LCHAR_ENTRY(cdb_sc_tqreadnowait, FALSE, 'w') /* 'w' update helper returning from t_qread instead of sleeping */ fis-gtm-V6.0-003/sr_port/cdbg_dump.c0000644000032200000250000002312512201176154016124 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "gtmdbglvl.h" #include "compiler.h" #include "opcode.h" #include "mvalconv.h" #include "cdbg_dump.h" #include "stringpool.h" #include "cache.h" #include "gtmio.h" #include "have_crit.h" LITDEF char *oprtype_names[] = { "Operand[0]", "Operand[1]", "Destination" }; LITDEF char *oprtype_type_names[] = { "NIL", "TVAR_REF", "TVAL_REF", "TINT_REF", "TVAD_REF", "TCAD_REF", "VREG_REF", "MLIT_REF", "MVAR_REF", "TRIP_REF", "TNXT_REF", "TJMP_REF", "INDR_REF", "MLAB_REF", "ILIT_REF", "CDLT_REF", "TEMP_REF", "MFUN_REF", "MNXL_REF", "TSIZ_REF", "OCNT_REF" }; LITDEF char *indents[11] = { "", " ", " ", " ", " ", " ", " ", " ", " ", " ", " " }; GBLREF char *oc_tab_graphic[]; GBLREF spdesc indr_stringpool; GBLREF int4 sa_temps_offset[]; GBLREF int4 sa_temps[]; LITREF int4 sa_class_sizes[]; #define MAX_INDENT (32 * 1024) STATICDEF char *indent_str; STATICDEF int last_indent = 0; void cdbg_dump_triple(triple *dtrip, int indent) { int len; PRINTF("%s Triple %s [0x"lvaddr"] fwdptr: 0x"lvaddr" bkwdptr: 0x"lvaddr" srcline: %d colmn: %d rtaddr: %d\n", cdbg_indent(indent), oc_tab_graphic[dtrip->opcode], (long unsigned int) dtrip, (long unsigned int) dtrip->exorder.fl, (long unsigned int) dtrip->exorder.bl, dtrip->src.line, dtrip->src.column, dtrip->rtaddr); /*switch(dtrip->opcode) { case OC_CDLIT: PRINTF("%s OC_CDLT ptr: 0x"lvaddr" len: 0x"lvaddr"\n", cdbg_indent(indent), opr->oprval.cdlt->addr, opr->oprval.cdlt->len); if (opr->oprval.cdlt->len) cdbg_dump_mstr(cdbg_indent(indent), opr->oprval.cdlt); break; } */ cdbg_dump_operand(indent + 1, &dtrip->operand[0], OP_0); cdbg_dump_operand(indent + 1, &dtrip->operand[1], OP_1); if (dtrip->destination.oprclass) cdbg_dump_operand(indent + 1, &dtrip->destination, OP_DEST); FFLUSH(stdout); } void cdbg_dump_shrunk_triple(triple *dtrip, int old_size, int new_size) { PRINTF("Shrunken triple %s [0x"lvaddr"] fwdptr: 0x"lvaddr" bkwdptr: 0x"lvaddr" srcline: %d colmn: %d rtaddr: %d\n", oc_tab_graphic[dtrip->opcode], (long unsigned int) dtrip, (long unsigned int) dtrip->exorder.fl, (long unsigned int) dtrip->exorder.bl, dtrip->src.line, dtrip->src.column, dtrip->rtaddr); PRINTF(" old size: %d new size: %d shrinkage: %d\n", old_size, new_size, (old_size - new_size)); FFLUSH(stdout); } void cdbg_dump_operand(int indent, oprtype *opr, int opnum) { triple *rtrip; int offset; int len; char *buff; char mid[(SIZEOF(mident_fixed) * 2) + 1]; /* Sized to hold an labels name rtn.lbl */ if (opr) PRINTF("%s %s [0x"lvaddr"] Type: %s\n", cdbg_indent(indent), oprtype_names[opnum], (long unsigned int) opr, oprtype_type_names[opr->oprclass]); else PRINTF("%s ** Warning ** Null opr passed as operand\n", cdbg_indent(indent)); if (!opr->oprclass) { FFLUSH(stdout); return; } /* We have a real oprclass, dump it's info */ switch(opr->oprclass) { case TVAR_REF: PRINTF("%s Temporary variable index %d\n", cdbg_indent(indent), opr->oprval.temp); break; case TCAD_REF: case TVAD_REF: PRINTF("%s %s reference - whatever it means: value is %d\n", cdbg_indent(indent), ((TCAD_REF == opr->oprclass) ? "TCAD_REF" : "TVAD_REF"), opr->oprval.temp); break; case MVAR_REF: if (opr->oprval.vref) { PRINTF("%s LS vref: 0x"lvaddr" RS vref: 0x"lvaddr" index: %d varname: %s last triple: " "0x"lvaddr"\n", cdbg_indent(indent),(long unsigned int) opr->oprval.vref->lson, (long unsigned int) opr->oprval.vref->rson, opr->oprval.vref->mvidx, cdbg_makstr(opr->oprval.vref->mvname.addr, &buff, opr->oprval.vref->mvname.len), (long unsigned int) opr->oprval.vref->last_fetch); free(buff); } else PRINTF("%s ** Warning ** oprval.vref is NULL\n", cdbg_indent(indent)); break; case TINT_REF: case TVAL_REF: offset = sa_temps_offset[opr->oprclass]; offset -= (sa_temps[opr->oprclass] - opr->oprval.temp) * sa_class_sizes[opr->oprclass]; PRINTF("%s temp index: %d offset: 0x%08x\n", cdbg_indent(indent), opr->oprval.temp, offset); break; case ILIT_REF: PRINTF("%s ilit value: %d [0x%08x]\n", cdbg_indent(indent), opr->oprval.ilit, opr->oprval.ilit); break; case MLIT_REF: if (opr->oprval.mlit) PRINTF("%s lit-ref fwdptr: 0x"lvaddr" bkwdptr: 0x"lvaddr" rtaddr: 0x"lvaddr"\n", cdbg_indent(indent), (long unsigned int) opr->oprval.mlit->que.fl, (long unsigned int) opr->oprval.mlit->que.bl, opr->oprval.mlit->rt_addr); else PRINTF("%s ** Warning ** oprval.mlit is NULL\n", cdbg_indent(indent)); cdbg_dump_mval(indent, &opr->oprval.mlit->v); break; case TJMP_REF: if (opr->oprval.tref) PRINTF("%s tjmp-ref jump list ptr: 0x"lvaddr"\n", cdbg_indent(indent), (long unsigned int) &opr->oprval.tref->jmplist); else PRINTF("%s ** Warning ** oprval.tref is NULL\n", cdbg_indent(indent)); break; case TRIP_REF: rtrip = opr->oprval.tref; PRINTF("%s Trip reference:\n", cdbg_indent(indent)); cdbg_dump_triple(rtrip, indent + 1); break; case INDR_REF: cdbg_dump_operand(indent, opr->oprval.indr, opnum); break; case TSIZ_REF: if (opr->oprval.tsize) PRINTF("%s triple at 0x"lvaddr" has size %d\n", cdbg_indent(indent), (long unsigned int) opr->oprval.tsize->ct, opr->oprval.tsize->size); else PRINTF("%s ** Warning ** oprval.tsize is NULL\n", cdbg_indent(indent)); break; case OCNT_REF: PRINTF("%s offset from call to next triple: %d\n", cdbg_indent(indent), opr->oprval.offset); break; case MLAB_REF: case MFUN_REF: if (opr->oprval.lab) { len = opr->oprval.lab->mvname.len; memcpy(mid, opr->oprval.lab->mvname.addr, len); mid[len] = 0; PRINTF("%s ref type: %s mlabel name: %s\n", cdbg_indent(indent), oprtype_type_names[opr->oprclass], mid); } else PRINTF("%s ref type: %s ** Warning ** oprval.lab is NULL\n", cdbg_indent(indent), oprtype_type_names[opr->oprclass]); break; case CDLT_REF: if (opr->oprval.cdlt) { len = opr->oprval.cdlt->len; memcpy(mid, opr->oprval.cdlt->addr, len); mid[len] = 0; PRINTF("%s cdlt-ref mstr->%s", cdbg_indent(indent), mid); } else PRINTF("%s ref type: %s ** Warning ** oprval.cdlt is NULL\n", cdbg_indent(indent), oprtype_type_names[opr->oprclass]); break; default: PRINTF("%s %s bogus reference\n", cdbg_indent(indent), oprtype_type_names[opr->oprclass]); } FFLUSH(stdout); } void cdbg_dump_mval(int indent, mval *mv) { boolean_t first; double mvf; int4 mvd; PRINTF("%s Type: 0x%1x (", cdbg_indent(indent), mv->mvtype); first = TRUE; if (mv->mvtype & MV_NM) { PRINTF("Number"); first = FALSE; } if (mv->mvtype & MV_INT) { if (!first) PRINTF(", "); PRINTF("Integer"); first = FALSE; } if (mv->mvtype & MV_STR) { if (!first) PRINTF(", "); PRINTF("String"); FFLUSH(stdout); first = FALSE; } if (first) { PRINTF("Undefined MVAL)\n"); return; } PRINTF(") Sign: %d Exp: %d\n", mv->sgn, mv->e); if (mv->mvtype & MV_NUM_MASK) { if (mv->mvtype & MV_INT) { mvd = mval2i(mv); PRINTF("%s Integer value: %d\n", cdbg_indent(indent), mvd); } else { mvf = mval2double(mv); PRINTF("%s Double value: %f\n", cdbg_indent(indent), mvf); } } if (mv->mvtype & MV_STR) { if (!mv->str.len) PRINTF("%s String value: \n", cdbg_indent(indent)); else cdbg_dump_mstr(indent, &mv->str); } FFLUSH(stdout); } /* Dump value of a given mstr. Assumes length is non-zero */ void cdbg_dump_mstr(int indent, mstr *ms) { unsigned char *buffer, *strp; int len; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; len = ms->len; strp = (unsigned char *)ms->addr; # if defined(USHBIN_SUPPORTED) || defined(VMS) /* In shared binary mode, shrink_trips is called after indir_lits() changes the addresses * in the mvals to offsets. De-offset them if they don't point into the (indirect) * stringpool. This *ONLY* happens during an indirect compilation. */ assert(TREF(compile_time) || indr_stringpool.base != indr_stringpool.free); if (!TREF(compile_time) && strp < indr_stringpool.base) strp += (UINTPTR_T)(indr_stringpool.base - SIZEOF(ihdtyp) - PADLEN(SIZEOF(ihdtyp), NATIVE_WSIZE)); # endif buffer = malloc(len + 1); memcpy(buffer, strp, len); buffer[len] = 0; PRINTF("%s String value: %s\n", cdbg_indent(indent), buffer); FFLUSH(stdout); free(buffer); } /* Provide string to do indenting of formatted output */ char *cdbg_indent(int indent) { if (10 >= indent) return (char *)indents[indent]; if (NULL == indent_str) indent_str = malloc(MAX_INDENT); if (MAX_INDENT < indent * 2) { FFLUSH(stdout); GTMASSERT; } if (indent > last_indent) memset(indent_str, ' ', indent * 2); indent_str[indent * 2] = 0; last_indent = indent; return indent_str; } /* Make a given addr/len string into a null terminate string */ char *cdbg_makstr(char *str, char **buf, int len) { *buf = malloc(len + 1); memcpy(*buf, str, len); (*buf)[len] = 0; return *buf; } fis-gtm-V6.0-003/sr_port/cdbg_dump.h0000644000032200000250000000201712201176154016126 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CDBG_DUMP_H #define CDBG_DUMP_H /* Values for 2nd arg of cdbg_dump_operand */ #define OP_0 0 /* operand[0] is passed */ #define OP_1 1 /* operand[1] is passed */ #define OP_DEST 2 /* destination is passed */ void cdbg_dump_triple(triple *dtrip, int indent); void cdbg_dump_shrunk_triple(triple *dtrip, int old_size, int new_size); void cdbg_dump_operand(int indent, oprtype *opr, int opnum); void cdbg_dump_mval(int indent, mval *mv); void cdbg_dump_mstr(int indent, mstr *ms); char *cdbg_indent(int indent); char *cdbg_makstr(char *str, char **buf, mstr_len_t len); #endif fis-gtm-V6.0-003/sr_port/ceprep_file.c0000644000032200000250000000733312201176154016460 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #ifdef VMS #include static struct FAB ceprep_fab; /* file access block for compiler escape preprocessor output */ static struct RAB ceprep_rab; /* record access block for compiler escape preprocessor output */ #endif #include "gtm_string.h" #include "cmd_qlf.h" #include "compiler.h" #include "io.h" #include "io_params.h" #include "op.h" #include "comp_esc.h" #define CEPREP_OPEN_TIMEOUT 30 GBLREF unsigned char source_buffer[]; GBLREF mident module_name; GBLREF io_pair io_curr_device; GBLREF command_qualifier cmd_qlf; static io_pair dev_in_use; void open_ceprep_file(void) { #ifdef VMS /* stub except for VMS */ #ifdef __ALPHA # pragma member_alignment save # pragma nomember_alignment #endif static readonly struct { unsigned char newversion; unsigned char wrap; unsigned char width; int4 v_width; unsigned char eol; } open_params_list = { (unsigned char) iop_newversion, (unsigned char) iop_wrap, (unsigned char) iop_recordsize, (int4) MAX_SRCLINE, (unsigned char) iop_eol }; #ifdef __ALPHA # pragma member_alignment restore #endif int mname_len; uint4 status; char charspace, ceprep_name_buff[MAX_MIDENT_LEN + SIZEOF(".MCI") - 1], fname[255]; mval file, params; struct NAM ceprep_nam; /* name block for file access block for compiler escape preprocessor output */ /* Create cepreprocessor output file. */ ceprep_fab = cc$rms_fab; ceprep_fab.fab$l_dna = ceprep_name_buff; mname_len = module_name.len; assert(mname_len <= MAX_MIDENT_LEN); if (0 == mname_len) { MEMCPY_LIT(ceprep_name_buff, "MDEFAULT.MCI"); ceprep_fab.fab$b_dns = SIZEOF("MDEFAULT.MCI") - 1; } else { memcpy(ceprep_name_buff, module_name.addr, mname_len); MEMCPY_LIT(&ceprep_name_buff[mname_len], ".MCI"); ceprep_fab.fab$b_dns = mname_len + SIZEOF(".MCI") - 1; } if (MV_DEFINED(&cmd_qlf.ceprep_file)) { ceprep_fab.fab$b_fns = cmd_qlf.ceprep_file.str.len; ceprep_fab.fab$l_fna = cmd_qlf.ceprep_file.str.addr; } ceprep_nam = cc$rms_nam; ceprep_nam.nam$l_esa = fname; ceprep_nam.nam$b_ess = SIZEOF(fname); ceprep_nam.nam$b_nop = (NAM$M_SYNCHK); ceprep_fab.fab$l_nam = &ceprep_nam; ceprep_fab.fab$l_fop = FAB$M_NAM; if (RMS$_NORMAL != (status = sys$parse(&ceprep_fab, 0, 0))) rts_error(VARLSTCNT(1) status); file.mvtype = params.mvtype = MV_STR; file.str.len = ceprep_nam.nam$b_esl; file.str.addr = fname; params.str.len = SIZEOF(open_params_list); params.str.addr = &open_params_list; op_open(&file, ¶ms, CEPREP_OPEN_TIMEOUT, 0); params.str.len = 1; charspace = (char)iop_eol; params.str.addr = &charspace; dev_in_use = io_curr_device; op_use(&file, ¶ms); #endif return; } void close_ceprep_file(void) { #ifdef VMS /* stub except for VMS */ unsigned char charspace; mval param, ceprep_file; param.str.len = 1; charspace = (char)iop_eol; param.str.addr = &charspace; ceprep_file.mvtype = param.mvtype = MV_STR; ceprep_file.str.len = io_curr_device.in->trans_name->len; ceprep_file.str.addr = io_curr_device.in->trans_name->dollar_io; op_close(&ceprep_file, ¶m); io_curr_device = dev_in_use; #endif return; } void put_ceprep_line(void) { #ifdef VMS /* stub except for VMS */ mval out; out.mvtype = MV_STR; out.str.len = strlen((char *)source_buffer); out.str.addr = source_buffer; op_write(&out); op_wteol(1); #endif return; } fis-gtm-V6.0-003/sr_port/cert_blk.c0000644000032200000250000003556512201176176016004 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsbml.h" #include "copy.h" #include "subscript.h" #include "filestruct.h" #include "gdscc.h" #include "gdskill.h" /* needed for tp.h */ #include "jnl.h" /* needed for tp.h */ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "error.h" #include "mmemory.h" #include "gtm_ffs.h" #include "cert_blk.h" #include "gtm_ctype.h" #ifdef GTM_TRIGGER #include #include "gv_trigger.h" #endif GBLREF uint4 dollar_tlevel; GBLREF boolean_t dse_running; GBLREF boolean_t mu_reorg_upgrd_dwngrd_in_prog; error_def(ERR_DBBLEVMX); error_def(ERR_DBBLEVMN); error_def(ERR_DBBSIZMN); error_def(ERR_DBBSIZMX); error_def(ERR_DBRSIZMN); error_def(ERR_DBRSIZMX); error_def(ERR_DBCMPNZRO); error_def(ERR_DBSTARSIZ); error_def(ERR_DBSTARCMP); error_def(ERR_DBCMPMX); error_def(ERR_DBKEYMX); error_def(ERR_DBKEYMN); error_def(ERR_DBCMPBAD); error_def(ERR_DBKEYORD); error_def(ERR_DBPTRNOTPOS); error_def(ERR_DBPTRMX); error_def(ERR_DBPTRMAP); error_def(ERR_DBLVLINC); error_def(ERR_DBBMSIZE); error_def(ERR_DBBMBARE); error_def(ERR_DBBMINV); error_def(ERR_DBBMMSTR); error_def(ERR_DBROOTBURN); error_def(ERR_DBDIRTSUBSC); error_def(ERR_DBMAXNRSUBS); /* same error as ERR_MAXNRSUBSCRIPTS, but has a string output as well */ error_def(ERR_DBINVGBL); error_def(ERR_DBBDBALLOC); #define BITS_PER_UCHAR 8 #define BLKS_PER_UINT4 ((SIZEOF(uint4) / SIZEOF(unsigned char)) * BITS_PER_UCHAR) / BML_BITS_PER_BLK #define BLOCK_WINDOW 8 #define LEVEL_WINDOW 3 #define OFFSET_WINDOW 4 #define TEXT1 ": " #define TEXT2 " " #define TEXT3 ":" #define TEXT4 ", " #define MAX_UTIL_LEN 40 #define RTS_ERROR_FUNC(CSA, ERR, BUFF) \ { \ if (gtmassert_on_error) \ GTMASSERT; \ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(4) MAKE_MSG_INFO(ERR), 2, LEN_AND_STR((char_ptr_t)BUFF)); \ } int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boolean_t gtmassert_on_error) { block_id child, prev_child; rec_hdr_ptr_t rp, r_top; int num_subscripts; uint4 bplmap, mask1, offset, rec_offset, rec_size; sm_uint_ptr_t chunk_p; /* Value is unaligned so will be assigned to chunk */ uint4 chunk, blk_size; sm_uc_ptr_t blk_top, blk_id_ptr, next_tp_child_ptr, key_base, mp, b_ptr; unsigned short rec_cmpc, min_cmpc; /* the minimum cmpc expected in any record (except star-key) in a gvt */ int tmp_cmpc; unsigned char ch, prior_expkey[MAX_KEY_SZ + 1]; unsigned int prior_expkeylen; unsigned short temp_ushort; int blk_levl; int comp_length, key_size; unsigned char util_buff[MAX_UTIL_LEN]; int util_len; off_chain chain; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; boolean_t is_gvt, is_directory, first_key, full, prev_char_is_delimiter; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; csa = &FILE_INFO(reg)->s_addrs; csd = csa->hdr; bplmap = csd->bplmap; assert(bplmap == BLKS_PER_LMAP); blk_levl = bp->levl; blk_size = bp->bsiz; offset = (uint4)blk / bplmap; util_len=0; i2hex_blkfill(blk,&util_buff[util_len], BLOCK_WINDOW); util_len += BLOCK_WINDOW; MEMCPY_LIT(&util_buff[util_len], TEXT1); /* OFFSET_WINDOW + 1 spaces */ util_len += SIZEOF(TEXT3) - 1; util_len += OFFSET_WINDOW +1; i2hex_blkfill(blk_levl, &util_buff[util_len], LEVEL_WINDOW); util_len += LEVEL_WINDOW; MEMCPY_LIT(&util_buff[util_len], TEXT2); util_len += SIZEOF(TEXT2) - 1; util_buff[util_len] = 0; chain = *(off_chain *)&blk; /* Assert that if at all chain.flag is non-zero (i.e. a created block), we are in TP and not yet in the commit logic. * The only exception to this rule is if we are in TP and inside phase1 of the commit logic and trying to certify a * block that was killed inside of the transaction (possible if cert_blk is called directly from tp_tend). In this case, * the block number passed is a special value GDS_CREATE_BLK_MAX so check that. */ assert(!chain.flag || dollar_tlevel && (!csa->t_commit_crit || ((T_COMMIT_CRIT_PHASE1 == csa->t_commit_crit) && (GDS_CREATE_BLK_MAX == blk)))); if (!chain.flag && ((offset * bplmap) == (uint4)blk)) /* it's a bitmap */ { if ((unsigned char)blk_levl != LCL_MAP_LEVL) { RTS_ERROR_FUNC(csa, MAKE_MSG_INFO(ERR_DBLVLINC), util_buff); return FALSE; } if (blk_size != BM_SIZE(bplmap)) { RTS_ERROR_FUNC(csa, ERR_DBBMSIZE, util_buff); return FALSE; } mp = (sm_uc_ptr_t)bp + SIZEOF(blk_hdr); if ((*mp & 1) != 0) { /* bitmap doesn't protect itself */ RTS_ERROR_FUNC(csa, ERR_DBBMBARE, util_buff); return FALSE; } full = TRUE; offset = ((csa->ti->total_blks - blk) >= bplmap) ? bplmap : (csa->ti->total_blks - blk); blk_top = (sm_uc_ptr_t)bp + BM_SIZE(offset + (BITS_PER_UCHAR / BML_BITS_PER_BLK) - 1); for (chunk_p = (sm_uint_ptr_t)mp ; (sm_uc_ptr_t)chunk_p - blk_top < 0 ; chunk_p++) { GET_LONG(chunk, chunk_p); /* Obtain unalinged unit4 value */ /* The following code is NOT independent of the bitmap layout: */ mask1 = chunk & SIXTEEN_BLKS_FREE; /* mask 'recycled' blocks to 'free' blocks */ if ((mask1 != 0) && full) /* check for free blocks */ { /* if (full bitmap || full chunk || regular scan of a "short" bitmap) */ if ((offset == bplmap) || ((blk_top - (sm_uc_ptr_t)chunk_p) > SIZEOF(chunk)) || (NO_FREE_SPACE != bml_find_free((int4)((sm_uc_ptr_t)chunk_p - mp), mp, offset))) { full = FALSE; } } mask1 ^= SIXTEEN_BLKS_FREE; /* complement to busy */ mask1 <<= 1; /* shift to reused position */ mask1 &= chunk; /* check against the original contents */ if (mask1 != 0) /* busy and reused should never appear together */ { RTS_ERROR_FUNC(csa, ERR_DBBMINV, util_buff); return FALSE; } } if (full == (NO_FREE_SPACE != gtm_ffs(blk / bplmap, MM_ADDR(csd), MASTER_MAP_BITS_PER_LMAP))) { RTS_ERROR_FUNC(csa, ERR_DBBMMSTR, util_buff); /* DSE CACHE -VERIFY used to fail occasionally with the DBBMMSTR error because of passing * an older twin global buffer that contained stale bitmap information. That is now fixed. * So we dont expect any more such failures. Assert accordingly. */ assert(!dse_running); return FALSE; } return TRUE; } if (blk_levl > MAX_BT_DEPTH) { RTS_ERROR_FUNC(csa, ERR_DBBLEVMX, util_buff); return FALSE; } if (blk_levl < 0) { RTS_ERROR_FUNC(csa, ERR_DBBLEVMN, util_buff); return FALSE; } if (blk_levl == 0) { /* data block */ if ((DIR_ROOT == blk) || (blk == root)) { /* headed for where an index block should be */ RTS_ERROR_FUNC(csa, ERR_DBROOTBURN, util_buff); return FALSE; } if (blk_size < (uint4)SIZEOF(blk_hdr)) { RTS_ERROR_FUNC(csa, ERR_DBBSIZMN, util_buff); return FALSE; } } else { /* index block */ if (blk_size < (uint4)(SIZEOF(blk_hdr) + SIZEOF(rec_hdr) + SIZEOF(block_id))) { /* must have at least one record */ RTS_ERROR_FUNC(csa, ERR_DBBSIZMN, util_buff); return FALSE; } } if (blk_size > (uint4)csd->blk_size) { RTS_ERROR_FUNC(csa, ERR_DBBSIZMX, util_buff); return FALSE; } is_directory = FALSE; is_gvt = FALSE; /* if both "is_directory" and "is_gvt" are FALSE, then we dont know YET if the given block is a directory or gvt */ if (DIR_ROOT == root) is_directory = TRUE; if ((0 != root) && (DIR_ROOT != root)) is_gvt = TRUE; /* MUPIP REORG -TRUNCATE has some special cases */ if (MUSWP_INCR_ROOT_CYCLE == TREF(in_mu_swap_root_state)) { /* We could be updating either a gvt root block or a directory leaf block. Don't know yet. */ is_directory = FALSE; is_gvt = FALSE; } else if (MUSWP_DIRECTORY_SWAP == TREF(in_mu_swap_root_state)) { /* We know we're updating a directory block, even though root is not DIR_ROOT. root and gv_target correspond * to the gvt being REORG'ed. */ is_directory = TRUE; is_gvt = FALSE; } blk_top = (sm_uc_ptr_t)bp + blk_size; first_key = TRUE; min_cmpc = 0; prior_expkeylen = 0; comp_length = 2 * SIZEOF(char); /* for double NUL to indicate no prior key */ prior_expkey[0] = prior_expkey[1] = 0; /* double NUL also works for memvcmp test for key order */ next_tp_child_ptr = NULL; prev_child = 0; for (rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)bp + SIZEOF(blk_hdr)) ; rp < (rec_hdr_ptr_t)blk_top ; rp = r_top) { GET_RSIZ(rec_size, rp); rec_offset = (uint4)((sm_ulong_t)rp - (sm_ulong_t)bp); /*add util_buff here*/ util_len=0; i2hex_blkfill(blk,&util_buff[util_len], BLOCK_WINDOW); util_len += BLOCK_WINDOW; MEMCPY_LIT(&util_buff[util_len], TEXT1); /* OFFSET_WINDOW + 1 spaces */ util_len += SIZEOF(TEXT3) - 1; i2hex_nofill(rec_offset, &util_buff[util_len], OFFSET_WINDOW); util_len += OFFSET_WINDOW + 1; i2hex_blkfill(blk_levl, &util_buff[util_len], LEVEL_WINDOW); util_len += LEVEL_WINDOW; MEMCPY_LIT(&util_buff[util_len], TEXT2); util_len += SIZEOF(TEXT2) - 1; util_buff[util_len] = 0; if (rec_size <= (uint4)SIZEOF(rec_hdr)) { RTS_ERROR_FUNC(csa, ERR_DBRSIZMN, util_buff); return FALSE; } if (rec_size > (uint4)((sm_ulong_t)blk_top - (sm_ulong_t)rp)) { RTS_ERROR_FUNC(csa, ERR_DBRSIZMX, util_buff); return FALSE; } r_top = (rec_hdr_ptr_t)((sm_ulong_t)rp + rec_size); rec_cmpc = EVAL_CMPC(rp); if (first_key) { if (rec_cmpc) { RTS_ERROR_FUNC(csa, ERR_DBCMPNZRO, util_buff); return FALSE; } if (0 == blk_levl) { ch = *((sm_uc_ptr_t)rp + SIZEOF(rec_hdr)); if (!(VALFIRSTCHAR_WITH_TRIG(ch))) GTMASSERT; } } if (r_top == (rec_hdr_ptr_t)blk_top && blk_levl) { /* star key */ if (rec_size != SIZEOF(rec_hdr) + SIZEOF(block_id)) { RTS_ERROR_FUNC(csa, ERR_DBSTARSIZ, util_buff); return FALSE; } if (rec_cmpc) { RTS_ERROR_FUNC(csa, ERR_DBSTARCMP, util_buff); return FALSE; } blk_id_ptr = (sm_uc_ptr_t)rp + SIZEOF(rec_hdr); } else { /* non-star key */ key_base = (sm_uc_ptr_t)rp + SIZEOF(rec_hdr); /* num_subscripts = number of full subscripts found in the key (including the compressed part) */ num_subscripts = 0; prev_char_is_delimiter = FALSE; if (rec_cmpc) { if (rec_cmpc >= prior_expkeylen) { RTS_ERROR_FUNC(csa, ERR_DBCMPMX, util_buff); return FALSE; } for (b_ptr = prior_expkey; b_ptr < (prior_expkey + rec_cmpc); b_ptr++) { if (KEY_DELIMITER == *b_ptr) num_subscripts++; } prev_char_is_delimiter = (KEY_DELIMITER == prior_expkey[rec_cmpc - 1]); } assert(key_base < (sm_uc_ptr_t)r_top); /* otherwise we would have signalled ERR_DBRSIZMN error */ for (blk_id_ptr = key_base ; ; ) { if (KEY_DELIMITER == *blk_id_ptr++) { if (!min_cmpc) { /* note down the length of the global-variable (without subscripts) from the * first key in the block. every other record in this block (except the star-key * in case of an index block) should have a rec_cmpc that is atleast this much * (of course this is TRUE only if we are in a GVT). */ min_cmpc = blk_id_ptr - key_base; } if (prev_char_is_delimiter) break; /* found key terminator */ prev_char_is_delimiter = TRUE; num_subscripts++; } else prev_char_is_delimiter = FALSE; if (blk_id_ptr >= (sm_uc_ptr_t)r_top) { RTS_ERROR_FUNC(csa, ERR_DBKEYMX, util_buff); return FALSE; } } num_subscripts--; /* the global variable name was counted above as a subscript. adjust that */ key_size = (int4)(blk_id_ptr - key_base); if (!first_key && (rec_cmpc < min_cmpc)) { /* name-level change between consecutive records in the block, this should be a directory block */ if (is_gvt) { /* this is a contradiction. a block cannot be a directory and gvt at the same time. * gvt should contain all keys with the same global name */ RTS_ERROR_FUNC(csa, ERR_DBINVGBL, util_buff); return FALSE; } is_directory = TRUE; /* no need to do this if it was already TRUE but we save an if check */ } if (num_subscripts) { /* key has subscripts, should therefore be a GVT block */ if (is_directory) { /* this is a contradiction. a block cannot be a directory and gvt at the same time. * the directory tree should contain only name-level (i.e. unsubscripted) globals */ RTS_ERROR_FUNC(csa, ERR_DBDIRTSUBSC, util_buff); return FALSE; } is_gvt = TRUE; /* no need to do this if it was already TRUE but we save an if check */ } if (MAX_GVSUBSCRIPTS <= num_subscripts) { RTS_ERROR_FUNC(csa, ERR_DBMAXNRSUBS, util_buff); return FALSE; } if (blk_levl && (key_size != (rec_size - SIZEOF(block_id) - SIZEOF(rec_hdr)))) { RTS_ERROR_FUNC(csa, ERR_DBKEYMN, util_buff); return FALSE; } assert(first_key || (rec_cmpc < prior_expkeylen)); if (!first_key) { if (prior_expkey[rec_cmpc] == key_base[0]) { RTS_ERROR_FUNC(csa, ERR_DBCMPBAD, util_buff); return FALSE; } if (((unsigned int)prior_expkey[rec_cmpc] >= (unsigned int)key_base[0])) { RTS_ERROR_FUNC(csa, ERR_DBKEYORD, util_buff); return FALSE; } } memcpy(prior_expkey + rec_cmpc, key_base, key_size); prior_expkeylen = rec_cmpc + key_size; } /* Check for proper child block numbers */ if ((0 != blk_levl) || (0 != is_directory)) { GET_LONG(child, blk_id_ptr); chain = *(off_chain *)&child; /* In TP, child block number can be greater than the total_blks for blocks created within TP. * Dont do any checks on such blocks. */ if (!dollar_tlevel || !chain.flag) { if (child <= 0) { RTS_ERROR_FUNC(csa, ERR_DBPTRNOTPOS, util_buff); return FALSE; } if ((child > csa->ti->total_blks) && !mu_reorg_upgrd_dwngrd_in_prog) { /* REORG -UPGRADE/DOWNGRADE can update recycled blocks, which may contain children beyond * the total_blks if a truncate happened sometime after the block was killed. */ RTS_ERROR_FUNC(csa, ERR_DBPTRMX, util_buff); return FALSE; } if (!(child % bplmap)) { RTS_ERROR_FUNC(csa, ERR_DBPTRMAP, util_buff); return FALSE; } if (child == prev_child) { RTS_ERROR_FUNC(csa, ERR_DBBDBALLOC, util_buff); return FALSE; } prev_child = child; } else { if ((blk_id_ptr != next_tp_child_ptr) && (NULL != next_tp_child_ptr)) { RTS_ERROR_FUNC(csa, ERR_DBPTRNOTPOS, util_buff); return FALSE; } next_tp_child_ptr = blk_id_ptr + chain.next_off; } } first_key = FALSE; comp_length = prior_expkeylen; } assert(!is_directory || !is_gvt); /* the block cannot be a directory AND gvt at the same time */ return TRUE; } fis-gtm-V6.0-003/sr_port/cert_blk.h0000644000032200000250000000323312201176154015770 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CERT_BLK_DEFINED #define CERT_BLK_DEFINED int cert_blk(gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boolean_t gtmassert_on_error); #define CERT_BLK_IF_NEEDED(certify_all_blocks, gv_cur_region, cs, blk_ptr, gv_target) \ { \ assert(gds_t_create != cs->mode); /* should have morphed into gds_t_acquired before getting here */ \ if (certify_all_blocks) \ { /* GTMASSERT on integ error */ \ /* If cs->mode is of type kill_t_create, then it would have been assigned an arbitrary block# \ * inside of the transaction which could match a real block # in the database at this point. \ * For example, it could be identical to the root block of the global in which case cert_blk \ * will assume this is the root block when actually this is a block that is no longer part of \ * the tree. So pass an invalid block# that indicates it is a created block. \ */ \ cert_blk(gv_cur_region, \ ((kill_t_create != cs->mode) ? cs->blk : GDS_CREATE_BLK_MAX), (blk_hdr_ptr_t)blk_ptr, \ dollar_tlevel ? ((NULL != cs->blk_target) ? cs->blk_target->root : 0) \ : ((NULL != gv_target) ? gv_target->root : 0), TRUE); \ } \ } #endif fis-gtm-V6.0-003/sr_port/cg_var.c0000644000032200000250000000202412201176176015440 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include #include "obj_file.h" #include "cg_var.h" #include "stringpool.h" #include "hashtab_mname.h" GBLREF spdesc stringpool; void cg_var(mvar *v, var_tabent **p) { /* Copy mident with variable name to variable table entry */ assert(stringpool.base <= (unsigned char *)v->mvname.addr && (unsigned char *)v->mvname.addr < stringpool.top); (*p)[v->mvidx].var_name = v->mvname; COMPUTE_HASH_MNAME(&((*p)[v->mvidx])); (*p)[v->mvidx].var_name.addr = (char *)(v->mvname.addr - (char *)stringpool.base); (*p)[v->mvidx].marked = FALSE; } fis-gtm-V6.0-003/sr_port/cg_var.h0000644000032200000250000000112112201176154015436 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2004 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CG_VAR_H_INCLUDED #define CG_VAR_H_INCLUDED void cg_var(mvar *v, var_tabent **p); void ind_cg_var(mvar *v, var_tabent **p); #endif fis-gtm-V6.0-003/sr_port/cgp.h0000644000032200000250000000117712201176154014761 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #define CGP_NOSTATE (0) #define CGP_PARSE (1) #define CGP_RESOLVE (2) #define CGP_APPROX_ADDR (3) #define CGP_ADDR_OPT (4) #define CGP_ASSEMBLY (5) #define CGP_MACHINE (6) #define CGP_FINI (7) fis-gtm-V6.0-003/sr_port/change_reg.c0000644000032200000250000000235512201176154016264 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "change_reg.h" #include "tp_set_sgm.h" GBLREF gd_region *gv_cur_region; GBLREF sgmnt_data_ptr_t cs_data; GBLREF sgmnt_addrs *cs_addrs; GBLREF uint4 dollar_tlevel; void change_reg(void) { if (!gv_cur_region) { cs_addrs = (sgmnt_addrs *)0; cs_data = (sgmnt_data_ptr_t)0; return; } switch (gv_cur_region->dyn.addr->acc_meth) { case dba_usr: case dba_cm: cs_addrs = (sgmnt_addrs *)0; cs_data = (sgmnt_data_ptr_t)0; break; case dba_mm: case dba_bg: cs_addrs = &FILE_INFO(gv_cur_region)->s_addrs; cs_data = cs_addrs->hdr; if (dollar_tlevel) tp_set_sgm(); break; default: GTMASSERT; } } fis-gtm-V6.0-003/sr_port/change_reg.h0000644000032200000250000000106012201176154016261 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CHANGE_REG_INCLUDED #define CHANGE_REG_INCLUDED void change_reg(void); #endif /* CHANGE_REG_INCLUDED */ fis-gtm-V6.0-003/sr_port/chk2lev.m0000644000032200000250000000152712201176154015552 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; chk2lev ;check for op codes which are missing slots New x,i Set x="" For Set x=$o(work(x)) Quit:x="" Do . If x#1 Do Quit . . Set x=x\1 . . If "OC_CO"'=$Extract(opx(x),1,5) Do . . . For i=x+.1:.1:x+.3 If '$Data(work(i)) Write !,"subcode ",i-x*10," is missing for op code ",x," (",opx(x),")",! . . Set x=x+.9 . If $Order(work(x))\1=x Write !,"triple code ",x," (",opx(x),") is present with subcodes",! Quit fis-gtm-V6.0-003/sr_port/chkop.m0000644000032200000250000000117112201176154015313 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; chkop ;display undefined triple codes u "" n x w !,"missing triple op codes: ",! s x="" chkop1 s x=$o(opx(x)) i x="" g chkop9 i '$d(work(x)),'$d(work(x+.1)) w x,?7,opx(x),! g chkop1 chkop9 q fis-gtm-V6.0-003/sr_port/chktchain.c0000644000032200000250000000246012201176154016133 0ustar librarygtc/**************************************************************** * * * Copyright 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" /* Check that the triple chain is a well formed doubly linked list */ void chktchain(triple *head) { triple *tp, *tp2; /* tp2 is needed to detect cycles in the list (so we avoid looping indefinitely) that dont return to the head */ for (tp = head->exorder.fl, tp2 = tp->exorder.fl; tp != head; tp = tp->exorder.fl, tp2 = tp2->exorder.fl->exorder.fl) { if (tp->exorder.bl->exorder.fl != tp) GTMASSERT; /* if this assert fails, then recompile with DEBUG_TRIPLES to catch the issue sooner */ if (tp->exorder.fl->exorder.bl != tp) GTMASSERT; /* if this assert fails, then recompile with DEBUG_TRIPLES to catch the issue sooner */ if (tp == tp2) /* cycle found, but without returning to the head of the linked list */ GTMASSERT; /* if this assert fails, then recompile with DEBUG_TRIPLES to catch the issue sooner */ } } fis-gtm-V6.0-003/sr_port/cli_get_str_ele.c0000644000032200000250000000150712201176154017323 0ustar librarygtc/**************************************************************** * * * Copyright 2003 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "cliif.h" LITREF unsigned char lower_to_upper_table[]; bool cli_get_str_ele(char *inbuff, char *dst, unsigned short *dst_len, boolean_t upper_case) { *dst_len = 0; while (*inbuff && ',' != *inbuff) { if (upper_case) *dst++ = lower_to_upper_table[*inbuff++]; else *dst++ = *inbuff++; (*dst_len)++; } *dst = 0; return (*dst_len ? TRUE : FALSE); } fis-gtm-V6.0-003/sr_port/cli_port.c0000644000032200000250000002164312201176154016016 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_ctype.h" #include "gtm_stdio.h" #include "gtm_stdlib.h" #include "gtm_string.h" #include "gtm_limits.h" #include #include "cli.h" #include "util.h" /* A lot of stuff that can be made portable across unix and vvms cli.c needs to be moved into this module. * For a start, cli_str_to_hex() is moved in. At least cli_get_str(), cli_get_int(), cli_get_num() can be moved in later. */ /* *------------------------------------------------------- * Check if string is a decimal number * * Return: * TRUE - only decimal digits * FALSE - otherwise * ------------------------------------------------------- */ int cli_is_dcm(char *p) { while (*p && ISDIGIT_ASCII(*p)) p++; if (*p) return (FALSE); else return (TRUE); } /* * -------------------------------------------------- * Convert string to hex. * * Return: * TRUE - OK * FALSE - Could not convert to hex * -------------------------------------------------- */ boolean_t cli_str_to_hex(char *str, uint4 *dst) { unsigned long result; int save_errno; save_errno = errno; errno = 0; result = STRTOUL(str, NULL, 16); if ( #if INT_MAX < LONG_MAX (UINT_MAX < result) || /* outside UINT range */ #endif (ERANGE == errno && ULONG_MAX == result) || (0 == result && 0 != errno)) { /* out of range or other error */ *dst = 0; errno = save_errno; return FALSE; } else { *dst = (uint4)result; errno = save_errno; return TRUE; } } /* * -------------------------------------------------- * Convert string to 64 bit hex. * * Return: * TRUE - OK * FALSE - Could not convert to hex * -------------------------------------------------- */ boolean_t cli_str_to_hex64(char *str, gtm_uint64_t *dst) { gtm_uint64_t result; int save_errno; save_errno = errno; errno = 0; result = STRTOU64L(str, NULL, 16); if ((ERANGE == errno && GTM_UINT64_MAX == result) || (0 == result && 0 != errno)) { /* out of range or other error */ *dst = 0; errno = save_errno; return FALSE; } else { *dst = result; errno = save_errno; return TRUE; } } /* * -------------------------------------------------- * Convert string to 64 bit unsigned int. * * Return: * TRUE - OK * FALSE - Could not convert to int * -------------------------------------------------- */ boolean_t cli_str_to_uint64(char *str, gtm_uint64_t *dst) { gtm_uint64_t result; int save_errno; save_errno = errno; errno = 0; result = STRTOU64L(str, NULL, 10); if ((ERANGE == errno && GTM_UINT64_MAX == result) || (0 == result && 0 != errno)) { /* out of range or other error */ *dst = 0; errno = save_errno; return FALSE; } else { *dst = result; errno = save_errno; return TRUE; } } /* * -------------------------------------------------- * Convert string to int. * * Return: * TRUE - OK * FALSE - Could not convert to int * -------------------------------------------------- */ boolean_t cli_str_to_int(char *str, int4 *dst) { long result; int save_errno; save_errno = errno; errno = 0; result = STRTOL(str, NULL, 10); if ( #if INT_MAX < LONG_MAX (INT_MIN > result || INT_MAX < result) || /* outside INT range */ #endif (ERANGE == errno && (LONG_MIN == result || LONG_MAX == result)) || (0 == result && 0 != errno)) { /* out of range or other error */ *dst = 0; errno = save_errno; return FALSE; } else { *dst = (int4)result; errno = save_errno; return TRUE; } } /* * -------------------------------------------------- * Convert string to 64 bit int. * * Return: * TRUE - OK * FALSE - Could not convert to int * -------------------------------------------------- */ boolean_t cli_str_to_int64(char *str, gtm_int64_t *dst) { gtm_int64_t result; int save_errno; save_errno = errno; errno = 0; result = STRTO64L(str, NULL, 10); if ((ERANGE == errno && (GTM_INT64_MIN == result || GTM_INT64_MAX == result)) || (0 == result && 0 != errno)) { /* out of range or other error */ *dst = 0; errno = save_errno; return FALSE; } else { *dst = result; errno = save_errno; return TRUE; } } /* * -------------------------------------------------- * Convert string to number. * * Return: * TRUE - OK * FALSE - Could not convert to number * -------------------------------------------------- */ boolean_t cli_str_to_num(char *str, int4 *dst) { long result; int save_errno, base; save_errno = errno; errno = 0; if (cli_is_dcm(str)) base = 10; else base = 16; result = STRTOL(str, NULL, base); if ( #if INT_MAX < LONG_MAX (INT_MIN > result || INT_MAX < result) || /* outside INT range */ #endif (ERANGE == errno && (LONG_MIN == result || LONG_MAX == result)) || (0 == result && 0 != errno)) { /* out of range or other error */ *dst = 0; errno = save_errno; return FALSE; } else { *dst = (int4)result; errno = save_errno; return TRUE; } } /* * -------------------------------------------------- * Convert string to 64 bit number. * * Return: * TRUE - OK * FALSE - Could not convert to number * -------------------------------------------------- */ boolean_t cli_str_to_num64(char *str, gtm_int64_t *dst) { gtm_int64_t result; int save_errno, base; save_errno = errno; errno = 0; if (cli_is_dcm(str)) base = 10; else base = 16; result = STRTO64L(str, NULL, base); if ((ERANGE == errno && (GTM_INT64_MIN == result || GTM_INT64_MAX == result)) || (0 == result && 0 != errno)) { /* out of range or other error */ *dst = 0; errno = save_errno; return FALSE; } else { *dst = result; errno = save_errno; return TRUE; } } int cli_parse_two_numbers(char *qual_name, const char delimiter, uint4 *first_num, uint4 *second_num) { /* Parse two unsigned base 10 numbers separated by the given delimiter. Eg. -LOG_INTERVAL=10,20 (on VMS, -LOG_INTERVAL="10,20"). * Both Unix and VMS accept the qualifier as a string. NOTE: On VMS, such qualifiers are quoted strings. * Both numbers are optional (eg. -LOG_INTERVAL=10, or -LOG_INTERVAL=",20", or -LOG_INTERVAL=,). * Return values: * CLI_2NUM_FIRST_SPECIFIED (binary 10), first number specified, second not * CLI_2NUM_SECOND_SPECIFIED (binary 01), first number not specified, second is * CLI_2NUM_BOTH_SPECIFIED (binary 11) (CLI_2NUM_FIRST_SPECIFIED | CLI_2NUM_SECOND_SPECIFIED), both specified * 0 (binary 00), error in parsing either number */ char *first_num_str, *second_num_str, *two_num_str_top, *num_endptr; char two_num_qual_str[128]; unsigned short two_num_qual_len; uint4 num; int retval = 0; two_num_qual_len = SIZEOF(two_num_qual_str); if (!cli_get_str(qual_name, two_num_qual_str, &two_num_qual_len)) { util_out_print("Error parsing !AZ qualifier", TRUE, qual_name); return 0; } #ifdef VMS /* DCL does not strip quotes included in the command line. However, the DEFAULT value (see mupip_cmd.cld) is stripped * of quotes. */ if ('"' == two_num_qual_str[0]) { assert('"' == two_num_qual_str[two_num_qual_len - 1]); /* end quote should exist */ first_num_str = &two_num_qual_str[1]; /* Skip begin quote */ two_num_qual_str[two_num_qual_len - 1] = '\0'; /* Zap end quote */ two_num_qual_len -= 2; /* Quotes gone */ } else #endif first_num_str = two_num_qual_str; for (second_num_str = first_num_str, two_num_str_top = first_num_str + two_num_qual_len; second_num_str < two_num_str_top && delimiter != *second_num_str; second_num_str++) ; if (delimiter == *second_num_str) *second_num_str++ = '\0'; if (*first_num_str != '\0') /* VMS issues EINVAL if strtoul is passed null string */ { errno = 0; num = (uint4)STRTOUL(first_num_str, &num_endptr, 10); if ((0 == num && (0 != errno || (num_endptr == first_num_str && *first_num_str != '\0'))) || (0 != errno && GTM64_ONLY(UINT_MAX == num) NON_GTM64_ONLY(ULONG_MAX == num))) { util_out_print("Error parsing or invalid parameter for !AZ", TRUE, qual_name); return 0; } *first_num = num; retval |= CLI_2NUM_FIRST_SPECIFIED; } /* else, first number not specified */ if (second_num_str < two_num_str_top && *second_num_str != '\0') { errno = 0; num = (uint4)STRTOUL(second_num_str, &num_endptr, 10); if ((0 == num && (0 != errno || (num_endptr == second_num_str && *second_num_str != '\0'))) || (0 != errno && GTM64_ONLY(UINT_MAX == num) NON_GTM64_ONLY(ULONG_MAX == num))) { util_out_print("Error parsing or invalid parameter for LOG_INTERVAL", TRUE); return 0; } *second_num = num; retval |= CLI_2NUM_SECOND_SPECIFIED; } /* else, second number not specified */ return retval; } fis-gtm-V6.0-003/sr_port/cliif.h0000644000032200000250000000465012201176154015275 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2005 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CLIIF_included #define CLIIF_included boolean_t cli_get_hex(char *entry, uint4 *dst); boolean_t cli_get_int(char *entry, int4 *dst); boolean_t cli_get_hex64(char *entry, gtm_uint64_t *dst); boolean_t cli_get_uint64(char *entry, gtm_uint64_t *dst); boolean_t cli_get_int64(char *entry, gtm_int64_t *dst); boolean_t cli_get_num(char *entry, int4 *dst); boolean_t cli_get_num64(char *entry, gtm_int64_t *dst); boolean_t cli_get_str(char *entry, char *dst, unsigned short *max_len); bool cli_get_str_ele(char *inbuff, char *dst, unsigned short *dst_len, boolean_t upper_case); boolean_t cli_get_time(char *entry, uint4 *dst); bool cli_get_value(char *entry, char val_buf[]); boolean_t cli_negated(char *entry); boolean_t cli_str_to_hex(char *str, uint4 *dst); boolean_t cli_str_to_hex64(char *str, gtm_uint64_t *dst); boolean_t cli_str_to_uint64(char *str, gtm_uint64_t *dst); boolean_t cli_str_to_int(char *str, int4 *dst); boolean_t cli_str_to_int64(char *str, gtm_int64_t *dst); boolean_t cli_str_to_num(char *str, int4 *dst); boolean_t cli_str_to_num64(char *str, gtm_int64_t *dst); int4 cli_t_f_n(char *entry); int4 cli_n_a_e(char *entry); int cli_get_string_token(int *eof); int cli_gettoken(int *eof); int cli_is_assign(char *p); int cli_is_dcm(char *p); int cli_is_hex(char *p); int cli_is_qualif(char *p); int cli_look_next_string_token(int *eof); int cli_look_next_token(int *eof); int cli_present(char *entry); /***type int added***/ void cli_str_setup(int length, char *addr); void cli_strupper(char *sp); int cli_parse_two_numbers(char *qual_name, const char delimiter, uint4 *first_num, uint4 *second_num); #ifdef __osf__ /* N.B. argv is passed in from main (in gtm.c) almost straight from the operating system. */ #pragma pointer_size (save) #pragma pointer_size (long) #endif void cli_lex_setup(int argc, char *argv[]); #ifdef __osf__ #pragma pointer_size (restore) #endif #define CLI_2NUM_FIRST_SPECIFIED 0x2 #define CLI_2NUM_SECOND_SPECIFIED 0x1 #endif /* CLIIF_included */ fis-gtm-V6.0-003/sr_port/cmd.c0000644000032200000250000002277712201176154014757 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "mdq.h" #include "opcode.h" #include "toktyp.h" #include "nametabtyp.h" #include "mmemory.h" #include "advancewindow.h" #include "cmd.h" #include "namelook.h" #include "error.h" #define VMS_OS 01 #define UNIX_OS 02 #define ALL_SYS (VMS_OS | UNIX_OS) #ifdef UNIX /* command validation is a function of the OS */ # define VALID_CMD(i) (cmd_data[i].os_syst & UNIX_OS) # ifdef __hppa # define TRIGGER_OS 0 # else # define TRIGGER_OS UNIX_OS # endif #elif defined VMS # define VALID_CMD(i) (cmd_data[i].os_syst & VMS_OS) # define TRIGGER_OS 0 #else # error UNSUPPORTED PLATFORM #endif GBLREF triple *curr_fetch_trip; error_def(ERR_CMD); error_def(ERR_CNOTONSYS); error_def(ERR_EXPR); error_def(ERR_INVCMD); error_def(ERR_PCONDEXPECTED); error_def(ERR_SPOREOL); int cmd(void) { /* All the commands are listed here. Two pairs of entries in general. * One for full command and one for short-hand notation. * For example, B and and BREAK. */ LITDEF nametabent cmd_names[] = { {1, "B"}, {5, "BREAK"} ,{1, "C"}, {5, "CLOSE"} ,{1, "D"}, {2, "DO"} ,{1, "E"}, {4, "ELSE"} ,{1, "F"}, {3, "FOR"} ,{1, "G"}, {4, "GOTO"} ,{1, "H"}, {4, "HALT"}, {4, "HANG"} ,{1, "I"}, {2, "IF"} ,{1, "J"}, {3, "JOB"} ,{1, "K"}, {4, "KILL"} ,{1, "L"}, {4, "LOCK"} ,{1, "M"}, {5, "MERGE"} ,{1, "N"}, {3, "NEW"} ,{1, "O"}, {4, "OPEN"} ,{1, "Q"}, {4, "QUIT"} ,{1, "R"}, {4, "READ"} ,{1, "S"}, {3, "SET"} ,{2, "TC"}, {7, "TCOMMIT"} ,{3, "TRE"}, {8, "TRESTART"} ,{3, "TRO"}, {8, "TROLLBAC*"} ,{2, "TS"}, {6, "TSTART"} ,{1, "U"}, {3, "USE"} ,{1, "V"}, {4, "VIEW"} ,{1, "W"}, {5, "WRITE"} ,{1, "X"}, {6, "XECUTE"} ,{2, "ZA"}, {8, "ZALLOCAT*"} ,{3, "ZAT"}, {7, "ZATTACH"} ,{2, "ZB"}, {6, "ZBREAK"} ,{2, "ZC"} ,{4, "ZCOM"} ,{8, "ZCONTINU*"} ,{8, "ZCOMPILE"} ,{2, "ZD"}, {8, "ZDEALLOC*"} ,{3, "ZED"}, {5, "ZEDIT"} ,{2, "ZG"}, {5, "ZGOTO"} ,{2, "ZH"} ,{5, "ZHALT"} ,{5, "ZHELP"} ,{7, "ZINVCMD"} ,{2, "ZK"}, {5, "ZKILL"} ,{2, "ZL"}, {5, "ZLINK"} ,{2, "ZM"}, {8, "ZMESSAGE"} ,{2, "ZP"}, {6, "ZPRINT"} ,{3, "ZSH"}, {5, "ZSHOW"} ,{3, "ZST"}, {5, "ZSTEP"} ,{3, "ZSY"}, {7, "ZSYSTEM"} ,{3, "ZTC"}, {8, "ZTCOMMIT"} # ifdef GTM_TRIGGER ,{3, "ZTR"}, {8, "ZTRIGGER"} # endif ,{3, "ZTS"}, {7, "ZTSTART"} ,{3, "ZWA"}, {6, "ZWATCH"} ,{3, "ZWI*"} ,{3, "ZWR"}, {6, "ZWRITE"} }; /* * cmd_index is an array indexed by the first alphabet of the command-name * cmd_index[0] and cmd_index[1] elements are for a command beginning with 'A'. * cmd_index[25] and cmd_index[26] element for a command beginning with 'Z'. * The cmd_index[n] holds the index of the first element in cmd_names * whose command-name begins with the same 'n'th letter of the alphabet (A is 1st letter). * Example: * Say, [B]REAK is the command. * 'B'-'A' = 1. and cmd_index[1] = 0 and cmd_index[1+1]=2. So it is in cmd_names[1] and cmd_names[2] * Say, [C]LOSE is the command. * 'C'-'A' = 2. and cmd_index[2] = 2 and cmd_index[2+1]=4. So it is in cmd_names[2] and cmd_names[4] * Say, [D]O is the command. * 'D'-'A' = 3. and cmd_index[3] = 4 and cmd_index[3+1]=6. So it is in cmd_names[4] and cmd_names[6] * Say, [I]F is the command. * 'I'-'A' = 8. and cmd_index[8] = 15 and cmd_index[8+1]=17. So it is in cmd_names[15] and cmd_names[17] * Say, [M]ERGE the command. * 'M'-'A' = 12. and cmd_index[12] = 23 and cmd_index[12+1]=25. So it is in cmd_names[23] and cmd_names[25] */ LITDEF unsigned char cmd_index[27] = { 0, 0, 2, 4, 6, 8, 10, 12, 15, 17, 19, 21, 23 ,25, 27, 29, 29, 31, 33, 35, 43, 45, 47, 49 ,51, 51, GTMTRIG_ONLY(96) NON_GTMTRIG_ONLY(94) }; LITDEF struct { int (*fcn)(); unsigned int eol_ok:1; unsigned int pcnd_ok:1; char os_syst; } cmd_data[] = { {m_break, 1, 1, ALL_SYS}, {m_break, 1, 1, ALL_SYS} ,{m_close, 0, 1, ALL_SYS}, {m_close, 0, 1, ALL_SYS} ,{m_do, 1, 1, ALL_SYS}, {m_do, 1, 1, ALL_SYS} ,{m_else, 1, 0, ALL_SYS}, {m_else, 1, 0, ALL_SYS} ,{m_for, 0, 0, ALL_SYS}, {m_for, 0, 0, ALL_SYS} ,{m_goto, 0, 1, ALL_SYS}, {m_goto, 0, 1, ALL_SYS} ,{m_hcmd, 1, 1, ALL_SYS} ,{m_halt, 1, 1, ALL_SYS} ,{m_hang, 0, 1, ALL_SYS} ,{m_if, 1, 0, ALL_SYS}, {m_if, 1, 0, ALL_SYS} ,{m_job, 0, 1, ALL_SYS}, {m_job, 0, 1, ALL_SYS} ,{m_kill, 1, 1, ALL_SYS}, {m_kill, 1, 1, ALL_SYS} ,{m_lock, 1, 1, ALL_SYS}, {m_lock, 1, 1, ALL_SYS} ,{m_merge, 0, 1, ALL_SYS}, {m_merge, 0, 1, ALL_SYS} ,{m_new, 1, 1, ALL_SYS}, {m_new, 1, 1, ALL_SYS} ,{m_open, 0, 1, ALL_SYS}, {m_open, 0, 1, ALL_SYS} ,{m_quit, 1, 1, ALL_SYS}, {m_quit, 1, 1, ALL_SYS} ,{m_read, 0, 1, ALL_SYS}, {m_read, 0, 1, ALL_SYS} ,{m_set, 0, 1, ALL_SYS}, {m_set, 0, 1, ALL_SYS} ,{m_tcommit, 1, 1, ALL_SYS}, {m_tcommit, 1, 1, ALL_SYS} ,{m_trestart, 1, 1, ALL_SYS}, {m_trestart, 1, 1, ALL_SYS} ,{m_trollback, 1, 1, ALL_SYS}, {m_trollback, 1, 1, ALL_SYS} ,{m_tstart, 1, 1, ALL_SYS}, {m_tstart, 1, 1, ALL_SYS} ,{m_use, 0, 1, ALL_SYS}, {m_use, 0, 1, ALL_SYS} ,{m_view, 0, 1, ALL_SYS}, {m_view, 0, 1, ALL_SYS} ,{m_write, 0, 1, ALL_SYS}, {m_write, 0, 1, ALL_SYS} ,{m_xecute, 0, 1, ALL_SYS}, {m_xecute, 0, 1, ALL_SYS} ,{m_zallocate, 0, 1, ALL_SYS}, {m_zallocate, 0, 1, ALL_SYS} ,{m_zattach, 1, 1, ALL_SYS}, {m_zattach, 1, 1, ALL_SYS} ,{m_zbreak, 0, 1, ALL_SYS}, {m_zbreak, 0, 1, ALL_SYS} ,{m_zcontinue, 1, 1, ALL_SYS} ,{m_zcompile, 0, 1, ALL_SYS} ,{m_zcontinue, 1, 1, ALL_SYS} ,{m_zcompile, 0, 1, ALL_SYS} ,{m_zdeallocate, 1, 1, ALL_SYS}, {m_zdeallocate, 1, 1, ALL_SYS} ,{m_zedit, 1, 1, ALL_SYS}, {m_zedit, 1, 1, ALL_SYS} ,{m_zgoto, 1, 1, ALL_SYS}, {m_zgoto, 1, 1, ALL_SYS} ,{m_zhelp, 1, 1, ALL_SYS} ,{m_zhalt, 1, 1, ALL_SYS} ,{m_zhelp, 1, 1, ALL_SYS} ,{m_zinvcmd, 1, 1, ALL_SYS} ,{m_zwithdraw, 0, 1, ALL_SYS}, {m_zwithdraw, 0, 1, ALL_SYS} ,{m_zlink, 1, 1, ALL_SYS}, {m_zlink, 1, 1, ALL_SYS} ,{m_zmessage, 0, 1, ALL_SYS}, {m_zmessage, 0, 1, ALL_SYS} ,{m_zprint, 1, 1, ALL_SYS}, {m_zprint, 1, 1, ALL_SYS} ,{m_zshow, 1, 1, ALL_SYS}, {m_zshow, 1, 1, ALL_SYS} ,{m_zstep, 1, 1, ALL_SYS}, {m_zstep, 1, 1, ALL_SYS} ,{m_zsystem, 1, 1, ALL_SYS}, {m_zsystem, 1, 1, ALL_SYS} ,{m_ztcommit, 1, 1, ALL_SYS}, {m_ztcommit, 1, 1, ALL_SYS} # ifdef GTM_TRIGGER ,{m_ztrigger, 0, 1, TRIGGER_OS}, {m_ztrigger, 0, 1, TRIGGER_OS} # endif ,{m_ztstart, 1, 1, ALL_SYS}, {m_ztstart, 1, 1, ALL_SYS} ,{m_zwatch, 0, 1, 0}, {m_zwatch, 0, 1, 0} ,{m_zwithdraw, 0, 1, ALL_SYS} ,{m_zwrite, 1, 1, ALL_SYS}, {m_zwrite, 1, 1, ALL_SYS} }; triple *temp_expr_start, *ref0, *ref1, *fetch0, *triptr; char *c; int rval, x; oprtype *cr; boolean_t shifting; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert((SIZEOF(cmd_names) / SIZEOF(nametabent)) == cmd_index[26]); while (TREF(expr_depth)) DECREMENT_EXPR_DEPTH; /* in case of prior errors */ (TREF(side_effect_base))[0] = FALSE; TREF(temp_subs) = FALSE; CHKTCHAIN(TREF(curtchain)); TREF(pos_in_chain) = *TREF(curtchain); if (TREF(window_token) != TK_IDENT) { stx_error(ERR_CMD); return FALSE; } assert(0 != (TREF(window_ident)).len); c = (TREF(window_ident)).addr; if ('%' == *c) { stx_error(ERR_CMD); return FALSE; } if (0 > (x = namelook(cmd_index, cmd_names, c, (TREF(window_ident)).len))) { if ((TK_COLON != TREF(director_token)) || (0 > (x = namelook(cmd_index, cmd_names, "ZINVCMD", 7)))) { /* the 2nd term of the above if should perform the assignment, but never be true - we're just paranoid */ stx_error(MAKE_MSG_TYPE(ERR_INVCMD, ERROR)); /* force INVCMD to an error so stx_error sees it as hard */ return FALSE; } stx_error(ERR_INVCMD); /* the warning form so stx_error treats it as provisional */ } if (!VALID_CMD(x) ) { stx_error(ERR_CNOTONSYS); return FALSE; } advancewindow(); if ((TK_COLON != TREF(window_token)) || !cmd_data[x].pcnd_ok) { assert((m_zinvcmd != cmd_data[x].fcn)); cr = NULL; shifting = FALSE; } else { advancewindow(); cr = (oprtype *)mcalloc(SIZEOF(oprtype)); if (!bool_expr(FALSE, cr)) { stx_error(ERR_PCONDEXPECTED); return FALSE; } if (shifting = ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode))) { /* NOTE - assignent above */ temp_expr_start = TREF(expr_start); triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(temp_expr_start); } } if (TK_SPACE == TREF(window_token)) advancewindow(); else if ((TK_EOL != TREF(window_token)) || !cmd_data[x].eol_ok) { stx_error(ERR_SPOREOL); return FALSE; } fetch0 = curr_fetch_trip; for (;;) { if ((EXPR_FAIL == (rval = (*cmd_data[x].fcn)())) || (TK_COMMA != TREF(window_token))) /* NOTE assignment */ break; else { advancewindow(); if ((TK_SPACE == TREF(window_token)) || (TK_EOL == TREF(window_token))) { stx_error(ERR_EXPR); return FALSE; } } } if ((EXPR_FAIL != rval) && cr) { if (fetch0 != curr_fetch_trip) { assert(OC_FETCH == curr_fetch_trip->opcode); *cr = put_tjmp((TREF(curtchain))->exorder.bl); } else { if (shifting) { ref0 = newtriple(OC_JMP); ref1 = newtriple(OC_GVRECTARG); ref1->operand[0] = put_tref(temp_expr_start); *cr = put_tjmp(ref1); tnxtarg(&ref0->operand[0]); } else tnxtarg(cr); } } return rval; } fis-gtm-V6.0-003/sr_port/cmd.h0000644000032200000250000000300512201176154014743 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CMD_INCLUDED #define CMD_INCLUDED int cmd(void); int m_break(void); int m_close(void); int m_do(void); int m_else(void); int m_xecute(void); int m_for(void); int m_goto(void); int m_halt(void); int m_hang(void); int m_hcmd(void); int m_if(void); int m_job(void); int m_kill(void); int m_lock(void); int m_merge(void); int m_new(void); int m_open(void); int m_quit(void); int m_read(void); int m_set(void); int m_tcommit(void); int m_trestart(void); int m_trollback(void); int m_tstart(void); int m_use(void); int m_view(void); int m_write(void); int m_xecute(void); int m_zallocate(void); int m_zattach(void); int m_zbreak(void); int m_zcompile(void); int m_zcontinue(void); int m_zdeallocate(void); int m_zedit(void); int m_zgoto(void); int m_zhalt(void); int m_zhelp(void); int m_zinvcmd(void); int m_zlink(void); int m_zmessage(void); int m_zprint(void); int m_zshow(void); int m_zstep(void); int m_zsystem(void); int m_ztcommit(void); #ifdef GTM_TRIGGER int m_ztrigger(void); #endif int m_ztstart(void); int m_zwatch(void); int m_zwithdraw(void); int m_zwrite(void); #endif fis-gtm-V6.0-003/sr_port/cmd_qlf.h0000644000032200000250000000467512201176154015623 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CMD_QLF_H_INCLUDED #define CMD_QLF_H_INCLUDED typedef struct { uint4 qlf; mval object_file; mval list_file; mval ceprep_file; mval rtnname; } command_qualifier; typedef struct { unsigned short page; /* page number */ unsigned short list_line; /* listing line number */ unsigned short lines_per_page; unsigned short space; /* spacing */ } list_params; /* command qualifer bit masks */ #define CQ_LIST (1 << 0) /* 0x0001 */ #define CQ_MACHINE_CODE (1 << 1) /* 0x0002 */ #define CQ_CROSS_REFERENCE (1 << 2) /* 0x0004 */ #define CQ_DEBUG (1 << 3) /* 0x0008 */ #define CQ_OBJECT (1 << 4) /* 0x0010 */ #define CQ_WARNINGS (1 << 5) /* 0x0020 */ #define CQ_IGNORE (1 << 6) /* 0x0040 */ #define CQ_LOWER_LABELS (1 << 7) /* 0x0080 */ #define CQ_LINE_ENTRY (1 << 8) /* 0x0100 */ #define CQ_CE_PREPROCESS (1 << 9) /* 0x0200 */ #define CQ_INLINE_LITERALS (1 << 10) /* 0x0400 */ #define CQ_ALIGN_STRINGS (1 << 11) /* 0x0800 */ #define CQ_UTF8 (1 << 12) /* 0x1000 */ #define CQ_NAMEOFRTN (1 << 13) /* 0x2000 */ #define CQ_DYNAMIC_LITERALS (1 << 14) /* 0x4000 -- Set via environmental variable gtm_dynamic_literals (gtm_logicals.h) */ /* TODO: add CQ_ALIGN_STRINGS to the default list below when alignment is supported */ #define CQ_DEFAULT (CQ_WARNINGS | CQ_OBJECT | CQ_IGNORE | CQ_LOWER_LABELS | CQ_LINE_ENTRY | CQ_INLINE_LITERALS) #define LISTTAB 10 #define PG_WID 132 #define INIT_CMD_QLF_STRINGS(CMD_QLF, OBJ_FILE, LIST_FILE, CEPREP_FILE, SIZE) \ { \ CMD_QLF.object_file.str.addr = OBJ_FILE; \ CMD_QLF.object_file.str.len = SIZE; \ CMD_QLF.list_file.str.addr = LIST_FILE; \ CMD_QLF.list_file.str.len = SIZE; \ CMD_QLF.ceprep_file.str.addr = CEPREP_FILE; \ CMD_QLF.ceprep_file.str.len = SIZE; \ } typedef struct src_line_type { struct { struct src_line_type *fl,*bl; } que; char *addr; int4 line; } src_line_struct; void zl_cmd_qlf(mstr *quals, command_qualifier *qualif); void get_cmd_qlf(command_qualifier *qualif); #endif /* CMD_QLF_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/cmerrors.msg0000644000032200000250000000162412201176154016400 0ustar librarygtc!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! ! Copyright 2001 Sanchez Computer Associates, Inc. ! ! ! ! This source code contains the intellectual property ! ! of its copyright holder(s), and is made available ! ! under a license. If you do not know the terms of ! ! the license, please stop and do not read further. ! ! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .FACILITY GTCM,249/PREFIX=CMERR_ .TITLE CMERRORS Error Messages for GTCM, VAX/VMS EDITION INVPROT /error/fao=0 REGNTFND /error/fao=0 CMINTQUE /fatal/fao=0 INVINTMSG /error/fao=0 CMEXCDASTLM /error/fao=0 CMSYSSRV /error/fao=0 .end fis-gtm-V6.0-003/sr_port/cmi.h0000644000032200000250000000113512201176154014752 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CMI_INCLUDED #define CMI__INCLUDED cmi_status_t cmi_read(struct CLB *lnk); cmi_status_t cmi_write(struct CLB *lnk); #endif /* CMI_INCLUDED */ fis-gtm-V6.0-003/sr_port/cmidef.h0000644000032200000250000000300412201176154015426 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2004 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CMIPORT_H_INCLUDED #define CMIPORT_H_INCLUDED #define CM_MSG_BUF_SIZE 512 /* Message buffer size */ #define CM_MAX_BUF_LEN ((unsigned short)0xFFFF) /* lnk->cbl is of type unsigned short, hence 64K-1 is the max currently */ /* * Connection States */ #define CM_CLB_IDLE 0 #define CM_CLB_READ 1 #define CM_CLB_WRITE 2 #define CM_CLB_CONNECT 3 #define CM_CLB_DISCONNECT 4 #define CM_CLB_WRITE_URG 5 #define CM_CLB_READ_URG 6 /* get platform specific stuff */ #include "cmidefsp.h" cmi_status_t cmi_read(struct CLB *c); cmi_status_t cmi_write(struct CLB *c); cmi_status_t cmi_open(struct CLB *c); cmi_status_t cmi_close(struct CLB *c); struct CLB *cmu_getclb(cmi_descriptor *node, cmi_descriptor *task); struct NTD *cmu_ntdroot(void); #ifndef RELQUE2PTR #define RELQUE2PTR(X) (((unsigned char *) &(X)) + ((int4) (X))) #endif #define PTR2RELQUE(DESTINATION,TARGET) (DESTINATION = (((unsigned char *) &(TARGET)) - ((unsigned char *) &(DESTINATION)))) #define QUEENT2CLB(QP, QH) (struct CLB *)((char *)(QP) - (char *)&(((struct CLB *)(0))->QH)) #endif /* CMI_INCLUDED */ fis-gtm-V6.0-003/sr_port/cmmdef.h0000644000032200000250000002404312201176154015440 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #define ZAREQUEST_SENT 16 #define LREQUEST_SENT 8 #define REQUEST_PENDING 4 #define REMOTE_ZALLOCATES 2 #define REMOTE_LOCKS 1 #define REMOTE_CLR_MASK (ZAREQUEST_SENT + LREQUEST_SENT + REMOTE_ZALLOCATES + REMOTE_LOCKS) #define CM_BUFFER_OVERHEAD 20 #define CM_BLKPASS 40 #define CMM_PROTOCOL_TYPE "GCM" #define S_PROTOCOL "VAXVMSGTM023GCM010 " #define S_HDRSIZE 1 #define S_PROTSIZE 33 #define S_REGINSIZE 6 #define S_LAFLAGSIZE 1 #define S_SUBLISTSIZE 1 #define CM_MINBUFSIZE 512 + CM_BUFFER_OVERHEAD #define CMLCK_REQUEUE 0 #define CM_LOCKS 0 #define CM_ZALLOCATES 0x80 #define CM_NOLKCANCEL 256 #define CM_WRITE 1 #define CM_READ 0 #define CM_NOOP 2 #define CMMS_E_ERROR 1 /* [0x01] */ #define CMMS_L_LKCANALL 2 /* [0x02] */ #define CMMS_L_LKCANCEL 3 /* [0x03] */ #define CMMS_L_LKDELETE 4 /* [0x04] */ #define CMMS_L_LKREQIMMED 5 /* [0x05] */ #define CMMS_L_LKREQNODE 6 /* [0x06] */ #define CMMS_L_LKREQUEST 7 /* [0x07] */ #define CMMS_L_LKRESUME 8 /* [0x08] */ #define CMMS_L_LKACQUIRE 9 /* [0x09] */ #define CMMS_L_LKSUSPEND 10 /* [0x0A] */ #define CMMS_M_LKABORT 11 /* [0x0B] */ #define CMMS_M_LKBLOCKED 12 /* [0x0C] */ #define CMMS_M_LKGRANTED 13 /* [0x0D] */ #define CMMS_M_LKDELETED 14 /* [0x0E] */ #define CMMS_M_LKSUSPENDED 15 /* [0x0F] */ #define CMMS_Q_DATA 16 /* [0x10] */ #define CMMS_Q_GET 17 /* [0x11] */ #define CMMS_Q_KILL 18 /* [0x12] */ #define CMMS_Q_ORDER 19 /* [0x13] */ #define CMMS_Q_PREV 20 /* [0x14] */ #define CMMS_Q_PUT 21 /* [0x15] */ #define CMMS_Q_QUERY 22 /* [0x16] */ #define CMMS_Q_ZWITHDRAW 23 /* [0x17] */ #define CMMS_R_DATA 24 /* [0x18] */ #define CMMS_R_GET 25 /* [0x19] */ #define CMMS_R_KILL 26 /* [0x1A] */ #define CMMS_R_ORDER 27 /* [0x1B] */ #define CMMS_R_PREV 28 /* [0x1C] */ #define CMMS_R_PUT 29 /* [0x1D] */ #define CMMS_R_QUERY 30 /* [0x1E] */ #define CMMS_R_ZWITHDRAW 31 /* [0x1F] */ #define CMMS_R_UNDEF 32 /* [0x20] */ #define CMMS_S_INITPROC 33 /* [0x21] */ #define CMMS_S_INITREG 34 /* [0x22] */ #define CMMS_S_TERMINATE 35 /* [0x23] */ #define CMMS_S_INTERRUPT 36 /* [0x24] */ #define CMMS_T_INITPROC 37 /* [0x25] */ #define CMMS_T_REGNUM 38 /* [0x26] */ #define CMMS_X_INQPROC 39 /* [0x27] */ #define CMMS_X_INQPRRG 40 /* [0x28] */ #define CMMS_X_INQREG 41 /* [0x29] */ #define CMMS_Y_STATPROCREC 42 /* [0x2A] */ #define CMMS_Y_STATPRRGREC 43 /* [0x2B] */ #define CMMS_Y_STATREGREC 44 /* [0x2C] */ #define CMMS_U_LKEDELETE 45 /* [0x2D] */ #define CMMS_U_LKESHOW 46 /* [0x2E] */ #define CMMS_V_LKESHOW 47 /* [0x2F] */ #define CMMS_E_TERMINATE 48 /* [0x30] */ #define CMMS_B_BUFRESIZE 49 /* [0x31] */ #define CMMS_B_BUFFLUSH 50 /* [0x32] */ #define CMMS_C_BUFRESIZE 51 /* [0x33] */ #define CMMS_C_BUFFLUSH 52 /* [0x34] */ #define CMMS_Q_INCREMENT 53 /* [0x35] */ /* Opcode for message type sent from client (to server) */ #define CMMS_R_INCREMENT 54 /* [0x36] */ /* Opcode for message type received by client (from server) */ #define CMM_QUERYGET_MIN_LEVEL "200" /* $query works as queryget only from version "V200" onwards */ #define CMM_INCREMENT_MIN_LEVEL "210" /* $INCREMENT works only from version "V210" onwards */ #define CMM_STDNULLCOLL_MIN_LEVEL "210" /* Standard null collation works only from version "V210" onwards */ #define CMM_LONGNAMES_MIN_LEVEL "210" /* long name works only from protocol "V210" onwards */ typedef struct cm_region_list_struct { que_ent regque; struct cm_region_list_struct *next; unsigned char regnum; unsigned char oper; unsigned short lks_this_cmd; bool reqnode; char filler[3]; struct cm_region_head_struct *reghead; struct cs_struct *cs; struct mlk_pvtblk_struct *blkd; struct mlk_pvtblk_struct *lockdata; uint4 pini_addr; } cm_region_list; typedef struct cs_struct { que_ent qent; cm_region_list *region_root; cm_region_list *current_region; struct CLB *clb_ptr; unsigned char state; unsigned char new_msg; unsigned char maxregnum; bool waiting_in_queue; #ifdef UNIX struct timeval connect; /* Debugging tool -- time connection was established */ time_t lastact; /* Debugging tool -- time of last server action */ #else uint4 connect[2]; /* Debugging tool -- time connection was established */ uint4 lastact[2]; /* Debugging tool -- time of last server action */ #endif uint4 stats; unsigned short procnum; unsigned short transnum; unsigned short lk_cancel; unsigned short last_cancelled; /* hold transnum of last cancelled lock request */ struct /* hold info from interrupt cancel msg */ { /* laflag can be 0, x40, x80 */ unsigned char laflag; /* + 1 if valid */ unsigned char transnum; /* for lk_cancel */ } int_cancel; struct jnl_process_vector_struct *pvec; boolean_t query_is_queryget; /* based on client/server protocol levels, query == queryget */ boolean_t err_compat; /* based on client/server protocol levels (and platform type), * rts_error mechanism b/n client and server might be different */ boolean_t cli_supp_allowexisting_stdnullcoll;/* decided based on client's protocol levels */ boolean_t client_supports_long_names; /* based on client's levels */ cm_region_list *region_array[256]; /* [UCHAR_MAX + 1] speed up gtcm_find_region */ } connection_struct; typedef struct cm_region_head_struct { relque head; struct cm_region_head_struct *next; struct cm_region_head_struct *last; connection_struct *connect_ptr; struct gd_region_struct *reg; uint4 refcnt; uint4 wakeup; hash_table_mname *reg_hash; } cm_region_head; typedef struct cm_lk_response_struct { struct cm_lk_response_struct *next; struct CLB *response; } cm_lk_response; typedef struct link_info_struct { unsigned char neterr; unsigned char lck_info; unsigned char lnk_active; char filler; struct mlk_pvtblk_struct *netlocks; unsigned short procnum; unsigned short buffered_count; unsigned short buffer_size; unsigned short buffer_used; unsigned char *buffer; boolean_t convert_byteorder; boolean_t query_is_queryget; /* based on client/server protocol levels, query == queryget */ boolean_t err_compat; /* based on client/server protocol levels (and platform type), * rts_error mechanism b/n client and server might be different */ cm_lk_response lk_response; boolean_t server_supports_dollar_incr; /* decided based on server protocol levels */ boolean_t server_supports_std_null_coll; /* decided based on server protocol levels */ boolean_t server_supports_long_names; /* decided based on server protocol levels */ } link_info; typedef struct { char code; char rnum; bool all; bool interactive; int4 pid; char nodelength; char node[32]; } clear_request; typedef struct { char code; char filler[3]; int4 status; int4 locknamelength; char lockname[256]; } clear_reply; typedef struct { char code; bool clear; } clear_confirm; typedef struct { char code; char rnum; bool all; bool wait; int4 pid; char nodelength; char node[32]; } show_request; typedef struct { char code; char line[256]; } show_reply; #define CM_CPU_OFFSET 0 #define CM_OS_OFFSET 3 #define CM_IMPLEMENTATION_OFFSET 6 #define CM_VERSION_OFFSET 9 #define CM_TYPE_OFFSET 12 #define CM_LEVEL_OFFSET 15 #define CM_ENDIAN_OFFSET 18 #define CM_FILLER_SIZE 14 typedef struct { char msg[S_PROTSIZE]; } protocol_msg; #define CM_PUT_USHORT(PTR, USVAL, CONVFLAG) \ { \ if (CONVFLAG) \ { \ unsigned short val = GTM_BYTESWAP_16(USVAL); \ PUT_USHORT(PTR, val); \ } \ else \ PUT_USHORT(PTR, USVAL); \ } #define CM_PUT_SHORT(PTR, SVAL, CONVFLAG) \ { \ if (CONVFLAG) \ { \ short val = GTM_BYTESWAP_16(SVAL); \ PUT_SHORT(PTR, val); \ } \ else \ PUT_SHORT(PTR, SVAL); \ } #define CM_PUT_ULONG(PTR, ULVAL, CONVFLAG) \ { \ if (CONVFLAG) \ { \ uint4 val = GTM_BYTESWAP_32(ULVAL); \ PUT_ULONG(PTR, val); \ } \ else \ PUT_ULONG(PTR, ULVAL); \ } #define CM_PUT_LONG(PTR, LVAL, CONVFLAG) \ { \ if (CONVFLAG) \ { \ int4 val = GTM_BYTESWAP_32(LVAL); \ PUT_LONG(PTR, val); \ } \ else \ PUT_LONG(PTR, LVAL); \ } #define CM_GET_USHORT(USVAR, PTR, CONVFLAG) \ { \ if (CONVFLAG) \ { \ unsigned short val; \ GET_USHORT(val, (PTR)); \ USVAR = GTM_BYTESWAP_16(val); \ } \ else \ GET_USHORT((USVAR), (PTR)); \ } #define CM_GET_SHORT(SVAR, PTR, CONVFLAG) \ { \ if (CONVFLAG) \ { \ short val; \ GET_SHORT(val, (PTR)); \ SVAR = GTM_BYTESWAP_16(val); \ } \ else \ GET_SHORT((SVAR), (PTR)); \ } #define CM_GET_ULONG(ULVAR, PTR, CONVFLAG) \ { \ if (CONVFLAG) \ { \ uint4 val; \ GET_ULONG(val, (PTR)); \ ULVAR = GTM_BYTESWAP_32(val); \ } \ else \ GET_ULONG((ULVAR), (PTR)); \ } #define CM_GET_LONG(LVAR, PTR, CONVFLAG) \ { \ if (CONVFLAG) \ { \ int4 val; \ GET_LONG(val, (PTR)); \ LVAR = GTM_BYTESWAP_32(val); \ } \ else \ GET_LONG((LVAR), (PTR)); \ } #define CM_GET_GVCURRKEY(PTR, LEN) \ /* fetch gvcurrkey fields from message buffer; side effect : PTR is modified \ * to point to the byte after gv_currkey */ \ /* if we want to keep gv_currkey->top, why bother changing it; vinu Jul 17, 2000 */ \ /* top = gv_currkey->top; */ \ /* GET_USHORT(gv_currkey->top, ptr); */ \ (PTR) += SIZEOF(unsigned short); \ GET_USHORT(gv_currkey->end, (PTR)); \ (PTR) += SIZEOF(unsigned short); \ GET_USHORT(gv_currkey->prev, (PTR)); \ (PTR) += SIZEOF(unsigned short); \ memcpy(gv_currkey->base, (PTR), (LEN) - 6); \ (PTR) += ((LEN) - 6); \ /* gv_currkey->top = top; */ fis-gtm-V6.0-003/sr_port/code_address_type.h0000644000032200000250000000203012201176154017655 0ustar librarygtc/**************************************************************** * * * Copyright 2007, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CODE_ADDRESS_TYPE_INCLUDE #define CODE_ADDRESS_TYPE_INCLUDE #include "mdef.h" #ifdef __ia64 GBLREF int function_type(char*); #endif /* __ia64 */ #define GTM_C_RTN 1 #define GTM_ASM_RTN 2 #ifndef __ia64 #define CODE_ADDRESS_TYPE(func) &func #else /* __ia64 */ #define CODE_ADDRESS_TYPE(func) CODE_ADDRESS(func) #endif /* __ia64 */ #endif /* CODE_ADDRESS_TYPE_INCLUDE */ fis-gtm-V6.0-003/sr_port/code_gen.c0000644000032200000250000000604612201176176015752 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "mdq.h" #include "cgp.h" #include "cmd_qlf.h" #include #include "obj_file.h" #include "list_file.h" #include #include "dumptable.h" LITREF octabstruct oc_tab[]; /* op-code table */ GBLREF triple t_orig; /* head of triples */ GBLREF char cg_phase; /* code generation phase */ GBLREF int4 curr_addr; /* current address */ GBLREF src_line_struct src_head; GBLREF short source_column,source_line; GBLREF int4 pending_errtriplecode; /* if non-zero contains the error code to invoke ins_errtriple with */ void code_gen(void) { int4 old_line, pad_len; src_line_struct *sl; triple *ct; /* current triple */ DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (CGP_ASSEMBLY == cg_phase) { curr_addr = t_orig.exorder.fl->rtaddr; old_line = -1; } assert(0 == pending_errtriplecode); /* we should never have a pending ins_errtriple at this point */ assert(&t_orig == TREF(curtchain)); /* curtchain should still be pointing to what it was originally */ DEBUG_ONLY(chktchain(&t_orig)); /* if this assert fails, then recompile with DEBUG_TRIPLES to catch the issue sooner */ dqloop(&t_orig, exorder, ct) { if (CGP_APPROX_ADDR == cg_phase) ct->rtaddr = curr_addr; else if (CGP_ASSEMBLY == cg_phase) { if (ct->src.line != old_line) { list_line(""); for (sl = src_head.que.bl; sl->line <= ct->src.line && sl != &src_head; ) { list_line_number(); dqdel(sl,que); list_line(sl->addr); sl = src_head.que.bl; } old_line = ct->src.line; } } source_line = ct->src.line; source_column = ct->src.column; if (!(oc_tab[ct->opcode].octype & OCT_CGSKIP)) trip_gen(ct); }/* dqloop */ #ifdef _AIX emit_epilog(); #endif /* The code section needs to be padded so the next section (variable name table) can be optimally aligned for use by the hashing functions (ex use 8 byte loads on alpha requires 8 byte alignment). We compute the pad length and record it and add it to the code size. Later when the code is optimized, the pad length will be subtracted back out, rechecked for padding and an appropriate pad length recomputed. */ if (CGP_APPROX_ADDR == cg_phase) TREF(codegen_padlen) = PADLEN(curr_addr, SECTION_ALIGN_BOUNDARY); /* Length to pad to align next section */ if (TREF(codegen_padlen)) { assert(STR_LIT_LEN(PADCHARS) >= TREF(codegen_padlen)); if (CGP_MACHINE == cg_phase) emit_immed(PADCHARS, TREF(codegen_padlen)); /* Pad out with extraneous info */ else curr_addr += TREF(codegen_padlen); } if (CGP_ASSEMBLY == cg_phase) dumptable(); }/* code_gen */ fis-gtm-V6.0-003/sr_port/coerce.c0000644000032200000250000000432612201176154015442 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "mdq.h" #include "mvalconv.h" #include "hashtab_str.h" GBLREF hash_table_str *complits_hashtab; LITREF octabstruct oc_tab[]; void coerce(oprtype *a,unsigned short new_type) { mliteral *lit; opctype conv, old_op; triple *ref, *coerc; stringkey litkey; ht_ent_str *litent; boolean_t litdltd; assert (new_type == OCT_MVAL || new_type == OCT_MINT || new_type == OCT_BOOL); assert (a->oprclass == TRIP_REF); ref = a->oprval.tref; old_op = ref->opcode; if (new_type & oc_tab[old_op].octype) return; if (old_op == OC_COMVAL || old_op == OC_COMINT) { dqdel(ref,exorder); ref = ref->operand[0].oprval.tref; old_op = ref->opcode; if (new_type & oc_tab[old_op].octype) return; } else if (OC_LIT == old_op && OCT_MINT == new_type) { lit = ref->operand[0].oprval.mlit; if (!(++lit->rt_addr)) { /* completely removing this otherwise unused literal as needs to be an ILIT instead */ if (NULL != complits_hashtab && NULL != complits_hashtab->base) { /* Deleted entry is in the hash table .. remove it */ litkey.str = lit->v.str; COMPUTE_HASH_STR(&litkey); DEBUG_ONLY(litent = lookup_hashtab_str(complits_hashtab, &litkey)); assert(litent); /* Literal is there .. better be found */ assert(litent->value == (void *)lit); litdltd = delete_hashtab_str(complits_hashtab, &litkey); assert(litdltd); } dqdel(lit, que); } ref->opcode = OC_ILIT; ref->operand[0].oprclass = ILIT_REF; ref->operand[0].oprval.ilit = MV_FORCE_INTD(&(lit->v)); return; } if (new_type == OCT_BOOL) conv = OC_COBOOL; else if (new_type == OCT_MINT) conv = OC_COMINT; else conv = OC_COMVAL; coerc = newtriple(conv); coerc->operand[0] = put_tref(ref); *a = put_tref(coerc); return; } fis-gtm-V6.0-003/sr_port/collseq.c0000644000032200000250000000416712201176154015647 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "io.h" #include "iosp.h" #include "collseq.h" #include "error.h" #include "trans_log_name.h" #include "gtm_logicals.h" int find_local_colltype(void) { int lct, status; char transbuf[MAX_TRANS_NAME_LEN]; mstr lognam, transnam; lognam.len = SIZEOF(LCT_PREFIX) - 1; lognam.addr = LCT_PREFIX; status = TRANS_LOG_NAME(&lognam, &transnam, transbuf, SIZEOF(transbuf), do_sendmsg_on_log2long); if (SS_NORMAL != status) return 0; lct = asc2i((uchar_ptr_t)transnam.addr, transnam.len); return lct >= MIN_COLLTYPE && lct <= MAX_COLLTYPE ? lct : 0; } collseq *ready_collseq(int act) { unsigned char filespec[SIZEOF(CT_PREFIX) + 4]; /* '4' to hold the chars in the max allowable * collation sequence (255) plus the terminating null */ unsigned char *fsp; collseq temp_csp, *csp; mstr fspec; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; /* Validate the alternative collating type (act) */ if (!(act >= 1 && act <= MAX_COLLTYPE)) return (collseq*)NULL; /* Search for record of the collating type already being mapped in. */ for (csp = TREF(collseq_list); csp != NULL && act != csp->act; csp = csp->flink) ; if (NULL == csp) { /* If not found, create a structure and attempt to map in the collating support package.*/ temp_csp.act = act; temp_csp.flink = TREF(collseq_list); memcpy(filespec, CT_PREFIX, SIZEOF(CT_PREFIX)); fsp = i2asc(&filespec[SIZEOF(CT_PREFIX) - 1], act); *fsp = 0; fspec.len = INTCAST(fsp - filespec); fspec.addr = (char *)filespec; if (!map_collseq(&fspec, &temp_csp)) return NULL; csp = (collseq *) malloc(SIZEOF(collseq)); *csp = temp_csp; TREF(collseq_list) = csp; } return csp; } fis-gtm-V6.0-003/sr_port/collseq.h0000644000032200000250000000651512201176154015653 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef COLLSEQ_H_INCLUDED #define COLLSEQ_H_INCLUDED #include "min_max.h" #define MAX_COLLTYPE 255 #define MIN_COLLTYPE 0 #define XFORM 0 #define XBACK 1 #define ALLOC_XFORM_BUFF(STR1LEN) \ { \ mstr_len_t lcl_len; \ \ if (0 == TREF(max_lcl_coll_xform_bufsiz)) \ { \ assert(NULL == TREF(lcl_coll_xform_buff)); \ TREF(max_lcl_coll_xform_bufsiz) = MAX_STRBUFF_INIT; \ TREF(lcl_coll_xform_buff) = (char *)malloc(TREF(max_lcl_coll_xform_bufsiz)); \ } \ lcl_len = STR1LEN; \ assert(MAX_STRLEN >= lcl_len); \ if (lcl_len > TREF(max_lcl_coll_xform_bufsiz)) \ { \ assert(NULL != TREF(lcl_coll_xform_buff)); \ free(TREF(lcl_coll_xform_buff)); \ assert(MAX_STRLEN >= TREF(max_lcl_coll_xform_bufsiz)); \ while (lcl_len > TREF(max_lcl_coll_xform_bufsiz)) \ TREF(max_lcl_coll_xform_bufsiz) *= 2; \ TREF(max_lcl_coll_xform_bufsiz) = MIN(MAX_STRLEN, TREF(max_lcl_coll_xform_bufsiz)); \ TREF(lcl_coll_xform_buff) = (char *)malloc(TREF(max_lcl_coll_xform_bufsiz)); \ } \ } /* Following two macros are currently used in replication filters, merge command and binary load to transform GTM null subscripts collation to standard null subscript collation and vice versa */ #define GTM2STDNULLCOLL(key, len) \ { \ unsigned char *currptr, *ptrtop; \ \ currptr = (unsigned char *)(key); \ ptrtop = (currptr + (len)); \ assert(currptr < ptrtop); \ do { \ if ((STR_SUB_PREFIX == *currptr++) && (KEY_DELIMITER == *currptr)) \ *(currptr - 1) = SUBSCRIPT_STDCOL_NULL; \ assert(currptr <= ptrtop); \ while ((currptr < ptrtop) && (KEY_DELIMITER != *currptr++)) \ ; \ } while ((currptr < ptrtop) && (KEY_DELIMITER != *currptr)); \ assert(currptr <= ptrtop); \ } #define STD2GTMNULLCOLL(key, len) \ { \ unsigned char *currptr, *ptrtop; \ \ currptr = (unsigned char *)(key); \ ptrtop = (currptr + (len)); \ assert(currptr < ptrtop); \ do { \ if ((SUBSCRIPT_STDCOL_NULL == *currptr++) && (KEY_DELIMITER == *currptr)) \ *(currptr - 1) = STR_SUB_PREFIX; \ assert(currptr <= ptrtop); \ while ((currptr < ptrtop) && (KEY_DELIMITER != *currptr++)) \ ; \ } while ((currptr < ptrtop) && (KEY_DELIMITER != *currptr)); \ assert(currptr <= ptrtop); \ } typedef struct collseq_struct { struct collseq_struct *flink; int act; int4 (*xform)(); int4 (*xback)(); int4 (*version)(); int4 (*verify)(); int argtype; } collseq; boolean_t map_collseq(mstr *fspec, collseq *ret_collseq); collseq *ready_collseq(int act); int4 do_verify(collseq *csp, unsigned char type, unsigned char ver); int find_local_colltype(void); void act_in_gvt(void); #endif /* COLLSEQ_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/comline.h0000644000032200000250000000112312201176154015625 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #define MAX_RECALL 99 #define MAX_RECALL_NUMBER_LENGTH 2 /* i.e. maximum recallable strings 99 */ #define clmod(x) ((x + MAX_RECALL) % MAX_RECALL) fis-gtm-V6.0-003/sr_port/comp_esc.h0000644000032200000250000000140512201176154015772 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ struct ce_sentinel_desc { char *escape_sentinel; int4 escape_length; int4 (*user_routine)(); struct ce_sentinel_desc *next; }; int ce_init(void); void ce_substitute(struct ce_sentinel_desc *shp, int4 source_col, int4 *skip_ct); void close_ceprep_file(void); void open_ceprep_file(void); void put_ceprep_line(void); fis-gtm-V6.0-003/sr_port/comp_fini.c0000644000032200000250000000662512201176176016155 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "stringpool.h" #include #include "mv_stent.h" #include "cgp.h" #include "alloc_reg.h" #include "advancewindow.h" #include "hashtab_str.h" /* WARNING: comp_fini restores the currently-active stringpool from the * indirection stringpool (indr_stringpool) to the runtime stringpool * (rts_stringpool). It depends on comp_init having changed it from * rts_stringpool to indr_stringpool during compilation setup. */ GBLREF spdesc stringpool, rts_stringpool, indr_stringpool; GBLREF short int source_column; GBLREF char cg_phase; GBLREF unsigned char *source_buffer; error_def(ERR_INDEXTRACHARS); error_def(ERR_INDRCOMPFAIL); int comp_fini(int status, mstr *obj, opctype retcode, oprtype *retopr, oprtype *dst, mstr_len_t src_len) { triple *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (status) { while (TK_SPACE == TREF(window_token)) /* Eat up trailing white space */ advancewindow(); if (TK_ERROR == TREF(window_token)) { status = EXPR_FAIL; stx_error(ERR_INDRCOMPFAIL); } else if ((TK_EOL != TREF(window_token)) || (source_column < src_len)) { status = EXPR_FAIL; stx_error(ERR_INDEXTRACHARS); } else { cg_phase = CGP_RESOLVE; assert(TREF(for_stack_ptr) == TADR(for_stack)); if (*TREF(for_stack_ptr)) tnxtarg(*TREF(for_stack_ptr)); ref = newtriple(retcode); if (retopr) ref->operand[0] = *retopr; if (OC_IRETMVAL == retcode) ref->operand[1] = *dst; start_fetches(OC_NOOP); resolve_ref(0); /* cannot fail because there are no MLAB_REF's in indirect code */ alloc_reg(); INVOKE_STP_GCOL(0); /* The above invocation of stp_gcol with a parameter of 0 is a critical part of compilation * (both routine compilations and indirect dynamic compilations). This collapses the indirect * (compilation) stringpool so that only the literals are left. This stringpool is then written * out to the compiled object as the literal pool for that compilation. Temporary stringpool * use for conversions or whatever are eliminated. Note the path is different in stp_gcol for * the indirect stringpool which is only used during compilations. */ assert(indr_stringpool.base == stringpool.base); indr_stringpool = stringpool; stringpool = rts_stringpool; TREF(compile_time) = FALSE; ind_code(obj); indr_stringpool.free = indr_stringpool.base; } } else { /* If this assert fails, it means a syntax problem could have been caught earlier. Consider placing a more useful * and specific error message at that location. */ assert(FALSE); stx_error(ERR_INDRCOMPFAIL); } if (EXPR_FAIL == status) { assert(indr_stringpool.base == stringpool.base); indr_stringpool = stringpool; stringpool = rts_stringpool; indr_stringpool.free = indr_stringpool.base; TREF(compile_time) = FALSE; cg_phase = CGP_NOSTATE; } TREF(transform) = TRUE; COMPILE_HASHTAB_CLEANUP; mcfree(); return status; } fis-gtm-V6.0-003/sr_port/comp_indr.c0000644000032200000250000000701212201176176016153 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #include #include "stack_frame.h" #include "mv_stent.h" #include "copy.h" #include "cache.h" #include "objlabel.h" #include "mprof.h" #include "compiler.h" #include "obj_file.h" #include "error.h" GBLREF mv_stent *mv_chain; GBLREF unsigned char *stackbase, *stacktop, *stackwarn, *msp; GBLREF stack_frame *frame_pointer; GBLREF boolean_t is_tracing_on; error_def(ERR_STACKCRIT); error_def(ERR_STACKOFLOW); void comp_indr(mstr *obj) { stack_frame *sf; unsigned char *fix, *fix_base, *tmps, *syms, *save_msp; int tempsz, vartabsz, fixup_cnt, zapsz; INTPTR_T *vp; ihdtyp *rtnhdr; assert((frame_pointer < frame_pointer->old_frame_pointer) || (NULL == frame_pointer->old_frame_pointer)); save_msp = msp; sf = (stack_frame *)(msp -= SIZEOF(stack_frame)); rtnhdr = (ihdtyp *)obj->addr; /* Check that our cache_entry pointer is in proper alignment with us */ assert(rtnhdr->indce->obj.addr == (char *)rtnhdr); tempsz = ROUND_UP2(rtnhdr->temp_size, SIZEOF(char *)); tmps = msp -= tempsz; vartabsz = rtnhdr->vartab_len; vartabsz *= SIZEOF(ht_ent_mname *); /* Check that our vars and friends can fit on this stack */ if ((msp -= vartabsz) <= stackwarn) { if (msp <= stacktop) { msp = save_msp; rts_error(VARLSTCNT(1) ERR_STACKOFLOW); } else rts_error(VARLSTCNT(1) ERR_STACKCRIT); } syms = msp; *sf = *frame_pointer; sf->old_frame_pointer = frame_pointer; sf->type = 0; sf->temps_ptr = tmps; sf->l_symtab = (ht_ent_mname **)syms; sf->vartab_len = rtnhdr->vartab_len; if (zapsz = (vartabsz + tempsz)) /* Note assignment */ memset(syms, 0, zapsz); /* Zap temps and symtab together */ sf->vartab_ptr = (char *)rtnhdr + rtnhdr->vartab_off; sf->temp_mvals = rtnhdr->temp_mvals; /* Code starts just past the literals that were fixed up and past the validation and hdr offset fields */ sf->mpc = (unsigned char *)rtnhdr + rtnhdr->fixup_vals_off + (rtnhdr->fixup_vals_num * SIZEOF(mval)); /* IA64 required SECTION_ALIGN_BOUNDARY alignment (16 bytes). ABS 2008/12 * This has been carried forward to other 64bit platfoms without problems */ GTM64_ONLY(sf->mpc = (unsigned char *)ROUND_UP2((UINTPTR_T)sf->mpc, SECTION_ALIGN_BOUNDARY)); sf->mpc = sf->mpc + (2 * SIZEOF(INTPTR_T)); /* Account for hdroffset and MAGIC_VALUE */ sf->flags = SFF_INDCE; /* We will be needing cleanup for this frame */ sf->ret_value = NULL; sf->dollar_test = -1; /* initialize it with -1 for indication of not yet being used */ DEBUG_ONLY( vp = (INTPTR_T *)sf->mpc; assert(NULL != vp); vp--; assert((GTM_OMAGIC << 16) + OBJ_LABEL == *vp); vp--; assert((unsigned char*)rtnhdr == (unsigned char *)vp + *vp); ); rtnhdr->indce->refcnt++; /* This entry is now in use on M stack */ if (is_tracing_on) new_prof_frame(FALSE); sf->ctxt = sf->mpc; assert(msp < stackbase); frame_pointer = sf; DBGEHND((stderr, "comp_indr: Added indirect stack frame at addr 0x"lvaddr" - New msp: 0x"lvaddr"\n", sf, msp)); assert((frame_pointer < frame_pointer->old_frame_pointer) || (NULL == frame_pointer->old_frame_pointer)); return; } fis-gtm-V6.0-003/sr_port/comp_init.c0000644000032200000250000000461112201176176016164 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "stp_parms.h" #include "compiler.h" #include "stringpool.h" #include #include "mv_stent.h" #include "opcode.h" #include "cgp.h" #include "lb_init.h" /* WARNING: comp_init changes the currently-active stringpool from the * the runtime stringpool (rts_stringpool) to the indirection stringpool * (indr_stringpool). comp_fini changes it back from indr_stringpool to * rts_stringpool when the compilation is finished. */ GBLREF spdesc stringpool,rts_stringpool; GBLREF spdesc indr_stringpool; GBLREF unsigned char *source_buffer; GBLREF int4 curr_fetch_count; GBLREF triple *curr_fetch_trip; GBLREF char cg_phase; error_def(ERR_INDRMAXLEN); void comp_init(mstr *src, oprtype *dst) { DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if ((unsigned)src->len >= MAX_SRCLINE) rts_error(VARLSTCNT(3) ERR_INDRMAXLEN, 1, MAX_SRCLINE); memcpy(source_buffer,src->addr,src->len); source_buffer[src->len + 1] = source_buffer[src->len] = 0; TREF(compile_time) = TRUE; TREF(transform) = FALSE; cg_phase = CGP_PARSE; TREF(source_error_found) = 0; TREF(last_source_column) = 0; assert(rts_stringpool.base == stringpool.base); rts_stringpool = stringpool; if (!indr_stringpool.base) { stp_init(STP_INITSIZE); indr_stringpool = stringpool; } else stringpool = indr_stringpool; tripinit(); lb_init(); assert(TREF(for_stack_ptr) == TADR(for_stack)); *TREF(for_stack_ptr) = NULL; curr_fetch_trip = newtriple(OC_FETCH); curr_fetch_count = 0; start_fetches(OC_FETCH); /* op_igetdst fetches the destination (ind_result) onto the M-stack at the start of execution so that if we end up doing * nested indirection, in which case ind_result could change, op_iretmval can put the result in the correct location. * op_igetsrc serves a very similar purpose, placing a copy of the source mval (ind_source) on the M-stack at the start * of execution. */ if (dst) *dst = put_tref(newtriple(OC_IGETDST)); return; } fis-gtm-V6.0-003/sr_port/compile_pattern.c0000644000032200000250000000417312201176154017367 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "compiler.h" #include "stringpool.h" #include "opcode.h" #include "mdq.h" #include "advancewindow.h" #include "compile_pattern.h" #include "patcode.h" #include "fullbool.h" GBLREF spdesc stringpool; GBLREF char *lexical_ptr; GBLREF unsigned char *source_buffer; GBLREF short int source_column; int compile_pattern(oprtype *opr, boolean_t is_indirect) { int status; ptstr retstr; mval retmval; mstr instr; triple *oldchain, *ref; save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (is_indirect) { if (SHIFT_SIDE_EFFECTS) { START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(opr)) { setcurtchain(oldchain); return FALSE; } ref = newtriple(OC_INDPAT); PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(opr)) return FALSE; ref = newtriple(OC_INDPAT); } ref->operand[0] = *opr; *opr = put_tref(ref); return TRUE; } else { instr.addr = (char *)&source_buffer[source_column - 1]; instr.len = STRLEN(instr.addr); status = patstr(&instr, &retstr, NULL); TREF(last_source_column) = (short int)(instr.addr - (char *)source_buffer); assert(TREF(last_source_column)); if (status) { /* status == syntax error when non-zero */ stx_error(status); return FALSE; } retmval.mvtype = MV_STR; retmval.str.len = retstr.len * SIZEOF(uint4); retmval.str.addr = (char *)stringpool.free; ENSURE_STP_FREE_SPACE(retmval.str.len); memcpy(stringpool.free, &retstr.buff[0], retmval.str.len); stringpool.free += retmval.str.len; *opr = put_lit(&retmval); lexical_ptr = instr.addr; advancewindow(); advancewindow(); return TRUE; } } fis-gtm-V6.0-003/sr_port/compile_pattern.h0000644000032200000250000000110212201176154017361 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __COMPILE_PATTERN_H__ #define __COMPILE_PATTERN_H__ int compile_pattern(oprtype *z, boolean_t is_indirect); #endif fis-gtm-V6.0-003/sr_port/compiler.h0000644000032200000250000005214112201176154016017 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef COMPILER_H_INCLUDED #define COMPILER_H_INCLUDED typedef unsigned int opctype; typedef struct mvarstruct { struct mvarstruct *lson, *rson; int4 mvidx; mident mvname; struct tripletype *last_fetch; } mvar; typedef struct mvaxstruct { struct mvaxstruct *last, *next; mvar *var; int4 mvidx; } mvax; typedef struct mlinestruct { struct mlinestruct *parent, *sibling, *child; struct tripletype *externalentry; uint4 line_number; /* ...operation on this line */ boolean_t table; /* put in table or not */ } mline; typedef struct mlabstruct { struct mlabstruct *lson, *rson; mline *ml; mident mvname; int formalcnt; boolean_t gbl; } mlabel; typedef struct mliteralstruct { struct { struct mliteralstruct *fl, *bl; } que; INTPTR_T rt_addr; mval v; } mliteral; typedef struct triplesize { struct tripletype *ct; int4 size; } tripsize; typedef struct oprtypestruct { char oprclass; union { struct oprtypestruct *indr; struct tripletype *tref; struct triplesize *tsize; mlabel *lab; mline *mlin; mliteral *mlit; mstr *cdlt; mvar *vref; int4 temp; int4 ilit; int4 offset; unsigned char vreg; } oprval; } oprtype; /* Values for oprclass */ #define NO_REF 0 #define TVAR_REF 1 #define TVAL_REF 2 #define TINT_REF 3 #define TVAD_REF 4 #define TCAD_REF 5 #define VALUED_REF_TYPES 6 #define VREG_REF 6 #define MLIT_REF 7 #define MVAR_REF 8 #define TRIP_REF 9 #define TNXT_REF 10 #define TJMP_REF 11 #define INDR_REF 12 #define MLAB_REF 13 #define ILIT_REF 14 #define CDLT_REF 15 #define TEMP_REF 16 #define MFUN_REF 17 #define MNXL_REF 18 /* refer to internalentry of child line */ #define TSIZ_REF 19 /* ilit refering to size of given triple codegen */ #define OCNT_REF 20 /* Offset from Call to Next Triple */ typedef struct tbptype { struct { struct tbptype *fl, *bl; } que; struct tripletype *bpt; } tbp; typedef struct { uint4 line; uint4 column; } source_address; typedef struct tripletype { opctype opcode; struct { struct tripletype *fl, *bl; } exorder; tbp backptr, /* triples which reference this triple's value */ jmplist; /* triples which jump to this one */ source_address src; int rtaddr; /* relative run time address of triple */ oprtype operand[2], destination; } triple; typedef struct { unsigned short octype; } octabstruct; /* Values for octype */ #define OCT_NULL 0 #define OCT_MVAL 1 #define OCT_MINT 2 #define OCT_MVADDR 4 #define OCT_CDADDR 8 #define OCT_VALUE (OCT_MVAL | OCT_MINT | OCT_CDADDR) #define OCT_BOOL 16 #define OCT_JUMP 32 #define OCT_EXPRLEAF 64 #define OCT_CGSKIP 128 #define OCT_COERCE 256 typedef struct { char name[20]; opctype bo_type; char uo_type; unsigned short opr_type; } toktabtype; /* These two structures really belong in glvn_pool.h, but gtmpcat doesn't know to include that file. So put them here for now. */ #include "callg.h" typedef struct { opctype sav_opcode; uint4 mval_top; /* mval just beyond ones used by this entry */ uint4 precursor; /* index of previous FOR slot at same level */ mval *lvname; gparam_list glvn_info; } glvn_pool_entry; typedef struct { uint4 capacity; /* total # allocated entries */ uint4 top; /* current available glvn_pool_entry slot */ uint4 for_slot[MAX_FOR_STACK + 1]; /* indices of most recent FOR slots */ uint4 share_slot; /* currently active slot */ opctype share_opcode; /* currently active opcode */ uint4 mval_capacity; /* total # allocated mvals */ uint4 mval_top; /* current available mval in mval_stack */ mval *mval_stack; /* stack of mvals */ glvn_pool_entry slot[1]; /* stack of entries */ } glvn_pool; #define VMS_OS 01 #define UNIX_OS 02 #define ALL_SYS (VMS_OS | UNIX_OS) #ifdef UNIX /* function and svn validation are a function of the OS */ # define VALID_FUN(i) (fun_data[i].os_syst & UNIX_OS) # define VALID_SVN(i) (svn_data[i].os_syst & UNIX_OS) # ifdef __hppa # define TRIGGER_OS 0 # else # define TRIGGER_OS UNIX_OS # endif #elif defined VMS # define VALID_FUN(i) (fun_data[i].os_syst & VMS_OS) # define VALID_SVN(i) (svn_data[i].os_syst & VMS_OS) # define TRIGGER_OS 0 #else # error UNSUPPORTED PLATFORM #endif #define MUMPS_INT 0 /* integer - they only type the compiler handles differently */ #define MUMPS_EXPR 1 /* expression */ #define MUMPS_STR 2 /* string */ #define MUMPS_NUM 3 /* numeric - potentially non-integer */ #define EXPR_FAIL 0 /* expression had syntax error - frequently represented by FALSE*/ #define EXPR_GOOD 1 /* expression ok, no indirection at root - frequently represented by TRUE */ #define EXPR_INDR 2 /* expression ok, indirection at root */ #define EXPR_SHFT 4 /* expression ok, involved shifted GV references */ #define CHARMAXARGS 256 #define MAX_FORARGS 127 #define MAX_SRCLINE 8192 /* maximum length of a program source or indirection line */ #define NO_FORMALLIST (-1) /* Some errors should not cause stx_error to issue an rts_error. These are the errors related to * a) Invalid Intrinsic Commands * b) Invalid Intrinsic Function Names * c) Invalid Intrinsic Special Variables * d) Invalid Deviceparameters for IO commands * These should cause an error at runtime if and only if that codepath is reached. * PostConditionals can cause this path to be avoided in which case we do not want to issue an error at compile time. * Therefore issue only a warning at compile-time and proceed with compilation as if this codepath will not be reached at runtime. */ error_def(ERR_DEVPARINAP); error_def(ERR_DEVPARUNK); error_def(ERR_DEVPARVALREQ); error_def(ERR_FNOTONSYS); error_def(ERR_INVCMD); error_def(ERR_INVFCN); error_def(ERR_INVSVN); error_def(ERR_SVNONEW); error_def(ERR_SVNOSET); #define IS_STX_WARN(errcode) \ ((ERR_DEVPARINAP == errcode) || (ERR_DEVPARUNK == errcode) || (ERR_DEVPARVALREQ == errcode) \ || (ERR_FNOTONSYS == errcode) || (ERR_INVCMD == errcode) || (ERR_INVFCN == errcode) \ || (ERR_INVSVN == errcode) || (ERR_SVNONEW == errcode) || (ERR_SVNOSET == errcode)) /* This macro does an "stx_error" of the input errcode but before that it asserts that the input errcode is one * of the known error codes that are to be handled as a compile-time warning (instead of an error). It also set * the variable "parse_warn" to TRUE which is relied upon by the functions that invoke this macro. Note that when * triggers are included, warnings become errors so bypass the warning stuff. */ #ifdef GTM_TRIGGER # define STX_ERROR_WARN(errcode) \ { \ if (!TREF(trigger_compile)) \ parse_warn = TRUE; \ assert(IS_STX_WARN(errcode)); \ stx_error(errcode); \ if (TREF(trigger_compile)) \ return FALSE; \ } #else # define STX_ERROR_WARN(errcode) \ { \ parse_warn = TRUE; \ assert(IS_STX_WARN(errcode)); \ stx_error(errcode); \ } #endif #ifdef DEBUG # define COMPDBG(x) if (gtmDebugLevel & GDL_DebugCompiler) {x} #else # define COMPDBG(x) #endif /* Cutover from simple lists to hash table access - tuned by testing compilation of 24K+ Vista M source routines. */ #include "copy.h" #define LIT_HASH_CUTOVER DEBUG_ONLY(4) PRO_ONLY(32) #define SYM_HASH_CUTOVER DEBUG_ONLY(4) PRO_ONLY(16) #define COMPLITS_HASHTAB_CLEANUP \ { \ GBLREF hash_table_str *complits_hashtab; \ if (complits_hashtab && complits_hashtab->base) \ { /* Release hash table itself but leave hash table descriptor if exists */ \ free_hashtab_str(complits_hashtab); \ } \ } #define COMPSYMS_HASHTAB_CLEANUP \ { \ GBLREF hash_table_str *compsyms_hashtab; \ if (compsyms_hashtab && compsyms_hashtab->base) \ { /* Release hash table itself but leave hash table descriptor if exists */ \ free_hashtab_str(compsyms_hashtab); \ compsyms_hashtab->base = NULL; \ } \ } #define COMPILE_HASHTAB_CLEANUP \ COMPLITS_HASHTAB_CLEANUP; \ COMPSYMS_HASHTAB_CLEANUP; /* Macro to compute running checksum of a routine one line at a time. */ #define RTN_SRC_CHKSUM(srcptr, srclen, chksum) \ { \ char *chkcalc, *cptr; \ uint4 srcint; \ for (chkcalc = srcptr, cptr = srcptr + srclen; chkcalc < cptr; ) \ { \ srcint = 0; \ if (INTCAST(cptr - chkcalc) < SIZEOF(uint4)) \ { \ memcpy(&srcint, chkcalc, cptr - chkcalc); \ chkcalc = cptr; /* Stops loop after this iteration is complete */ \ } else \ { \ GET_ULONG(srcint, chkcalc); \ chkcalc += SIZEOF(uint4); \ } \ chksum ^= srcint; \ chksum >>= 1; \ } \ } typedef struct { triple *expr_start; triple *expr_start_orig; boolean_t shift_side_effects; boolean_t saw_side_effect; triple tmpchain; } save_se; #define START_GVBIND_CHAIN(SS, OLDCHAIN) \ { \ (SS)->expr_start = TREF(expr_start); \ (SS)->expr_start_orig = TREF(expr_start_orig); \ (SS)->shift_side_effects = TREF(shift_side_effects); \ (SS)->saw_side_effect = TREF(saw_side_effect); \ TREF(expr_start) = NULL; \ TREF(expr_start_orig) = NULL; \ TREF(shift_side_effects) = FALSE; \ TREF(saw_side_effect) = FALSE; \ dqinit(&(SS)->tmpchain, exorder); \ OLDCHAIN = setcurtchain(&(SS)->tmpchain); \ } #define PLACE_GVBIND_CHAIN(SS, OLDCHAIN) \ { \ newtriple(OC_GVSAVTARG); \ TREF(expr_start) = (SS)->expr_start; \ TREF(expr_start_orig) = (SS)->expr_start_orig; \ TREF(shift_side_effects) = (SS)->shift_side_effects; \ TREF(saw_side_effect) = (SS)->saw_side_effect; \ setcurtchain(OLDCHAIN); \ assert(NULL != TREF(expr_start)); \ dqadd(TREF(expr_start), &(SS)->tmpchain, exorder); \ TREF(expr_start) = (SS)->tmpchain.exorder.bl; \ assert(OC_GVSAVTARG == (TREF(expr_start))->opcode); \ newtriple(OC_GVRECTARG)->operand[0] = put_tref(TREF(expr_start)); \ } /* note assignment below */ #define SHIFT_SIDE_EFFECTS ((TREF(saw_side_effect) = TREF(shift_side_effects)) && (GTM_BOOL == TREF(gtm_fullbool))) #define INITIAL_SIDE_EFFECT_DEPTH 33 /* initial allocation for expression nesting to track side effects */ /* note side effect for boolean shifting temporaries */ #define ENCOUNTERED_SIDE_EFFECT \ { /* Needs #include "show_source_line" and #include "fullbool.h" */ \ \ if (TREF(shift_side_effects)) \ { \ TREF(saw_side_effect) = TRUE; \ if (!run_time && (FULL_BOOL_WARN == TREF(gtm_fullbool))) \ { /* warnings requested by by gtm_fullbool and enabled by eval_expr */ \ show_source_line(TRUE); \ dec_err(VARLSTCNT(1) ERR_BOOLSIDEFFECT); \ } \ } \ } #define SE_WARN_ON (!run_time && (SE_WARN == TREF(side_effect_handling))) #define ISSUE_SIDEEFFECTEVAL_WARNING(COLUMN) \ { \ TREF(last_source_column) = (COLUMN); \ show_source_line(TRUE); \ dec_err(VARLSTCNT(1) ERR_SIDEEFFECTEVAL); \ } /* maintain array indexed by expr_depth to track side effects - for subscripts, actuallists, binary expressions and functions */ #define INCREMENT_EXPR_DEPTH \ { \ boolean_t *TMP_BASE; \ \ if (!(TREF(expr_depth))++) \ TREF(expr_start) = TREF(expr_start_orig) = NULL; \ else \ { /* expansion is unlikely as it's hard to nest expressions deeply, but we don't want a hard limit */ \ assertpro(TREF(expr_depth)); /* expr_depth doesn't handle rollover */ \ assert(TREF(expr_depth) <= TREF(side_effect_depth)); \ if (TREF(expr_depth) == TREF(side_effect_depth)) \ { \ TMP_BASE = TREF(side_effect_base); \ (TREF(side_effect_depth))++; \ TREF(side_effect_base) = malloc(SIZEOF(boolean_t) * TREF(side_effect_depth)); \ memcpy(TREF(side_effect_base), TMP_BASE, SIZEOF(boolean_t) * TREF(expr_depth)); \ free(TMP_BASE); \ (TREF(side_effect_base))[TREF(expr_depth)] = FALSE; \ } \ } \ assert(FALSE == (TREF(side_effect_base))[TREF(expr_depth)]); \ } /* complement of the above increment - uses the macro just below for assertpto and to clear the level we're leaving */ #define DECREMENT_EXPR_DEPTH \ { \ DISABLE_SIDE_EFFECT_AT_DEPTH; \ if (!(--(TREF(expr_depth)))) \ TREF(saw_side_effect) = TREF(shift_side_effects) = FALSE; \ } /* clear the current expr_depth level and propagate down */ #define DISABLE_SIDE_EFFECT_AT_DEPTH \ { \ unsigned int DEPTH; \ \ DEPTH = TREF(expr_depth); \ assertpro(DEPTH); /* expr_depth shouldn't underflow */ \ (TREF(side_effect_base))[DEPTH - 1] |= (TREF(side_effect_base))[DEPTH]; /* propagate down */ \ (TREF(side_effect_base))[DEPTH] = FALSE; \ } /* The following macro transfers subscripts from an array to the triple chain for gvn, lvn and name_glvn * it requires includes for fullbool.m, mdq.h, and show_source_line.h, and also GBLREF of runtime */ #define SUBS_ARRAY_2_TRIPLES(REF1, SB1, SB2, SUBSCRIPTS, XTRA) \ { \ boolean_t PROTECT_LVN, SE_NOTIFY; \ triple *REF2; \ \ if (PROTECT_LVN = (TREF(side_effect_base))[TREF(expr_depth)]) /* NOTE assignment */ \ SE_NOTIFY = SE_WARN_ON; \ while (SB2 < SB1) \ { \ if (PROTECT_LVN && (SB2 > (SUBSCRIPTS + XTRA)) && ((SB1 - SB2) > 1) \ && ((OC_VAR == SB2->oprval.tref->opcode) || (OC_GETINDX == SB2->oprval.tref->opcode))) \ { /* protect lvns from side effects: skip 1st (unsubscripted name), and last (nothing following) */ \ assert(OLD_SE != TREF(side_effect_handling)); \ REF2 = maketriple(OC_STOTEMP); \ REF2->operand[0] = *SB2; \ dqins(SB2->oprval.tref, exorder, REF2); /* NOTE:this violates information hiding */ \ if (SE_NOTIFY) \ ISSUE_SIDEEFFECTEVAL_WARNING(SB2->oprval.tref->src.column + 1); \ *SB2 = put_tref(REF2); \ } \ REF2 = newtriple(OC_PARAMETER); \ REF1->operand[1] = put_tref(REF2); \ REF1 = REF2; \ REF1->operand[0] = *SB2++; \ } \ } /* the macro below tucks a code reference into the for_stack so a FOR that's done can move on correctly when done */ #define FOR_END_OF_SCOPE(DEPTH, RESULT) \ { \ oprtype **Ptr; \ \ assert(0 <= DEPTH); \ assert(TREF(for_stack_ptr) < (oprtype **)TADR(for_stack) + MAX_FOR_STACK); \ Ptr = (oprtype **)TREF(for_stack_ptr) - DEPTH; \ assert(Ptr >= (oprtype **)TADR(for_stack)); \ if (NULL == *Ptr) \ *Ptr = (oprtype *)mcalloc(SIZEOF(oprtype)); \ RESULT = put_indr(*Ptr); \ } #define GOOD_FOR FALSE /* single level */ #define BLOWN_FOR TRUE /* all levels */ /* Marco to decrement or clear the for_stack, clear the for_temp array * and generate code to release run-time malloc'd mvals anchored in the for_saved_indx array * The corresponding FOR_PUSH macro is in m_for.c but this one is used in stx_error.c for error cases */ #define FOR_POP(ALL) \ { \ assert(TREF(for_stack_ptr) >= (oprtype **)TADR(for_stack)); \ assert(TREF(for_stack_ptr) <= (oprtype **)TADR(for_stack) + MAX_FOR_STACK); \ if (ALL) \ { \ (TREF(for_stack_ptr)) = (oprtype **)TADR(for_stack); \ *(TREF(for_stack_ptr)) = NULL; \ } else if (TREF(for_stack_ptr) > (oprtype **)TADR(for_stack)) \ --(TREF(for_stack_ptr)); \ } int actuallist(oprtype *opr); int bool_expr(boolean_t op, oprtype *addr); void bx_boolop(triple *t, boolean_t jmp_type_one, boolean_t jmp_to_next, boolean_t sense, oprtype *addr); void bx_relop(triple *t, opctype cmp, opctype tst, oprtype *addr); void bx_tail(triple *t, boolean_t sense, oprtype *addr); void chktchain(triple *head); void code_gen(void); void coerce(oprtype *a, unsigned short new_type); int comp_fini(int status, mstr *obj, opctype retcode, oprtype *retopr, oprtype *dst, mstr_len_t src_len); void comp_init(mstr *src, oprtype *dst); void comp_indr(mstr *obj); boolean_t compiler_startup(void); void create_temporaries(triple *sub, opctype put_oc); triple *entryref(opctype op1, opctype op2, mint commargcode, boolean_t can_commarg, boolean_t labref, boolean_t textname); int eval_expr(oprtype *a); int expratom(oprtype *a); int exfunc(oprtype *a, boolean_t alias_target); int expritem(oprtype *a); int expr(oprtype *a, int m_type); void ex_tail(oprtype *opr); int extern_func(oprtype *a); int f_ascii(oprtype *a, opctype op); int f_char(oprtype *a, opctype op); int f_data(oprtype *a, opctype op); int f_extract(oprtype *a, opctype op); int f_find(oprtype *a, opctype op); int f_fnumber(oprtype *a, opctype op); int f_fnzbitfind(oprtype *a, opctype op); int f_fnzbitget(oprtype *a, opctype op); int f_fnzbitset(oprtype *a, opctype op); int f_fnzbitstr(oprtype *a, opctype op); int f_get(oprtype *a, opctype op); int f_get1(oprtype *a, opctype op); int f_incr(oprtype *a, opctype op); int f_justify(oprtype *a, opctype op); int f_length(oprtype *a, opctype op); int f_mint(oprtype *a, opctype op); int f_mint_mstr(oprtype *a, opctype op); int f_mstr(oprtype *a, opctype op); int f_name(oprtype *a, opctype op); int f_next(oprtype *a, opctype op); int f_one_mval(oprtype *a, opctype op); int f_order(oprtype *a, opctype op); int f_order1(oprtype *a, opctype op); int f_piece(oprtype *a, opctype op); int f_qlength(oprtype *a, opctype op); int f_qsubscript(oprtype *a, opctype op); int f_query (oprtype *a, opctype op); int f_reverse(oprtype *a, opctype op); int f_select(oprtype *a, opctype op); int f_stack(oprtype *a, opctype op); int f_text(oprtype *a, opctype op); int f_translate(oprtype *a, opctype op); int f_two_mstrs(oprtype *a, opctype op); int f_two_mval(oprtype *a, opctype op); int f_view(oprtype *a, opctype op); int f_zahandle(oprtype *a, opctype op); int f_zcall(oprtype *a, opctype op); int f_zchar(oprtype *a, opctype op); int f_zconvert(oprtype *a, opctype op); int f_zdate(oprtype *a, opctype op); int f_zdebug(oprtype *a, opctype op); int f_zechar(oprtype *a, opctype op); int f_zgetsyi(oprtype *a, opctype op); int f_zjobexam(oprtype *a, opctype op); int f_zparse(oprtype *a, opctype op); int f_zpeek(oprtype *a, opctype op); int f_zprevious(oprtype *a, opctype op); int f_zqgblmod(oprtype *a, opctype op); int f_zsearch(oprtype *a, opctype op); int f_zsigproc(oprtype *a, opctype op); int f_zsqlexpr (oprtype *a, opctype op); int f_zsqlfield (oprtype *a, opctype op); int f_zsubstr(oprtype *a, opctype op); int f_ztrigger(oprtype *a, opctype op); int f_ztrnlnm(oprtype *a, opctype op); int f_zwidth(oprtype *a, opctype op); int f_zwrite(oprtype *a, opctype op); mlabel *get_mladdr(mident *c); mvar *get_mvaddr(mident *c); int glvn(oprtype *a); int gvn(void); void ind_code(mstr *obj); int indirection(oprtype *a); void ins_triple(triple *x); void int_label(void); int jobparameters (oprtype *c); boolean_t line(uint4 *lnc); int linetail(void); int lkglvn(boolean_t gblvn); int lref(oprtype *label, oprtype *offset, boolean_t no_lab_ok, mint commarg_code, boolean_t commarg_ok, boolean_t *got_some); int lvn(oprtype *a,opctype index_op,triple *parent); void make_commarg(oprtype *x, mint ind); oprtype make_gvsubsc(mval *v); triple *maketriple(opctype op); int name_glvn(boolean_t gblvn, oprtype *a); triple *newtriple(opctype op); int nref(void); void obj_code(uint4 src_lines, uint4 checksum); int one_job_param(char **parptr); int parse_until_rparen_or_space(void); oprtype put_ocnt(void); oprtype put_tsiz(void); oprtype put_cdlt(mstr *x); oprtype put_ilit(mint x); oprtype put_indr(oprtype *x); oprtype put_lit(mval *x); oprtype put_mfun(mident *l); oprtype put_mlab(mident *l); oprtype put_mnxl(void); oprtype put_mvar(mident *x); oprtype put_str(char *pt, mstr_len_t n); oprtype put_tjmp(triple *x); oprtype put_tnxt(triple *x); oprtype put_tref(triple *x); int resolve_ref(int errknt); void resolve_tref(triple *, oprtype *); triple *setcurtchain(triple *x); /* VMS uses same code generator as USHBIN so treat as USHBIN for these compiler routines */ # if defined(USHBIN_SUPPORTED) || defined(VMS) void shrink_trips(void); boolean_t litref_triple_oprcheck(oprtype *operand); # else void shrink_jmps(void); # endif void start_fetches(opctype op); void start_for_fetches(void); void tnxtarg(oprtype *a); void tripinit(void); void walktree(mvar *n,void (*f)(),char *arg); void wrtcatopt(triple *r, triple ***lpx, triple **lptop); int zlcompile(unsigned char len, unsigned char *addr); /***type int added***/ #endif /* COMPILER_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/compiler_ch.c0000644000032200000250000000304012201176176016462 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "error.h" #include "cgp.h" #include "cmd_qlf.h" #include "list_file.h" #include "source_file.h" #include #include "obj_file.h" #include "reinit_externs.h" #include "compiler.h" #include "util.h" #include "hashtab_str.h" GBLREF command_qualifier cmd_qlf; GBLREF char cg_phase; GBLREF boolean_t mstr_native_align, save_mstr_native_align; error_def(ERR_ASSERT); error_def(ERR_FORCEDHALT); error_def(ERR_GTMASSERT); error_def(ERR_GTMASSERT2); error_def(ERR_GTMCHECK); error_def(ERR_MEMORY); error_def(ERR_VMSMEMORY); error_def(ERR_STACKOFLOW); error_def(ERR_OUTOFSPACE); CONDITION_HANDLER(compiler_ch) { START_CH; if (DUMPABLE) { NEXTCH; } if (cmd_qlf.qlf & CQ_WARNINGS) PRN_ERROR; COMPILE_HASHTAB_CLEANUP; reinit_externs(); mstr_native_align = save_mstr_native_align; if (cg_phase == CGP_MACHINE) drop_object_file(); if (cg_phase > CGP_NOSTATE) { if (cg_phase < CGP_RESOLVE) close_source_file(); if (cg_phase < CGP_FINI && (cmd_qlf.qlf & CQ_LIST || cmd_qlf.qlf & CQ_CROSS_REFERENCE)) { close_list_file(); } } UNWIND(NULL, NULL); } fis-gtm-V6.0-003/sr_port/compiler_startup.c0000644000032200000250000001467012201176154017601 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "compiler.h" #include "opcode.h" #include "cmd_qlf.h" #include "mdq.h" #include "cgp.h" #include "error.h" #include "mmemory.h" #include "stringpool.h" #include "list_file.h" #include "source_file.h" #include "lb_init.h" #include "reinit_externs.h" #include "comp_esc.h" #include "resolve_blocks.h" #include "hashtab_str.h" #define HOPELESS_COMPILE 128 GBLREF short int source_column, source_line; /* ensure source_buffer is aligned on a int4 word boundary so that * we can calculate the checksum a longword at a time. */ GBLREF int4 aligned_source_buffer[MAX_SRCLINE / SIZEOF(int4) + 1]; GBLREF unsigned char *source_buffer; GBLREF src_line_struct src_head; GBLREF triple t_orig, *curr_fetch_trip, *curr_fetch_opr; GBLREF int4 curr_fetch_count; GBLREF command_qualifier cmd_qlf; GBLREF int mlmax; GBLREF mline mline_root; GBLREF char cg_phase; /* code generation phase */ GBLREF boolean_t mstr_native_align, save_mstr_native_align; GBLREF hash_table_str *complits_hashtab; LITDEF char compile_terminated[] = "COMPILATION TERMINATED DUE TO EXCESS ERRORS"; boolean_t compiler_startup(void) { #ifdef DEBUG void dumpall(); #endif boolean_t compile_w_err; unsigned char err_buf[45]; unsigned char *cp, *cp2; int errknt; int4 n; uint4 checksum, line_count; mlabel *null_lab; src_line_struct *sl; mident null_mident; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; /* Although we have an invocation of compiler cleanups at the end of this module, there exist ways to avoid this * cleanup by working in direct mode, getting certain types of errors combined with an argumentless ZGOTO that unwinds * pretty much everything that can bypass that cleanup. So do a quick check if it is needed and if so, git-r-done * (test is part of the macro invocation). Note this is the easiest place to make this check rather than complicating * error handling to provide a similar effect. */ COMPILE_HASHTAB_CLEANUP; reinit_externs(); memset(&null_mident, 0, SIZEOF(null_mident)); ESTABLISH_RET(compiler_ch, FALSE); /* Since the stringpool alignment is solely based on mstr_native_align, we need to initialize it based * on the ALIGN_STRINGS qualifier so that all strings in the literal text pool are aligned. * However, when a module is compiled at runtime, we need to preserve the existing runtime setting * (that was initialized at GT.M startup) once the compilation is done. save_mstr_native_align is used for * this purpose. */ save_mstr_native_align = mstr_native_align; /* mstr_native_align = (cmd_qlf.qlf & CQ_ALIGN_STRINGS) ? TRUE : FALSE; */ mstr_native_align = FALSE; /* TODO: remove this line and uncomment the above line */ cg_phase = CGP_NOSTATE; TREF(source_error_found) = errknt = 0; if(!open_source_file()) { mstr_native_align = save_mstr_native_align; REVERT; return FALSE; } cg_phase = CGP_PARSE; if (cmd_qlf.qlf & CQ_LIST || cmd_qlf.qlf & CQ_CROSS_REFERENCE) { if (cmd_qlf.qlf & CQ_MACHINE_CODE) dqinit(&src_head, que); open_list_file(); } if (cmd_qlf.qlf & CQ_CE_PREPROCESS) open_ceprep_file(); tripinit(); null_lab = get_mladdr(&null_mident); null_lab->ml = &mline_root; mlmax++; curr_fetch_trip = curr_fetch_opr = newtriple(OC_LINEFETCH); curr_fetch_count = 0; TREF(code_generated) = FALSE; checksum = 0; line_count = 1; for (source_line = 1; errknt <= HOPELESS_COMPILE; source_line++) { if (-1 == (n = read_source_file())) break; if (cmd_qlf.qlf & CQ_LIST || cmd_qlf.qlf & CQ_CROSS_REFERENCE) { if (cmd_qlf.qlf & CQ_MACHINE_CODE) { sl = (src_line_struct *)mcalloc(SIZEOF(src_line_struct)); dqins(&src_head, que, sl); sl->addr = mcalloc(n + 1); /* +1 for zero termination */ sl->line = source_line; memcpy(sl->addr, source_buffer, n + 1); } else { list_line_number(); list_line((char *)source_buffer); } } /* calculate checksum */ RTN_SRC_CHKSUM((char *)source_buffer, n, checksum); TREF(source_error_found) = 0; lb_init(); if (cmd_qlf.qlf & CQ_CE_PREPROCESS) put_ceprep_line(); if (!line(&line_count)) { assert(TREF(source_error_found)); errknt++; } } close_source_file(); if (cmd_qlf.qlf & CQ_CE_PREPROCESS) close_ceprep_file(); cg_phase = CGP_RESOLVE; if (t_orig.exorder.fl == &t_orig) /* if no lines in routine, set up line 0 */ newtriple(OC_LINESTART); newtriple(OC_RET); /* always provide a default QUIT */ mline_root.externalentry = t_orig.exorder.fl; INVOKE_STP_GCOL(0); /* The above invocation of stp_gcol with a parameter of 0 is a critical part of compilation * (both routine compilations and indirect dynamic compilations). This collapses the indirect * (compilation) stringpool so that only the literals are left. This stringpool is then written * out to the compiled object as the literal pool for that compilation. Temporary stringpool * use for conversions or whatever are eliminated. Note the path is different in stp_gcol for * the indirect stringpool which is only used during compilations. */ start_fetches(OC_NOOP); resolve_blocks(); errknt = resolve_ref(errknt); compile_w_err = (errknt <= HOPELESS_COMPILE && (cmd_qlf.qlf & CQ_IGNORE)); if (cmd_qlf.qlf & CQ_LIST || cmd_qlf.qlf & CQ_CROSS_REFERENCE) { list_line(""); if (errknt) cp = i2asc(err_buf, errknt); else { cp = err_buf; *cp++ = 'n'; *cp++ = 'o'; } memcpy(cp, " error", SIZEOF(" error")); cp += SIZEOF(" error") - 1; if (1 != errknt) *cp++ = 's'; *cp = 0; list_line((char *)err_buf); if (errknt > HOPELESS_COMPILE) list_line((char *)compile_terminated); if (cmd_qlf.qlf & CQ_MACHINE_CODE && compile_w_err) list_head(1); } if ((!errknt || compile_w_err) && (cmd_qlf.qlf & CQ_OBJECT || cmd_qlf.qlf & CQ_MACHINE_CODE)) { obj_code(line_count, checksum); cg_phase = CGP_FINI; } if (cmd_qlf.qlf & CQ_LIST || cmd_qlf.qlf & CQ_CROSS_REFERENCE) { list_cmd(); close_list_file(); } COMPILE_HASHTAB_CLEANUP; reinit_externs(); mstr_native_align = save_mstr_native_align; REVERT; return errknt ? TRUE : FALSE; } fis-gtm-V6.0-003/sr_port/compswap.h0000644000032200000250000000612212201176154016034 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef COMPSWAP_H_INCLUDE #define COMPSWAP_H_INCLUDE /* COMPSWAP_LOCK/UNLOCK are the same for all platform except for __ia64, which needs slightly different versions to handle * memory consistency isues */ #ifdef UNIX boolean_t compswap_secshr(sm_global_latch_ptr_t lock, int compval, int newval1); # if (defined(_AIX) || (defined(__ia64) && defined(__linux__))) /* AIX or Linux Itanium */ boolean_t compswap_lock(sm_global_latch_ptr_t lock, int compval, int newval1); boolean_t compswap_unlock(sm_global_latch_ptr_t lock, int compval, int newval1); # define COMPSWAP_LOCK(LCK, CMPVAL1, CMPVAL2, NEWVAL1, NEWVAL2) compswap_lock(LCK, CMPVAL1, NEWVAL1) # define COMPSWAP_UNLOCK(LCK, CMPVAL1, CMPVAL2, NEWVAL1, NEWVAL2) compswap_unlock(LCK, CMPVAL1, NEWVAL1) # elif !defined(__ia64) boolean_t compswap(sm_global_latch_ptr_t lock, int compval, int newval1); # define COMPSWAP_LOCK(LCK, CMPVAL1, CMPVAL2, NEWVAL1, NEWVAL2) compswap(LCK, CMPVAL1, NEWVAL1) # define COMPSWAP_UNLOCK(LCK, CMPVAL1, CMPVAL2, NEWVAL1, NEWVAL2) compswap(LCK, CMPVAL1, NEWVAL1) # elif (defined(__HP_cc) || (defined(__hpux) && defined(__GNUC__))) /* Use compiler inline assembly macros for HP-UX/HP C or GCC on HPUX*/ /* This is assuming 32 bit lock storage, which right now seems to be PIDs * most of the time. PIDs are currently 32 bit values, but that could change * someday, so beware */ # include # define FENCE (_Asm_fence) (_UP_CALL_FENCE | _UP_SYS_FENCE | _DOWN_CALL_FENCE | _DOWN_SYS_FENCE) # define COMPSWAP_LOCK(LCK, CMPVAL1, CMPVAL2, NEWVAL1, NEWVAL2) \ ( \ _Asm_mov_to_ar((_Asm_app_reg)_AREG_CCV, (uint64_t) CMPVAL1,FENCE), \ _Asm_cmpxchg((_Asm_sz)_SZ_W, (_Asm_sem)_SEM_ACQ,(uint32_t *)LCK, \ (uint64_t)NEWVAL1, (_Asm_ldhint)_LDHINT_NONE) == (uint64_t)CMPVAL1 ? 1 : 0 \ ) # define COMPSWAP_UNLOCK(LCK, CMPVAL1, CMPVAL2, NEWVAL1, NEWVAL2) \ ( \ _Asm_mov_to_ar((_Asm_app_reg)_AREG_CCV,(uint64_t) CMPVAL1,FENCE), \ _Asm_cmpxchg((_Asm_sz)_SZ_W,(_Asm_sem)_SEM_REL,(uint32_t *)LCK, \ (uint64_t)NEWVAL1, (_Asm_ldhint)_LDHINT_NONE) == (uint64_t)CMPVAL1 ? 1 : 0 \ ) # else # error Unsupported Platform sr_port/compswap.h # endif /* __ia64 */ #else boolean_t compswap(sm_global_latch_ptr_t lock, int compval1, int compval2, int newval1, int newval2); boolean_t compswap_secshr(sm_global_latch_ptr_t lock, int compval1, int compval2, int newval1, int newval2); # define COMPSWAP_LOCK(LCK, CMPVAL1, CMPVAL2, NEWVAL1, NEWVAL2) compswap(LCK, CMPVAL1, CMPVAL2, NEWVAL1, NEWVAL2) # define COMPSWAP_UNLOCK(LCK, CMPVAL1, CMPVAL2, NEWVAL1, NEWVAL2) compswap(LCK, CMPVAL1, CMPVAL2, NEWVAL1, NEWVAL2) #endif #endif fis-gtm-V6.0-003/sr_port/copy.h0000644000032200000250000000541612201176154015162 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* If unaligned access is supported UNALIGNED_ACCESS_SUPPORTED has to be defined in the appropriate mdefsp.h * On platforms where unaligned data is not legal, * the macros are defined using a series of character moves */ #ifdef UNALIGNED_ACCESS_SUPPORTED /* Unsigned versions are different from signed ones as we may get sign extension problems when promotion is needed */ #define GET_LONGP(X,Y) (*(int4 *)(X) = *(int4 *)(Y)) #define GET_SHORTP(X,Y) (*(short *)(X) = *(short *)(Y)) #define GET_LONG(X,Y) ((X) = *(int4 *)(Y)) #define GET_ULONG(X,Y) ((X) = *(uint4 *)(Y)) #define GET_SHORT(X,Y) ((X) = *(short *)(Y)) #define GET_USHORT(X,Y) ((X) = *(unsigned short *)(Y)) #define GET_CHAR(X,Y) ((X) = *(unsigned char *)(Y)) #define REF_CHAR(Y) (*(unsigned char *)Y) #define PUT_ZERO(X) ((X) = 0) #define PUT_LONG(X,Y) (*(int4*)(X) = (Y)) #define PUT_ULONG(X,Y) (*(uint4*)(X) = (Y)) #define PUT_SHORT(X,Y) (*(short*)(X) = (Y)) #define PUT_USHORT(X,Y) (*(unsigned short*)(X) = (Y)) #define PUT_CHAR(X,Y) (*(unsigned char *)(X) = (Y)) #else #include #define GET_LONGP(X,Y) (*(caddr_t)(X) = *(caddr_t)(Y), \ *((caddr_t)(X)+1) = *((caddr_t)(Y)+1), \ *((caddr_t)(X)+2) = *((caddr_t)(Y)+2), \ *((caddr_t)(X)+3) = *((caddr_t)(Y)+3)) #define GET_SHORTP(X,Y) (*(caddr_t)(X) = *(caddr_t)(Y), *((caddr_t)(X)+1) = *((caddr_t)(Y)+1)) /* Unsigned versions are same as the signed ones as we do char by char */ #define GET_LONG(X,Y) (*(caddr_t)(&X) = *(caddr_t)(Y), \ *((caddr_t)(&X)+1) = *((caddr_t)(Y)+1), \ *((caddr_t)(&X)+2) = *((caddr_t)(Y)+2), \ *((caddr_t)(&X)+3) = *((caddr_t)(Y)+3)) #define GET_ULONG GET_LONG #define GET_SHORT(X,Y) (*(caddr_t)(&X) = *(caddr_t)(Y), *((caddr_t)(&X)+1) = *((caddr_t)(Y)+1)) #define GET_USHORT GET_SHORT #define GET_CHAR(X,Y) (*(caddr_t)(&X) = *(caddr_t)(Y)) #define REF_CHAR(Y) (*(caddr_t)(Y)) #define PUT_ZERO(X) (memset((caddr_t)&(X), 0, SIZEOF(X))) #define PUT_LONG(X,Y) (*(caddr_t)(X) = *(caddr_t)(&Y), \ *((caddr_t)(X)+1) = *((caddr_t)(&Y)+1), \ *((caddr_t)(X)+2) = *((caddr_t)(&Y)+2), \ *((caddr_t)(X)+3) = *((caddr_t)(&Y)+3)) #define PUT_ULONG PUT_LONG #define PUT_SHORT(X,Y) (*(caddr_t)(X) = *(caddr_t)(&Y), *((caddr_t)(X)+1) = *((caddr_t)(&Y)+1)) #define PUT_USHORT PUT_SHORT #define PUT_CHAR(X,Y) (*(caddr_t)(X) = *(caddr_t)(&Y)) #endif /*UNALIGNED_ACCESS_SUPPORTED*/ fis-gtm-V6.0-003/sr_port/copy_stack_frame.c0000644000032200000250000000403312201176176017512 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include #include "stack_frame.h" #include "mprof.h" #include "error.h" #include "glvn_pool.h" GBLREF stack_frame *frame_pointer; GBLREF unsigned char *stackbase ,*stacktop, *msp, *stackwarn; error_def(ERR_STACKCRIT); error_def(ERR_STACKOFLOW); void copy_stack_frame(void) { register stack_frame *sf; unsigned char *msp_save; msp_save = msp; sf = (stack_frame *)(msp -= SIZEOF(stack_frame)); if (msp <= stackwarn) { if (msp <= stacktop) { msp = msp_save; rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKOFLOW); } else rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKCRIT); } assert(msp < stackbase); assert((frame_pointer < frame_pointer->old_frame_pointer) || (NULL == frame_pointer->old_frame_pointer)); *sf = *frame_pointer; sf->old_frame_pointer = frame_pointer; sf->flags = 0; /* Don't propagate special flags */ sf->type &= SFT_ZINTR_OFF; /* Don't propagate special type - normally can't propagate but if $ZINTERRUPT frame is * rewritten by ZGOTO to a "regular" frame, this frame type *can* propagate. */ SET_GLVN_INDX(sf, GLVN_POOL_UNTOUCHED); sf->ret_value = NULL; sf->dollar_test = -1; /* initialize it with -1 for indication of not yet being used */ frame_pointer = sf; DBGEHND((stderr, "copy_stack_frame: Added stackframe at addr 0x"lvaddr" old-msp: 0x"lvaddr" new-msp: 0x"lvaddr"\n", sf, msp_save, msp)); assert((frame_pointer < frame_pointer->old_frame_pointer) || (NULL == frame_pointer->old_frame_pointer)); } void copy_stack_frame_sp(void) { copy_stack_frame(); new_prof_frame(TRUE); } fis-gtm-V6.0-003/sr_port/cre_jnl_file.c0000644000032200000250000005071212201176154016615 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_stat.h" #if defined(UNIX) #include "gtm_fcntl.h" #include "gtm_unistd.h" #include "eintr_wrappers.h" #include "gtm_permissions.h" #if defined(__MVS__) #include "gtm_zos_io.h" #endif #elif defined(VMS) #include #include #include #include "iosb_disk.h" #endif #include "gtm_file_stat.h" #include "gtm_rename.h" #include "error.h" #include "gdsroot.h" #include "gdsbt.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "gtmio.h" #include "util.h" #include "gtmmsg.h" #include "send_msg.h" #include "iosp.h" #include "repl_sp.h" #include "is_file_identical.h" #include "jnl_get_checksum.h" #include "gtmimagename.h" #include "get_fs_block_size.h" #include "wbox_test_init.h" #include "gt_timer.h" #include "anticipatory_freeze.h" /* Note : Now all system error messages are issued here. So callers do not need to issue them again */ #define STATUS_MSG(info) \ { \ if (SS_NORMAL != info->status2) \ { \ if (IS_GTM_IMAGE) \ send_msg(VARLSTCNT(12) ERR_JNLCRESTATUS, 7, CALLFROM, info->jnl_len, info->jnl, \ info->fn_len, info->fn, info->status, 0, info->status2); \ else \ gtm_putmsg(VARLSTCNT1(11) ERR_JNLCRESTATUS, 7, CALLFROM, info->jnl_len, info->jnl,\ info->fn_len, info->fn, info->status, PUT_SYS_ERRNO(info->status2)); \ } else if (SS_NORMAL != info->status) \ { \ if (IS_GTM_IMAGE) \ send_msg(VARLSTCNT(10) ERR_JNLCRESTATUS, 7, CALLFROM, info->jnl_len, \ info->jnl, info->fn_len, info->fn, info->status); \ else \ gtm_putmsg(VARLSTCNT(10) ERR_JNLCRESTATUS, 7, CALLFROM, info->jnl_len, \ info->jnl, info->fn_len, info->fn, info->status); \ } \ } #define RETURN_ON_ERROR(info) \ if (SYSCALL_ERROR(info->status) || SYSCALL_ERROR(info->status2)) \ { \ int status; \ F_CLOSE(channel, status);/* resets "channel" to FD_INVALID */ \ if (NULL != jrecbuf_base) \ { \ free(jrecbuf_base); \ jrecbuf_base = NULL; \ } \ return EXIT_ERR; \ } #if defined(VMS) #define ZERO_SIZE_IN_BLOCKS 127 /* 127 is RMS maximum blocks / write */ #define ZERO_SIZE (ZERO_SIZE_IN_BLOCKS * DISK_BLOCK_SIZE) #endif GBLREF jnl_gbls_t jgbl; GBLREF boolean_t mupip_jnl_recover; GBLREF jnl_process_vector *prc_vec; ZOS_ONLY(error_def(ERR_BADTAG);) error_def(ERR_FILERENAME); error_def(ERR_JNLCRESTATUS); error_def(ERR_JNLFNF); error_def(ERR_PERMGENFAIL); error_def(ERR_PREMATEOF); error_def(ERR_RENAMEFAIL); error_def(ERR_TEXT); /* Create a journal file from info. * If necessary, it renames journal file of same name. * Note: jgbl.gbl_jrec_time must be set by callers */ uint4 cre_jnl_file(jnl_create_info *info) { mstr filestr; int org_fn_len, rename_fn_len, fstat; char *org_fn, rename_fn[MAX_FN_LEN]; boolean_t no_rename; assert(0 != jgbl.gbl_jrec_time); if (!info->no_rename) /* ***MAY*** be rename is required */ { no_rename = FALSE; if (SS_NORMAL != (info->status = prepare_unique_name((char *)info->jnl, info->jnl_len, "", "", rename_fn, &rename_fn_len, jgbl.gbl_jrec_time, &info->status2))) { no_rename = TRUE; } else { filestr.addr = (char *)info->jnl; filestr.len = info->jnl_len; if (FILE_PRESENT != (fstat = gtm_file_stat(&filestr, NULL, NULL, FALSE, (uint4 *)&info->status))) { if (FILE_NOT_FOUND != fstat) { STATUS_MSG(info); return EXIT_ERR; } if (IS_GTM_IMAGE) send_msg(VARLSTCNT(4) ERR_JNLFNF, 2, filestr.len, filestr.addr); else gtm_putmsg(VARLSTCNT(4) ERR_JNLFNF, 2, filestr.len, filestr.addr); no_rename = TRUE; } /* Note if info->no_prev_link == TRUE, we do not keep previous link, though rename can happen */ if (JNL_ENABLED(info) && !info->no_prev_link) { memcpy(info->prev_jnl, rename_fn, rename_fn_len + 1); info->prev_jnl_len = rename_fn_len; } else assert(info->no_prev_link); } if (no_rename) { STATUS_MSG(info); info->status = info->status2 = SS_NORMAL; info->no_rename = TRUE; /* We wanted to rename, but not required anymore */ info->no_prev_link = TRUE; /* No rename => no prev_link */ } } /* else we know for sure rename is not required */ return (cre_jnl_file_common(info, rename_fn, rename_fn_len)); } /* This creates info->jnl and if (!info->no_rename) then it renames existing info->jnl to be rename_fn */ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_len) { jnl_file_header *header; unsigned char hdr_base[JNL_HDR_LEN + MAX_IO_BLOCK_SIZE]; struct_jrec_pfin *pfin_record; struct_jrec_pini *pini_record; struct_jrec_epoch *epoch_record; struct_jrec_eof *eof_record; unsigned char *create_fn, fn_buff[MAX_FN_LEN]; int create_fn_len, cre_jnl_rec_size, status, write_size, jrecbufbase_size; fd_type channel; char *jrecbuf, *jrecbuf_base; gd_id jnlfile_id; # ifdef VMS struct FAB fab; struct NAM nam; char es_buffer[MAX_FN_LEN], name_buffer[MAX_FN_LEN]; uint4 blk, block, zero_size; io_status_block_disk iosb; # else struct stat stat_buf; int fstat_res; ZOS_ONLY(int realfiletag;) int stat_res; int group_id; struct stat sb; int perm; struct perm_diag_data pdd; # endif int idx; trans_num db_tn; uint4 temp_offset, temp_checksum, pfin_offset, eof_offset; uint4 jnl_fs_block_size; jrecbuf = NULL; if (info->no_rename) { /* The only cases where no-renaming is possible are as follows * (i) MUPIP SET JOURNAL where the new journal file name is different from the current journal file name * (ii) For MUPIP BACKUP, MUPIP SET JOURNAL, GT.M Runtime and forw_phase_recovery, * in case the current journal file does not exist (due to some abnormal condition). * But in this case we cut the link and hence info->no_prev_link should be TRUE. * The assert below tries to capture this as much as possible without introducing any new global variables. */ assert((IS_MUPIP_IMAGE && !jgbl.forw_phase_recovery) || (IS_GTM_IMAGE && info->no_prev_link)); create_fn_len = info->jnl_len; create_fn = info->jnl; assert(0 == create_fn[create_fn_len]); } else { create_fn = &fn_buff[0]; if (SS_NORMAL != (info->status = prepare_unique_name((char *)info->jnl, (int)info->jnl_len, "", EXT_NEW, (char *)create_fn, &create_fn_len, 0, &info->status2))) { STATUS_MSG(info); return EXIT_ERR; } } # ifdef UNIX OPENFILE3((char *)create_fn, O_CREAT | O_EXCL | O_RDWR, 0600, channel); if (-1 == channel) { info->status = errno; STATUS_MSG(info); return EXIT_ERR; } # ifdef __MVS__ if (-1 == gtm_zos_set_tag(channel, TAG_BINARY, TAG_NOTTEXT, TAG_FORCE, &realfiletag)) TAG_POLICY_SEND_MSG((char *)create_fn, errno, realfiletag, TAG_BINARY); # endif FSTAT_FILE(channel, &stat_buf, fstat_res); if (-1 == fstat_res) { info->status = errno; STATUS_MSG(info); F_CLOSE(channel, status); return EXIT_ERR; } /* check database file again. It was checked earlier so should still be ok. */ STAT_FILE((sm_c_ptr_t)info->fn, &sb, stat_res); if (-1 == stat_res) { info->status = errno; STATUS_MSG(info); F_CLOSE(channel, status); return EXIT_ERR; } /* setup new group and permissions if indicated by the security rules. */ if (gtm_set_group_and_perm(&sb, &group_id, &perm, PERM_FILE, &pdd) < 0) { send_msg(VARLSTCNT(6+PERMGENDIAG_ARG_COUNT) ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("journal file"), RTS_ERROR_STRING(info->fn), PERMGENDIAG_ARGS(pdd)); if (IS_GTM_IMAGE) rts_error(VARLSTCNT(6+PERMGENDIAG_ARG_COUNT) ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("journal file"), RTS_ERROR_STRING(info->fn), PERMGENDIAG_ARGS(pdd)); else gtm_putmsg(VARLSTCNT(6+PERMGENDIAG_ARG_COUNT) ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("journal file"), RTS_ERROR_STRING(info->fn), PERMGENDIAG_ARGS(pdd)); F_CLOSE(channel, status); return EXIT_ERR; } /* if group not the same then change group of temporary file */ if ((-1 != group_id) && (group_id != stat_buf.st_gid) && (-1 == fchown(channel, -1, group_id))) { info->status = errno; STATUS_MSG(info); F_CLOSE(channel, status); return EXIT_ERR; } if (-1 == FCHMOD(channel, perm)) { info->status = errno; STATUS_MSG(info); F_CLOSE(channel, status); /* resets "channel" to FD_INVALID */ return EXIT_ERR; } jnl_fs_block_size = get_fs_block_size(channel); /* We need to write the journal file header, followed by pini/epoch/pfin/eof records followed by 0-padding * to ensure the final size of the journal file is filesystem-block-size aligned. * To have a "jnl_fs_block_size" aligned buffer that is also a multiple of jnl_fs_block_size long, * we need to allocate the needed size + 2 * jnl_fs_block_size. This will leave up to jnl_fs_block_size * before the actual "used" part for alignment plus enough left after the "used" part to make up a buffer * to write that is a multiple of jnl_fs_block_size. */ jrecbufbase_size = PINI_RECLEN + EPOCH_RECLEN + PFIN_RECLEN + EOF_RECLEN + (2 * jnl_fs_block_size); jrecbuf_base = malloc(jrecbufbase_size); jrecbuf = (char *)ROUND_UP2((uintszofptr_t)jrecbuf_base, jnl_fs_block_size); memset(jrecbuf, 0, jnl_fs_block_size); set_gdid_from_stat(&jnlfile_id, &stat_buf); # else nam = cc$rms_nam; nam.nam$l_rsa = name_buffer; nam.nam$b_rss = SIZEOF(name_buffer); nam.nam$l_esa = es_buffer; nam.nam$b_ess = SIZEOF(es_buffer); nam.nam$b_nop = NAM$M_NOCONCEAL; fab = cc$rms_fab; fab.fab$l_nam = &nam; fab.fab$b_org = FAB$C_SEQ; fab.fab$b_rfm = FAB$C_FIX; fab.fab$l_fop = FAB$M_UFO | FAB$M_MXV | FAB$M_CBT; fab.fab$b_fac = FAB$M_GET | FAB$M_PUT | FAB$M_BIO; fab.fab$b_shr = FAB$M_SHRGET | FAB$M_SHRPUT | FAB$M_UPI | FAB$M_NIL; fab.fab$w_mrs = DISK_BLOCK_SIZE; fab.fab$l_alq = info->alloc; fab.fab$w_deq = info->extend; fab.fab$l_fna = create_fn; fab.fab$b_fns = create_fn_len; info->status = sys$create(&fab); if (0 == (info->status & 1)) { info->status2 = fab.fab$l_stv; /* store secondary status information */ STATUS_MSG(info); return EXIT_ERR; } channel = fab.fab$l_stv; jrecbufbase_size = ZERO_SIZE; jrecbuf_base = jrecbuf = malloc(ZERO_SIZE); memset(jrecbuf, 0, ZERO_SIZE); block = (JNL_HDR_LEN >> LOG2_DISK_BLOCK_SIZE); assert(block * DISK_BLOCK_SIZE == JNL_HDR_LEN); for (blk = block; blk < info->alloc; blk += ZERO_SIZE_IN_BLOCKS) { zero_size = (blk + ZERO_SIZE_IN_BLOCKS <= info->alloc) ? ZERO_SIZE : (info->alloc - blk) * DISK_BLOCK_SIZE; JNL_DO_FILE_WRITE(NULL, NULL, channel, blk * DISK_BLOCK_SIZE, jrecbuf, zero_size, info->status, info->status2); STATUS_MSG(info); RETURN_ON_ERROR(info); } memcpy(jnlfile_id.dvi, &nam.nam$t_dvi, SIZEOF(jnlfile_id.dvi)); memcpy(jnlfile_id.did, &nam.nam$w_did, SIZEOF(jnlfile_id.did)); memcpy(jnlfile_id.fid, &nam.nam$w_fid, SIZEOF(jnlfile_id.fid)); jnl_fs_block_size = get_fs_block_size(channel); # endif info->checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&jnlfile_id, SIZEOF(gd_id)); /* Journal file header size relies on this assert */ assert(256 == GTMCRYPT_RESERVED_HASH_LEN); header = (jnl_file_header *)(ROUND_UP2((uintszofptr_t)hdr_base, jnl_fs_block_size)); /* We have already saved previous journal file name in info */ jfh_from_jnl_info(info, header); header->recover_interrupted = mupip_jnl_recover; assert(ROUND_UP2(JNL_HDR_LEN, jnl_fs_block_size) == JNL_HDR_LEN); assert((unsigned char *)header + JNL_HDR_LEN <= ARRAYTOP(hdr_base)); /* Although the real journal file header is REAL_JNL_HDR_LEN, we write the entire journal file header * including padding (64K in Unix) so we write 0-padding instead of some garbage. Not necessary * but makes analysis of journal file using dump utilities (like od) much easier. Also 0-initialization * might help us in the future when we add some fields in the file header. The cost of the extra padding * write is not so much since it is only once per journal file at creation time. All future writes of the * file header write only the real file header and not the 0-padding. */ JNL_DO_FILE_WRITE(info->csa, create_fn, channel, 0, header, JNL_HDR_LEN, info->status, info->status2); STATUS_MSG(info); RETURN_ON_ERROR(info); assert(DISK_BLOCK_SIZE >= EPOCH_RECLEN + EOF_RECLEN + PFIN_RECLEN + PINI_RECLEN); pini_record = (struct_jrec_pini *)&jrecbuf[0]; pini_record->prefix.jrec_type = JRT_PINI; pini_record->prefix.forwptr = pini_record->suffix.backptr = PINI_RECLEN; db_tn = info->csd->trans_hist.curr_tn; pini_record->prefix.tn = db_tn; pini_record->prefix.pini_addr = JNL_HDR_LEN; pini_record->prefix.time = jgbl.gbl_jrec_time; /* callers must set it */ pini_record->suffix.suffix_code = JNL_REC_SUFFIX_CODE; assert(prc_vec); memcpy((unsigned char*)&pini_record->process_vector[CURR_JPV], (unsigned char*)prc_vec, SIZEOF(jnl_process_vector)); /* Already process_vector[ORIG_JPV] is memset 0 */ pini_record->filler = 0; pini_record->prefix.checksum = INIT_CHECKSUM_SEED; temp_checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)pini_record, SIZEOF(struct_jrec_pini)); temp_offset = JNL_HDR_LEN; ADJUST_CHECKSUM(temp_checksum, temp_offset, temp_checksum); ADJUST_CHECKSUM(temp_checksum, info->checksum, pini_record->prefix.checksum); /* EPOCHs are written unconditionally in Unix while they are written only for BEFORE_IMAGE in VMS */ if (JNL_HAS_EPOCH(info)) { epoch_record = (struct_jrec_epoch *)&jrecbuf[PINI_RECLEN]; epoch_record->prefix.jrec_type = JRT_EPOCH; epoch_record->prefix.forwptr = epoch_record->suffix.backptr = EPOCH_RECLEN; epoch_record->prefix.tn = db_tn; epoch_record->prefix.pini_addr = JNL_HDR_LEN; epoch_record->prefix.time = jgbl.gbl_jrec_time; epoch_record->blks_to_upgrd = info->blks_to_upgrd; epoch_record->free_blocks = info->free_blocks; epoch_record->total_blks = info->total_blks; epoch_record->fully_upgraded = info->csd->fully_upgraded; epoch_record->suffix.suffix_code = JNL_REC_SUFFIX_CODE; epoch_record->jnl_seqno = info->reg_seqno; UNIX_ONLY( for (idx = 0; idx < MAX_SUPPL_STRMS; idx++) epoch_record->strm_seqno[idx] = info->csd->strm_reg_seqno[idx]; if (jgbl.forw_phase_recovery) { /* If MUPIP JOURNAL -ROLLBACK, might need some adjustment. See macro definition for comments */ MUR_ADJUST_STRM_REG_SEQNO_IF_NEEDED(info->csd, epoch_record->strm_seqno); } ) VMS_ONLY( for (idx = 0; idx < MAX_SUPPL_STRMS; idx++) assert(0 == epoch_record->strm_seqno[idx]); /* should have been zeroed already by above memset */ ) epoch_record->filler = 0; epoch_record->prefix.checksum = INIT_CHECKSUM_SEED; temp_checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)epoch_record, SIZEOF(struct_jrec_epoch)); temp_offset = JNL_HDR_LEN + PINI_RECLEN; ADJUST_CHECKSUM(temp_checksum, temp_offset, temp_checksum); ADJUST_CHECKSUM(temp_checksum, info->checksum, epoch_record->prefix.checksum); pfin_record = (struct_jrec_pfin *)&jrecbuf[PINI_RECLEN + EPOCH_RECLEN]; pfin_offset = JNL_HDR_LEN + PINI_RECLEN + EPOCH_RECLEN; eof_record = (struct_jrec_eof *)&jrecbuf[PINI_RECLEN + EPOCH_RECLEN + PFIN_RECLEN]; eof_offset = JNL_HDR_LEN + PINI_RECLEN + EPOCH_RECLEN + PFIN_RECLEN; cre_jnl_rec_size = PINI_RECLEN + EPOCH_RECLEN + PFIN_RECLEN + EOF_RECLEN; } else { pfin_record = (struct_jrec_pfin *)&jrecbuf[PINI_RECLEN]; pfin_offset = JNL_HDR_LEN + PINI_RECLEN; eof_record = (struct_jrec_eof *)&jrecbuf[PINI_RECLEN + PFIN_RECLEN]; eof_offset = JNL_HDR_LEN + PINI_RECLEN + PFIN_RECLEN; cre_jnl_rec_size = PINI_RECLEN + PFIN_RECLEN + EOF_RECLEN; } pfin_record->prefix.jrec_type = JRT_PFIN; pfin_record->prefix.forwptr = pfin_record->suffix.backptr = PFIN_RECLEN; pfin_record->prefix.tn = db_tn; pfin_record->prefix.pini_addr = JNL_HDR_LEN; pfin_record->prefix.time = jgbl.gbl_jrec_time; pfin_record->suffix.suffix_code = JNL_REC_SUFFIX_CODE; pfin_record->filler = 0; pfin_record->prefix.checksum = INIT_CHECKSUM_SEED; temp_checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)pfin_record, SIZEOF(struct_jrec_pfin)); ADJUST_CHECKSUM(temp_checksum, pfin_offset, temp_checksum); ADJUST_CHECKSUM(temp_checksum, info->checksum, pfin_record->prefix.checksum); eof_record->prefix.jrec_type = JRT_EOF; eof_record->prefix.forwptr = eof_record->suffix.backptr = EOF_RECLEN; eof_record->prefix.tn = db_tn; eof_record->prefix.pini_addr = JNL_HDR_LEN; eof_record->prefix.time = jgbl.gbl_jrec_time; QWASSIGN(eof_record->jnl_seqno, info->reg_seqno); eof_record->suffix.suffix_code = JNL_REC_SUFFIX_CODE; eof_record->filler = 0; eof_record->prefix.checksum = INIT_CHECKSUM_SEED; temp_checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)eof_record, SIZEOF(struct_jrec_eof)); ADJUST_CHECKSUM(temp_checksum, eof_offset, temp_checksum); ADJUST_CHECKSUM(temp_checksum, info->checksum, eof_record->prefix.checksum); /* Assert that the journal file header and journal records are all in sync with respect to the db tn. */ assert(header->bov_tn == db_tn); assert(header->eov_tn == db_tn); /* Write the journal records, but also 0-fill the tail of the journal file enough to fill * an aligned filesystem-block-size boundary. Take into account that the file header is already written. */ write_size = ROUND_UP2((JNL_HDR_LEN + cre_jnl_rec_size), jnl_fs_block_size) - JNL_HDR_LEN; assert((jrecbuf + write_size) <= (jrecbuf_base + jrecbufbase_size)); /* Assert that initial virtual-size of the journal file (which is nothing but the journal allocation) * gives us enough space to keep the journal file header + padding + PINI/PFIN/EPOCH/EOF records. * Do the assertion in units of 512-byte blocks as that keeps the values well under 4G. Keeping the * units in bytes causes the highest autoswitchlimit value to round up to 4G effectively becoming 0 * on certain platforms and therefore failing the assert. */ assert(ROUND_UP2(header->virtual_size, jnl_fs_block_size/DISK_BLOCK_SIZE) > DIVIDE_ROUND_UP(JNL_HDR_LEN + write_size, DISK_BLOCK_SIZE)); JNL_DO_FILE_WRITE(info->csa, create_fn, channel, JNL_HDR_LEN, jrecbuf, write_size, info->status, info->status2); STATUS_MSG(info); RETURN_ON_ERROR(info); UNIX_ONLY(GTM_JNL_FSYNC(info->csa, channel, status);) F_CLOSE(channel, status); /* resets "channel" to FD_INVALID */ free(jrecbuf_base); jrecbuf_base = NULL; if (info->no_rename) return EXIT_NRM; /* Say, info->jnl = a.mjl * So system will have a.mjl and a.mjl_new for a crash before the following call * Following does rename of a.mjl to a.mjl_timestamp. * So system will have a.mjl_timestamp and a.mjl_new for a crash after this call */ WAIT_FOR_REPL_INST_UNFREEZE_SAFE(info->csa); /* wait for instance freeze before journal file renames */ if (SS_NORMAL != (info->status = gtm_rename((char *)info->jnl, (int)info->jnl_len, (char *)rename_fn, rename_fn_len, &info->status2))) { if (IS_GTM_IMAGE) send_msg(VARLSTCNT(6) ERR_RENAMEFAIL, 4, info->jnl_len, info->jnl, rename_fn_len, rename_fn); else gtm_putmsg(VARLSTCNT(6) ERR_RENAMEFAIL, 4, info->jnl_len, info->jnl, rename_fn_len, rename_fn); STATUS_MSG(info); return EXIT_ERR; } /* Following does rename of a.mjl_new to a.mjl. * So system will have a.mjl_timestamp as previous generation and a.mjl as new/current journal file */ WAIT_FOR_REPL_INST_UNFREEZE_SAFE(info->csa); /* wait for instance freeze before journal file renames */ if (SS_NORMAL != (info->status = gtm_rename((char *)create_fn, create_fn_len, (char *)info->jnl, (int)info->jnl_len, &info->status2))) { if (IS_GTM_IMAGE) send_msg(VARLSTCNT(6) ERR_RENAMEFAIL, 4, info->jnl_len, info->jnl, rename_fn_len, rename_fn); else gtm_putmsg(VARLSTCNT(6) ERR_RENAMEFAIL, 4, info->jnl_len, info->jnl, rename_fn_len, rename_fn); STATUS_MSG(info); return EXIT_ERR; } if (IS_GTM_IMAGE) send_msg(VARLSTCNT (6) ERR_FILERENAME, 4, info->jnl_len, info->jnl, rename_fn_len, rename_fn); else gtm_putmsg(VARLSTCNT (6) ERR_FILERENAME, 4, info->jnl_len, info->jnl, rename_fn_len, rename_fn); DEBUG_ONLY( if (gtm_white_box_test_case_enabled && (WBTEST_JNL_CREATE_INTERRUPT == gtm_white_box_test_case_number)) { UNIX_ONLY(DBGFPF((stderr, "CRE_JNL_FILE: started a wait\n"))); /* this white-box test is for UNIX */ LONG_SLEEP(600); assert(FALSE); /* Should be killed before that */ } ) return EXIT_NRM; } fis-gtm-V6.0-003/sr_port/cre_jnl_file_intrpt_rename.c0000644000032200000250000000725212201176154021545 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_rename.h" #include "gtm_file_remove.h" #include "gtm_file_stat.h" #include "gtmmsg.h" #include "iosp.h" #include "gdsroot.h" #include "gdsbt.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "send_msg.h" #include "gtmimagename.h" void cre_jnl_file_intrpt_rename(int fn_len, sm_uc_ptr_t fn) { mstr filestr; int status1, status2, ext_new_jnl_fn_len; uint4 status, ustatus; unsigned char ext_new_jnl_fn[MAX_FN_LEN]; error_def(ERR_FILEPARSE); error_def(ERR_RENAMEFAIL); error_def(ERR_FILEDELFAIL); error_def(ERR_FILEDEL); error_def(ERR_FILERENAME); filestr.addr = (char *)fn; filestr.len = fn_len; prepare_unique_name((char *)fn, fn_len, "", EXT_NEW, (char *)ext_new_jnl_fn, &ext_new_jnl_fn_len, 0, &ustatus); assert(SS_NORMAL == ustatus); status1 = gtm_file_stat(&filestr, NULL, NULL, FALSE, &ustatus); if (FILE_STAT_ERROR == status1) { if (IS_GTM_IMAGE) send_msg(VARLSTCNT(5) ERR_FILEPARSE, 2, filestr.len, filestr.addr, ustatus); else gtm_putmsg(VARLSTCNT(5) ERR_FILEPARSE, 2, filestr.len, filestr.addr, ustatus); return; } filestr.addr = (char *)ext_new_jnl_fn; filestr.len = ext_new_jnl_fn_len; status2 = gtm_file_stat(&filestr, NULL, NULL, FALSE, &ustatus); if (FILE_STAT_ERROR == status2) { if (IS_GTM_IMAGE) send_msg(VARLSTCNT(5) ERR_FILEPARSE, 2, filestr.len, filestr.addr, ustatus); else gtm_putmsg(VARLSTCNT(5) ERR_FILEPARSE, 2, filestr.len, filestr.addr, ustatus); return; } if (FILE_NOT_FOUND == status1) { if (FILE_PRESENT == status2) { status = gtm_rename(filestr.addr, (int)filestr.len, (char *)fn, fn_len, &ustatus); if (SYSCALL_ERROR(status)) { if (IS_GTM_IMAGE) { VMS_ONLY(send_msg(VARLSTCNT(8) ERR_RENAMEFAIL, 4, filestr.len, filestr.addr, fn_len, fn, status, ustatus);) UNIX_ONLY(send_msg(VARLSTCNT(7) ERR_RENAMEFAIL, 4, filestr.len, filestr.addr, fn_len, fn, status);) } else { VMS_ONLY(gtm_putmsg(VARLSTCNT(8) ERR_RENAMEFAIL, 4, filestr.len, filestr.addr, fn_len, fn, status, ustatus);) UNIX_ONLY(gtm_putmsg(VARLSTCNT(7) ERR_RENAMEFAIL, 4, filestr.len, filestr.addr, fn_len, fn, status);) } } else { if (IS_GTM_IMAGE) send_msg(VARLSTCNT(6) ERR_FILERENAME, 4, (int)filestr.len, filestr.addr, fn_len, fn); else gtm_putmsg(VARLSTCNT(6) ERR_FILERENAME, 4, filestr.len, filestr.addr, fn_len, fn); } } } else { if (FILE_PRESENT == status2) { status = gtm_file_remove(filestr.addr, (int)filestr.len, &ustatus); if (SYSCALL_ERROR(status)) { if (IS_GTM_IMAGE) { VMS_ONLY(send_msg(VARLSTCNT(6) ERR_FILEDELFAIL, 2, filestr.len, filestr.addr, status, ustatus);) UNIX_ONLY(send_msg(VARLSTCNT(5) ERR_FILEDELFAIL, 2, filestr.len, filestr.addr, status);) } else { VMS_ONLY(gtm_putmsg(VARLSTCNT(6) ERR_FILEDELFAIL, 2, filestr.len, filestr.addr, status, ustatus);) UNIX_ONLY(gtm_putmsg(VARLSTCNT(5) ERR_FILEDELFAIL, 2, filestr.len, filestr.addr, status);) } } else { if (IS_GTM_IMAGE) send_msg(VARLSTCNT(4) ERR_FILEDEL, 2, filestr.len, filestr.addr); else gtm_putmsg(VARLSTCNT(4) ERR_FILEDEL, 2, filestr.len, filestr.addr); } } } } fis-gtm-V6.0-003/sr_port/cre_private_code_copy.c0000644000032200000250000000340712201176176020534 0ustar librarygtc/**************************************************************** * * * Copyright 2002, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "iosp.h" #include "error.h" #include #include "inst_flush.h" #include "private_code_copy.h" #include "stack_frame.h" #include "gtm_text_alloc.h" #include "gtm_string.h" CONDITION_HANDLER(cre_priv_ch) { error_def(UNIX_ONLY(ERR_MEMORY) VMS_ONLY(ERR_VMSMEMORY);) START_CH; if (SIGNAL == UNIX_ONLY(ERR_MEMORY) VMS_ONLY(ERR_VMSMEMORY)) { UNWIND(NULL, NULL); /* ignore "lack-of-memory" error, rather not set breakpoint than error out in such a case */ } NEXTCH; } uint4 cre_private_code_copy(rhdtyp *rtn) { unsigned char *new_ptext; int code_size; error_def(UNIX_ONLY(ERR_MEMORY) VMS_ONLY(ERR_VMSMEMORY);) #ifdef USHBIN_SUPPORTED assert(NULL != rtn->shlib_handle); /* don't need private copy if not shared */ assert(NULL == rtn->shared_ptext_adr); /* if already private, we shouldn't be calling this routine */ code_size = (int)(rtn->ptext_end_adr - rtn->ptext_adr) ; ESTABLISH_RET(cre_priv_ch, UNIX_ONLY(ERR_MEMORY) VMS_ONLY(ERR_VMSMEMORY)); new_ptext = GTM_TEXT_ALLOC(code_size); REVERT; memcpy(new_ptext, rtn->ptext_adr, code_size); adjust_frames(rtn->ptext_adr, rtn->ptext_end_adr, new_ptext); rtn->shared_ptext_adr = rtn->ptext_adr; rtn->ptext_adr = new_ptext; rtn->ptext_end_adr = new_ptext + code_size; inst_flush(new_ptext, code_size); #endif return SS_NORMAL; } fis-gtm-V6.0-003/sr_port/create_dummy_gbldir.c0000644000032200000250000001015412201176154020177 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "gtm_string.h" #include "gtm_stdio.h" #include "gtm_fcntl.h" #include "gtm_unistd.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "mlkdef.h" #include "filestruct.h" #include "gbldirnam.h" #include "hashtab_mname.h" #include "hashtab.h" #ifdef GTM64 #define SAVE_ADDR_REGION \ { \ int4 *tmp = (int *)&(addr->regions); \ *int4_ptr++ = *tmp; \ int4_ptr++; \ } #else /* GTM64 */ #define SAVE_ADDR_REGION \ *int4_ptr++ = (int4)addr->regions; #endif /* GTM64 */ static gdr_name *gdr_name_head; gd_addr *create_dummy_gbldir(void) { header_struct *header; gd_addr *addr; gdr_name *name; gd_binding *map, *map_top; gd_region *region; gd_region *region_top; gd_segment *segment; int4 *int4_ptr; uint4 t_offset, size; size = SIZEOF(header_struct) + SIZEOF(gd_addr) + 3 * SIZEOF(gd_binding) + 1 * SIZEOF(gd_region) + 1 * SIZEOF(gd_segment); header = (header_struct *)malloc(ROUND_UP(size, DISK_BLOCK_SIZE)); memset(header, 0, ROUND_UP(size, DISK_BLOCK_SIZE)); header->filesize = size; size = ROUND_UP(size, DISK_BLOCK_SIZE); memcpy(header->label, GDE_LABEL_LITERAL, SIZEOF(GDE_LABEL_LITERAL)); addr = (gd_addr *)((char *)header + SIZEOF(header_struct)); addr->max_rec_size = 256; addr->maps = (gd_binding*)((UINTPTR_T)addr + SIZEOF(gd_addr)); addr->n_maps = 3; addr->regions = (gd_region*)((INTPTR_T)(addr->maps) + 3 * SIZEOF(gd_binding)); addr->n_regions = 1; addr->segments = (gd_segment*)((INTPTR_T)(addr->regions) + SIZEOF(gd_region)); addr->n_segments = 1; addr->link = 0; addr->tab_ptr = 0; addr->id = 0; addr->local_locks = 0; addr->end = (UINTPTR_T)(addr->segments + 1 * SIZEOF(gd_segment)); int4_ptr = (int4*)(addr->maps); *int4_ptr++ = 0x232FFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; SAVE_ADDR_REGION *int4_ptr++ = 0x24FFFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; SAVE_ADDR_REGION *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; *int4_ptr++ = 0xFFFFFFFF; SAVE_ADDR_REGION region = (gd_region*)(addr->regions); segment = (gd_segment*)(addr->segments); region->rname_len = 7; memcpy(region->rname,"DEFAULT",7); for (map = addr->maps, map_top = map + addr->n_maps; map < map_top ; map++) { t_offset = map->reg.offset; map->reg.addr = (gd_region *)((char *)addr + t_offset); } for (region = addr->regions, region_top = region + addr->n_regions; region < region_top ; region++) { t_offset = region->dyn.offset; region->dyn.addr = (gd_segment *)((char *)addr + t_offset); } /* Should be using gd_id_ptr_t below, but ok for now since malloc won't return > 4G * and since addr->id is a 4-byte pointer only until we change the format of the global directory. */ addr->id = (gd_id *)malloc(SIZEOF(gd_id)); memset(addr->id, 0, SIZEOF(gd_id)); addr->tab_ptr = (hash_table_mname *)malloc(SIZEOF(hash_table_mname)); init_hashtab_mname((hash_table_mname *)addr->tab_ptr, 0, HASHTAB_NO_COMPACT, HASHTAB_NO_SPARE_TABLE ); name = (gdr_name *)malloc(SIZEOF(gdr_name)); MALLOC_CPY_LIT(name->name.addr, "DUMMY.GLD"); if (gdr_name_head) name->link = (gdr_name *)gdr_name_head; else name->link = 0; gdr_name_head = name; gdr_name_head->gd_ptr = addr; return addr; } fis-gtm-V6.0-003/sr_port/create_fatal_error_zshow_dmp.c0000644000032200000250000000344212201176154022115 0ustar librarygtc/**************************************************************** * * * Copyright 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #ifdef VMS #include #endif #ifdef UNIX #include #endif #include "error.h" #include "jobexam_process.h" #include "gtmdbglvl.h" #include "create_fatal_error_zshow_dmp.h" LITDEF mval gtmfatal_error_filename = DEFINE_MVAL_LITERAL(MV_STR, 0, 0, SIZEOF(GTMFATAL_ERROR_DUMP_FILENAME) - 1, GTMFATAL_ERROR_DUMP_FILENAME, 0, 0); GBLREF int4 exi_condition; GBLREF uint4 gtmDebugLevel; GBLREF volatile int4 gtmMallocDepth; /* On VMS, SIGNAL is sig->chf$l_sig_name (a parameter to mdb_condition_handler) so needs to be passed in */ void create_fatal_error_zshow_dmp(int4 signal, boolean_t repeat_error) { mval dummy_mval; int4 save_SIGNAL; /* On UNIX this is exi_condition */ UNIX_ONLY(PRN_ERROR); if (UNIX_ONLY(0 == gtmMallocDepth && ((SIGBUS != exi_condition && SIGSEGV != exi_condition) || (GDL_ZSHOWDumpOnSignal & gtmDebugLevel))) VMS_ONLY((SS$_ACCVIO != signal) || (GDL_ZSHOWDumpOnSignal & gtmDebugLevel))) { /* If dumpable condition, create traceback file of M stack info and such */ /* On Unix, we need to push out our error now before we potentially overlay it in jobexam_process() */ /* Create dump file */ UNIX_ONLY(save_SIGNAL = SIGNAL); /* Signal might be modified by jobexam_process() */ jobexam_process((mval *)>mfatal_error_filename, &dummy_mval); UNIX_ONLY(SIGNAL = save_SIGNAL); } } fis-gtm-V6.0-003/sr_port/create_fatal_error_zshow_dmp.h0000644000032200000250000000123712201176154022122 0ustar librarygtc/**************************************************************** * * * Copyright 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CREATE_FATAL_ERROR_ZSHOW_DMP_H_ # define CREATE_FATAL_ERROR_ZSHOW_DMP_H_ #define GTMFATAL_ERROR_DUMP_FILENAME "GTM_FATAL_ERROR" void create_fatal_error_zshow_dmp(int4 signal, boolean_t repeat_error); #endif fis-gtm-V6.0-003/sr_port/create_temporaries.c0000644000032200000250000001045712201176154020061 0ustar librarygtc/**************************************************************** * * * Copyright 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_ctype.h" #include "compiler.h" #include "mdq.h" #include "opcode.h" #include "indir_enum.h" #include "nametabtyp.h" #include "toktyp.h" #include "funsvn.h" #include "mmemory.h" #include "advancewindow.h" #include "namelook.h" #include "cmd.h" #include "svnames.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "alias.h" #include "glvn_pool.h" #ifdef UNICODE_SUPPORTED #include "gtm_utf8.h" #endif /* This function adds triples to the execution chain to store the values of subscripts (in glvns in compound SETs) * in temporaries (using OC_STOTEMP opcode). This function is only invoked when * a) The SET is a compound SET (i.e. there are multiple targets specified on the left side of the SET command). * b) Subscripts are specified in glvns which are targets of the SET. * e.g. set a=0,(a,array(a))=1 * The expected result of the above command as per the M-standard is that array(0) (not array(1)) gets set to 1. * That is, the value of the subscript "a" should be evaluated at the start of the compound SET before any sets happen * and should be used in any subscripts that refer to the name "a". * In the above example, since it is a compound SET and "a" is used in a subscript, we need to store the value of "a" * before the start of the compound SET (i.e.a=0) in a temporary and use that as the subscript for "array". * If in the above example the compound set was instead specified as set a=1,array(a)=1, the value of 1 gets substituted * when used in "array(a)". * This is where the compound set acts differently from a sequence of multiple sets. This is per the M-standard. * In the above example, the subscript used was also a target within the compound SET. It is possible that the * subscript is not also an individual target within the same compound SET. Even in that case, this function * will be called to store the subscript in temporaries (as we dont know at compile time if a particular * subscript is also used as a target within a compound SET). */ void create_temporaries(triple *sub, opctype put_oc) { oprtype *sb1; triple *s0, *s1; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(TREF(temp_subs)); assert(NULL != sub); sb1 = &sub->operand[1]; if ((OC_GVNAME == put_oc) || (OC_PUTINDX == put_oc) || (OC_SRCHINDX == put_oc)) { sub = sb1->oprval.tref; /* global name */ assert(OC_PARAMETER == sub->opcode); sb1 = &sub->operand[1]; } else if (OC_GVEXTNAM == put_oc) { sub = sb1->oprval.tref; /* first env */ assert(OC_PARAMETER == sub->opcode); sb1 = &sub->operand[0]; assert(TRIP_REF == sb1->oprclass); s0 = sb1->oprval.tref; if ((OC_GETINDX == s0->opcode) || (OC_VAR == s0->opcode)) { s1 = maketriple(OC_STOTEMP); s1->operand[0] = *sb1; *sb1 = put_tref(s1); s0 = s0->exorder.fl; dqins(s0->exorder.bl, exorder, s1); } sb1 = &sub->operand[1]; sub = sb1->oprval.tref; /* second env */ assert(OC_PARAMETER == sub->opcode); sb1 = &sub->operand[0]; assert(TRIP_REF == sb1->oprclass); s0 = sb1->oprval.tref; if ((OC_GETINDX == s0->opcode) || (OC_VAR == s0->opcode)) { s1 = maketriple(OC_STOTEMP); s1->operand[0] = *sb1; *sb1 = put_tref(s1); s0 = s0->exorder.fl; dqins(s0->exorder.bl, exorder, s1); } sb1 = &sub->operand[1]; sub = sb1->oprval.tref; /* global name */ assert(OC_PARAMETER == sub->opcode); sb1 = &sub->operand[1]; } while (sb1->oprclass) { assert(TRIP_REF == sb1->oprclass); sub = sb1->oprval.tref; assert(OC_PARAMETER == sub->opcode); sb1 = &sub->operand[0]; assert(TRIP_REF == sb1->oprclass); s0 = sb1->oprval.tref; if ((OC_GETINDX == s0->opcode) || (OC_VAR == s0->opcode)) { s1 = maketriple(OC_STOTEMP); s1->operand[0] = *sb1; *sb1 = put_tref(s1); s0 = s0->exorder.fl; dqins(s0->exorder.bl, exorder, s1); } sb1 = &sub->operand[1]; } } fis-gtm-V6.0-003/sr_port/crit_wake.h0000644000032200000250000000103112201176154016145 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __CRIT_WAKE_H__ #define __CRIT_WAKE_H__ int crit_wake(sm_uint_ptr_t pid); #endif fis-gtm-V6.0-003/sr_port/cryptdef.h0000644000032200000250000000237112201176154016025 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ typedef struct { uint4 sid[16]; uint4 exp_date; unsigned char gtm_serial[8]; } gtm_id_block; typedef struct { gtm_id_block plaintext; unsigned char key[SIZEOF(gtm_id_block)]; gtm_id_block cryptext; } gtm_id_struct; #define CRYPT_CHKSYSTEM { if (!licensed) \ { \ if ((lkid & 4) == 4) \ { \ GTMASSERT; \ } \ lkid++; \ } \ } #if defined (DEBUG) || defined (NOLICENSE) #define LP_LICENSED(a,b,c,d,e,f,g,h,i,j) 1 /* equivalent to SS$_NORMAL */ #if defined (VMS) #define LP_ACQUIRE(a,b,c,d) lp_id(d) #else #define LP_ACQUIRE(a,b,c,d) 1 #endif #define LP_CONFIRM(a,b) 1 #else #define LP_LICENSED(a,b,c,d,e,f,g,h,i,j) lp_licensed(a,b,c,d,e,f,g,h,i,j) #define LP_ACQUIRE(a,b,c,d) lp_acquire(a,b,c,d) #define LP_CONFIRM(a,b) lp_confirm(a,b) #endif fis-gtm-V6.0-003/sr_port/ctrlc_handler_dummy.c0000644000032200000250000000100212201176154020205 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "ctrlc_handler_dummy.h" void ctrlc_handler_dummy(void) { } fis-gtm-V6.0-003/sr_port/ctrlc_handler_dummy.h0000644000032200000250000000105212201176154020217 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __CTRLC_HANDLER_DUMMY_H__ #define __CTRLC_HANDLER_DUMMY_H__ void ctrlc_handler_dummy(void); #endif fis-gtm-V6.0-003/sr_port/cvtparm.c0000644000032200000250000000602712201176154015656 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "compiler.h" #include "stringpool.h" #include "io_params.h" #include "io.h" #include "iottdef.h" #include "cvtparm.h" #include "mvalconv.h" #include "cvttime.h" #include "cvtprot.h" GBLREF spdesc stringpool; LITREF unsigned char io_params_size[]; #define IOP_DESC(a,b,c,d,e) {d, e} LITDEF dev_ctl_struct dev_param_control[] = { #include "iop.h" }; #undef IOP_DESC int4 cvtparm(int iocode, mval *src, mval *dst) { error_def(ERR_DEVPARTOOBIG); error_def(ERR_DEVPARPROT); int4 status, nl, tim[2]; int siz, cnt, strlen; short ns; unsigned char *cp, msk; io_termmask lngmsk; assert(MV_DEFINED(src)); strlen = -1; siz = io_params_size[iocode]; ENSURE_STP_FREE_SPACE(siz + 1); switch(dev_param_control[iocode].source_type) { case IOP_SRC_INT: assert(siz == SIZEOF(int4) || siz == SIZEOF(short)); MV_FORCE_NUM(src); nl = MV_FORCE_INT(src); if (siz == SIZEOF(int4)) cp = (unsigned char *)&nl; else { assert (siz == SIZEOF(short)); ns = (short) nl; cp = (unsigned char *) &ns; } break; case IOP_SRC_STR: assert(siz == IOP_VAR_SIZE); MV_FORCE_STR(src); if (src->str.len > 255) /*one byte string lengths within a parameter string*/ return (int4) ERR_DEVPARTOOBIG; strlen = src->str.len; siz = strlen + SIZEOF(unsigned char); cp = (unsigned char *) src->str.addr; break; case IOP_SRC_MSK: MV_FORCE_STR(src); assert(siz == SIZEOF(int4)); nl = 0; for (cp = (unsigned char *) src->str.addr, cnt = src->str.len ; cnt > 0 ; cnt--) nl |= (1 << *cp++); cp = (unsigned char *) &nl; break; case IOP_SRC_LNGMSK: MV_FORCE_STR(src); assert(siz == SIZEOF(io_termmask)); memset(&lngmsk, 0, SIZEOF(io_termmask)); for (cp = (unsigned char *) src->str.addr, cnt = src->str.len ; cnt > 0 ; cnt--) { msk = *cp++; nl = msk / 32; lngmsk.mask[nl] |= (1 << (msk - (nl * 32))); } cp = (unsigned char *) &lngmsk; break; case IOP_SRC_PRO: assert(siz == SIZEOF(unsigned char)); MV_FORCE_STR(src); nl = cvtprot(src->str.addr, src->str.len); if (nl == -1) return (int4) ERR_DEVPARPROT; msk = nl; cp = &msk; break; case IOP_SRC_TIME: status = cvttime(src, tim); if ((status & 1) == 0) return status; siz = SIZEOF(tim) ; cp = (unsigned char *) tim ; break; default: assert(FALSE); } dst->mvtype = MV_STR; dst->str.addr = (char *) stringpool.free; dst->str.len = siz; if (strlen >= 0) { *stringpool.free++ = strlen; siz -= SIZEOF(char); } memcpy(stringpool.free, cp, siz); stringpool.free += siz; return 0; } fis-gtm-V6.0-003/sr_port/cvtparm.h0000644000032200000250000000110012201176154015646 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CVTPARM_INCLUDED #define CVTPARM_INCLUDED int4 cvtparm(int iocode, mval *src, mval *dst); #endif /* CVTPARM_INCLUDED */ fis-gtm-V6.0-003/sr_port/cvtprot.h0000644000032200000250000000102712201176155015704 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __CVTPROT_H__ #define __CVTPROT_H__ int cvtprot(char *cp, short cnt); #endif fis-gtm-V6.0-003/sr_port/cvttime.h0000644000032200000250000000106412201176155015657 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef CVTTIME_INCLUDED #define CVTTIME_INCLUDED int4 cvttime(mval *src, int4 *tim); #endif /* CVTTIME_INCLUDED */ fis-gtm-V6.0-003/sr_port/cws_insert.h0000644000032200000250000000643712201176155016375 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __CWS_INSERT_H__ #define __CWS_INSERT_H__ GBLREF hash_table_int4 cw_stagnate; GBLREF boolean_t cw_stagnate_reinitialized; /* Usually a process does not need the cw_stagnate hash table as it is used only in the final retry. * But CWS_RESET (to ensure the hashtable is reinitialized) is done in a lot of places and almost every transaction. * To avoid unnecessary overhead in the reset, we start from a small initial value for CWS_INITIAL_SIZE. * When necessary hash rounties will expand automatically. */ #define CWS_INITIAL_SIZE 4 /* Initialize the cw_stagnate hash-table */ #define CWS_INIT \ { \ if (0 == cw_stagnate.size) \ { \ init_hashtab_int4(&cw_stagnate, CWS_INITIAL_SIZE, HASHTAB_COMPACT, HASHTAB_SPARE_TABLE); \ cw_stagnate_reinitialized = TRUE; \ } \ } /* macro CWS_INSERT appends a block_id onto an hashtable of block_id's * cw_stagnate is the address of the hashtable * it is initially NULL * CWS_INITIAL_SIZE is the initial size of the hash table * table is enlarged each time it fills up * The hashtable is allocated the first time this routine is* called, and the contents of it are reset by calling cws_reset * in t_begin, t_begin_crit and tp_hist. The hashtable expands by itself. */ GBLREF boolean_t mu_reorg_in_swap_blk; GBLREF int4 cws_reorg_remove_index; GBLREF block_id cws_reorg_remove_array[]; #define CWS_INSERT(block) \ { \ ht_ent_int4 *dummy; \ boolean_t new_entry; \ \ cw_stagnate_reinitialized = FALSE; \ new_entry = add_hashtab_int4(&cw_stagnate, (uint4 *)(&block), HT_VALUE_DUMMY, &dummy); \ /* If in mu_swap_blk and a new entry was added to the hashtable, note this block number \ * in the cws_reorg_remove_array for later removal in the next iteration of the for \ * loop in "mu_swap_blk" (see mu_swap_blk.c for more detail). \ */ \ if (mu_reorg_in_swap_blk && new_entry) \ { \ CWS_REORG_INSERT(block); \ } \ } #define CWS_REORG_REMOVE_ARRAYSIZE ((4 * MAX_BT_DEPTH) + 2) /* see mu_swap_blk.c for detail on this calculation */ #define CWS_REORG_REMOVE_MAXINDEX (CWS_REORG_REMOVE_ARRAYSIZE - 1) #define CWS_REORG_INSERT(blk) \ { \ assert(cws_reorg_remove_index < CWS_REORG_REMOVE_MAXINDEX); \ cws_reorg_remove_array[++cws_reorg_remove_index] = (blk); \ } /* the use of the variable cw_stagnate_reinitialized to optimize CWS_RESET assumes that all calls to * add_hashtab_int4() are done through CWS_INSERT macro. */ #define CWS_RESET \ { /* if a transaction did not use cw_stagnate hash table, there is no need to reset it */ \ if (!cw_stagnate_reinitialized) \ { \ reinitialize_hashtab_int4(&cw_stagnate); \ cw_stagnate_reinitialized = TRUE; \ } \ } #endif fis-gtm-V6.0-003/sr_port/d.mpt0000644000032200000250000000152112201176155014776 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1987, 2003 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %D ;GT.M %D utility - write current date as [d]d-mmm-yy ;invoke at INT to set %DAT to the current date as [d]d-mmm-yy ;invoke at FUNC as an extrinsic special variable ;supplied for illustration and compatibility ;use of inline code is easy and efficient ; w $$FUNC() q INT s %DAT=$$FUNC() q FUNC() n h,monyear s monyear=$S($ZDATEFORM:"-MON-YEAR",1:"-MON-YY") s h=$h q +$zd(h,"DD")_$zd(h,monyear) fis-gtm-V6.0-003/sr_port/date.mpt0000644000032200000250000000545212201176155015477 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1987, 2003 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %DATE ;GT.M %DATE utility - returns $H format date in %DN ;invoke at INT with %DS to by pass interactive prompt ;formats accepted include: ; days as 1 or 2 digits ; months as 1 or 2 digits or as unique alpha prefixes ; years as 2 or 4 digits ; "T" or "t" for today with an optional +/- offset ; except for the +/- offset any non alphameric character(s) ; are accepted as delimiters ; numeric months must precede days ; alpha months may precede or follow days ; a missing year is defaulted to this year ; null input is defaulted to today ; n %DS f r !,"Date: ",%DS s %DN=$$FUNC(%DS) q:%DN'="" w " - invalid date" q INT s %DN=$$FUNC($g(%DS)) q FUNC(dt) n cp,dd,dir,ilen,mm,tok,tp,yy,dh,zd i $g(dt)="" q +$H s ilen=$l(dt)+1,cp=1 d advance i $e("TODAY",1,$l(tok))=$tr(tok,"today","TODAY") q $$incr(+$H) i $e("TOMORROW",1,$l(tok))=$tr(tok,"tomrw","TOMRW") q $$incr($H+1) i $e("YESTERDAY",1,$l(tok))=$tr(tok,"yestrday","YESTRDAY") q $$incr($H-1) i dir?1A s mm=$$amon(tok) q:mm=0 "" d advance s dd=tok q $$date i tok<1 q "" s mm=tok d advance i dir?1A s dd=mm,mm=$$amon(tok) q:mm=0 "" q $$date i mm<13 s dd=tok q $$date q "" ; advance f cp=cp:1:ilen q:$e(dt,cp)?1AN s dir=$e(dt,cp) i dir?1A f tp=cp+1:1:ilen q:$e(dt,tp)'?1A e i dir?1N f tp=cp+1:1:ilen q:$e(dt,tp)'?1N e s tok="" q s tok=$e(dt,cp,tp-1) s cp=tp q incr(h) f cp=cp:1:ilen q:"+-"[$e(dt,cp) i cp'=ilen s dd=$e(dt,cp) d advance i dir?.1N,cp=ilen q h+(dd_tok) q h ; amon(mm) s mm=$tr(mm,"abcdefghijklmnopqrstuvwxyz","ABCDEFGHIJKLMNOPQRSTUVWXYZ") i $l(mm)<3,"AJM"[tok,"JAPAU"'[mm q 0 n mon s mon="\JANUARY \FEBRUARY \MARCH \APRIL \MAY \JUNE \JULY \AUGUST \SEPTEMBER\OCTOBER \NOVEMBER \DECEMBER" q $f(mon,("\"_mm))+8\10 ; date() i dd<1 q "" d advance i dir'?.1N q "" s zd=$ZDATEFORM s yy=tok i yy="" s yy=$zd($h,"YEAR") i cp'=ilen q "" i $l(yy)<3 d . s dh=$H . s yy=yy+(100*$S('zd:19,(zd>1840)&($L(zd)=4):($E(zd,1,2)+$S($E(zd,3,4)'>yy:0,1:1)),1:$E($ZDATE(dh,"YEAR"),1,2))) ; 20th rolling current century i dd>$s(+mm'=2:$e(303232332323,mm)+28,yy#4:28,yy#100:29,yy#400:28,1:29) q "" n cc,dat s dat=yy-1841,mm=mm-1,cc=1 i dat<0 s dd=dd-1,cc=-1 s dat=dat\4*1461+(dat#4-$s(dat'<0:0,1:4)*365)+(mm*30)+$e(10112234455,mm)+dd-(yy-1800\100-(yy-1600\400)) i yy#4,mm>1 s dat=dat-cc i yy#100=0,mm<2,yy#400 s dat=dat+cc q dat fis-gtm-V6.0-003/sr_port/db_auto_upgrade.c0000644000032200000250000001617112201176155017330 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "gdscc.h" #include "gdsblkops.h" #include "filestruct.h" #include "io.h" #include "jnl.h" #include "mutex.h" #include "wcs_phase2_commit_wait.h" #include "gvcst_protos.h" /* for gvcst_init_sysops prototype */ GBLREF boolean_t dse_running; error_def(ERR_DBBADUPGRDSTATE); void db_auto_upgrade(gd_region *reg) { /* detect unitialized file header fields for this version of GT.M and do a mini auto-upgrade, initializing such fields * to default values in the new GT.M version */ sgmnt_addrs *csa; sgmnt_data_ptr_t csd; assert(NULL != reg); if (NULL == reg) return; csa = &FILE_INFO(reg)->s_addrs; csd = csa->hdr; assert(NULL != csd); if (NULL == csd) return; if (0 == csd->mutex_spin_parms.mutex_hard_spin_count) csd->mutex_spin_parms.mutex_hard_spin_count = MUTEX_HARD_SPIN_COUNT; if (0 == csd->mutex_spin_parms.mutex_sleep_spin_count) csd->mutex_spin_parms.mutex_sleep_spin_count = MUTEX_SLEEP_SPIN_COUNT; /* zero is a legitimate value for csd->mutex_spin_parms.mutex_spin_sleep_mask; so can't detect if need re-initialization */ INIT_NUM_CRIT_ENTRY_IF_NEEDED(csd); /* Auto upgrade based on minor database version number. This code currently only does auto upgrade and does not * do auto downgrade although that certainly is possible to implement if necessary. For now, if the current version * is at a lower level than the minor db version, we do nothing. * * Note the purpose of the minor_dbver field is so that some part of gtm (either runtime, or conversion utility) some * time and several versions down the road from now knows by looking at this field what fields in the fileheader are * valid so it is important that the minor db version be updated each time the fileheader is updated and this routine * correspondingly updated. SE 5/2006. */ if (csd->minor_dbver < GDSMVCURR) { /* In general, the method for adding new versions is: * 1) If there are no automatic updates for this version, it is optional to add the version to the switch * statement below. Those there are more for example at this time (through V53000). * 2) Update (or add) a case for the previous version to update any necessary fields. */ if (!csd->opened_by_gtmv53 && !csd->db_got_to_v5_once) { csd->opened_by_gtmv53 = TRUE; /* This is a case of a database that has been used by a pre-V53 version of GT.M that did not contain * the fix (C9H07-002873). At this point, the database might contain RECYCLED blocks that are a mix of * a) Those blocks that were RECYCLED at the time of the MUPIP UPGRADE from V4 to V5. * b) Those blocks that became RECYCLED due to M-kills in V5. * It is only (a) that we have to mark as FREE as it might contain too-full v4 format blocks. But there * is no way to distinguish the two. So we mark both (a) and (b) as FREE. This will mean no PBLKs written * for (b) and hence no backward journal recovery possible to a point before the start of the REORG UPGRADE. * We force a MUPIP REORG UPGRADE rerun (to mark RECYCLED blocks FREE) by setting fully_upgraded to FALSE. * Note that this does not need to be done for databases created by a V5 version (C9I05-002987). */ if (MASTER_MAP_SIZE_V4 == csd->master_map_len) { csd->fully_upgraded = FALSE; csd->reorg_upgrd_dwngrd_restart_block = 0; /* reorg upgrade should restart from block 0 */ /* Ensure reorg_db_fmt_start_tn and desired_db_format_tn are set to different * values so fresh reorg upgrade can set fully_upgraded to TRUE once it is done. */ csd->reorg_db_fmt_start_tn = 0; csd->desired_db_format_tn = 1; } else csd->db_got_to_v5_once = TRUE; /* db was created by V5 so safe to set this */ } /* When adding a new minor version, the following template should be maintained * a) Remove the penultimate 'break' * b) Remove the assert(FALSE) in the last case (most recent minor version) * c) If there are any file header fields added in the new minor version, initialize the fields to default values * in the last case * d) Add a new case with the new minor version * e) Add assert(FALSE) and break (like it was before) */ switch(csd->minor_dbver) { /* Note that handling for any fields introduced in a version will not go in the "switch-case" block * of code introduced for the new version but will go in the PREVIOUS "switch-case" block. */ case GDSMV51000: /* Multi-site replication available */ case GDSMV52000: /* Unicode */ case GDSMV53000: /* M-Itanium release */ gvstats_rec_upgrade(csa); /* Move GVSTATS information to new place in file header */ case GDSMV54002: /* GT.M V54002B introduced jnl_eov_tn for backward recovery */ csd->jnl_eovtn = csd->trans_hist.curr_tn; case GDSMV54002B: /* GT.M V55000 introduced strm_reg_seqno, save_strm_reg_seqno, intrpt_recov_resync_strm_seqno * AND obsoleted dualsite_resync_seqno. For new fields, we are guaranteed they are * zero (in formerly unused sections of the file header) so no need for any initialization. * For obsoleted fields, it would be good to clear them here so we dont run into issues later. */ UNIX_ONLY(csd->filler_seqno = 0;) /* was "dualsite_resync_seqno" in pre-V55000 versions */ /* In addition, V55000 introduced before_trunc_total_blks for MUPIP REORG -TRUNCATE. * Since it is a new field no initialization necessary. */ case GDSMV55000: UNIX_ONLY(csd->freeze_on_fail = FALSE;) UNIX_ONLY(csd->span_node_absent = TRUE;) UNIX_ONLY(csd->maxkeysz_assured = FALSE;) case GDSMV60000: case GDSMV60001: /* GT.M V60002 introduced mutex_spin_parms.mutex_que_entry_space_size */ NUM_CRIT_ENTRY(csd) = DEFAULT_NUM_CRIT_ENTRY; break; case GDSMV60002: /* Nothing to do for this version since it is GDSMVCURR for now. */ assert(FALSE); /* When this assert fails, it means a new GDSMV* was created, */ break; /* so a new "case" needs to be added BEFORE the assert. */ } csd->minor_dbver = GDSMVCURR; if (0 == csd->wcs_phase2_commit_wait_spincnt) csd->wcs_phase2_commit_wait_spincnt = WCS_PHASE2_COMMIT_DEFAULT_SPINCNT; } csd->last_mdb_ver = GDSMVCURR; if (csd->fully_upgraded && !csd->db_got_to_v5_once) { /* Database is fully upgraded but the db_got_to_v5_once field says different. * Don't know how that could happen, except with DSE which can change both the database file header fields */ assert(!dse_running); csd->db_got_to_v5_once = TRUE; /* fix it in PRO */ send_msg(VARLSTCNT(6) ERR_DBBADUPGRDSTATE, 4, REG_LEN_STR(reg), DB_LEN_STR(reg)); } return; } fis-gtm-V6.0-003/sr_port/db_common_init.c0000644000032200000250000000341112201176155017155 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* This is the routine used by both db_init() and mu_rndwn_file() for initializing appropriate structures. */ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "iosp.h" #include "jnl.h" GBLREF jnl_process_vector *prc_vec; void db_common_init(gd_region *reg, sgmnt_addrs *csa, sgmnt_data_ptr_t csd) { csa->bmm = MM_ADDR(csd); csa->reorg_last_dest = 0; /* For mupip reorg swap operation */ csa->region = reg; /* initialize the back-link */ reg->max_rec_size = csd->max_rec_size; reg->max_key_size = csd->max_key_size; reg->null_subs = csd->null_subs; reg->std_null_coll = csd->std_null_coll; reg->jnl_state = csd->jnl_state; reg->jnl_file_len = csd->jnl_file_len; /* journal file name length */ memcpy(reg->jnl_file_name, csd->jnl_file_name, reg->jnl_file_len); /* journal file name */ reg->jnl_alq = csd->jnl_alq; reg->jnl_deq = csd->jnl_deq; reg->jnl_buffer_size = csd->jnl_buffer_size; reg->jnl_before_image = csd->jnl_before_image; bt_init(csa); /* Initialization of prc_vec is done even for no journaling. gtcm uses this always. Others might need it too. */ if (NULL == prc_vec) { prc_vec = (jnl_process_vector *)malloc(SIZEOF(jnl_process_vector)); jnl_prc_vector(prc_vec); } } fis-gtm-V6.0-003/sr_port/db_csh_get.c0000644000032200000250000000642712201176155016270 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsbgtr.h" #include "cache.h" #include "hashtab.h" /* needed for cws_insert.h */ #include "hashtab_int4.h" /* needed for cws_insert.h */ #include "longset.h" /* needed for cws_insert.h */ #include "cws_insert.h" GBLREF sgmnt_addrs *cs_addrs; GBLREF unsigned int t_tries; GBLREF boolean_t mu_reorg_process; #define ENOUGH_TRIES_TO_FALL_BACK 17 /* This function returns a pointer to the cache_rec entry, NULL if not found, or CR_INVALID if the hash table is corrupt */ cache_rec_ptr_t db_csh_get(block_id block) /* block number to look up */ { register sgmnt_addrs *csa; sgmnt_data_ptr_t csd; cache_rec_ptr_t cr, cr_hash_base; int blk_hash, lcnt, ocnt, hmax; # ifdef DEBUG cache_rec_ptr_t cr_low, cr_high; # endif csa = cs_addrs; csd = csa->hdr; assert(dba_mm != csd->acc_meth); hmax = csd->bt_buckets; blk_hash = (block % hmax); DEBUG_ONLY(cr_low = &csa->acc_meth.bg.cache_state->cache_array[0];) DEBUG_ONLY(cr_high = cr_low + csd->bt_buckets + csd->n_bts;) cr_hash_base = csa->acc_meth.bg.cache_state->cache_array + blk_hash; ocnt = 0; do { cr = cr_hash_base; assert((0 == cr->blk) || (BT_QUEHEAD == cr->blk)); lcnt = hmax; do { cr = (cache_rec_ptr_t)((sm_uc_ptr_t)cr + cr->blkque.fl); assert(!CR_NOT_ALIGNED(cr, cr_low) && !CR_NOT_IN_RANGE(cr, cr_low, cr_high)); if (BT_QUEHEAD == cr->blk) { /* We have reached the end of the queue, validate we have run the queue * back around to the same queue header or we'll need to retry because the * queue changed on us. */ if (cr == cr_hash_base) return (cache_rec_ptr_t)NULL; break; /* Retry - something changed */ } if ((CR_BLKEMPTY != cr->blk) && ((cr->blk % hmax) != blk_hash)) break; /* Retry - something changed */ assert(!csa->now_crit || (0 != cr->blkque.fl) && (0 != cr->blkque.bl)); if (cr->blk == block) { if (CDB_STAGNATE <= t_tries || mu_reorg_process) CWS_INSERT(block); /* setting refer outside of crit may not prevent its replacement, but that's an * inefficiency, not a tragedy because of concurrency checks in t_end or tp_tend; * the real problem is to ensure that the cache_rec layout is such that this * assignment does not damage other fields. */ cr->refer = TRUE; return cr; } lcnt--; } while (lcnt); ocnt++; /* We rarely expect to come here, hence it is considered better to recompute the maximum value of ocnt (for the * termination check) instead of storing it in a local variable at the beginning of the do loop */ } while (ocnt < (csa->now_crit ? 1 : ENOUGH_TRIES_TO_FALL_BACK)); BG_TRACE_PRO_ANY(csa, db_csh_get_too_many_loops); return (TRUE == csa->now_crit ? (cache_rec_ptr_t)CR_NOTVALID : (cache_rec_ptr_t) NULL); } fis-gtm-V6.0-003/sr_port/db_csh_getn.c0000644000032200000250000003603712201176155016446 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include /* needed for VSIG_ATOMIC_T */ #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdskill.h" #include "gdscc.h" #include "filestruct.h" #include "interlock.h" #include "jnl.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab.h" /* needed for cws_insert.h */ #include "hashtab_int4.h" /* needed for tp.h and cws_insert.h */ #include "tp.h" #include "gdsbgtr.h" #include "min_max.h" #include "sleep_cnt.h" #include "send_msg.h" #include "relqop.h" #include "is_proc_alive.h" #include "cache.h" #include "longset.h" /* needed for cws_insert.h */ #include "cws_insert.h" #include "wcs_sleep.h" #include "wcs_get_space.h" #include "wcs_timer_start.h" #include "add_inter.h" #include "wbox_test_init.h" #include "have_crit.h" #include "memcoherency.h" #include "gtm_c_stack_trace.h" #include "anticipatory_freeze.h" GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF uint4 process_id; GBLREF uint4 image_count; GBLREF unsigned int t_tries; GBLREF uint4 dollar_tlevel; GBLREF sgm_info *sgm_info_ptr; GBLREF boolean_t mu_reorg_process; #ifdef UNIX GBLREF uint4 update_trans; GBLREF jnlpool_addrs jnlpool; #endif #define TRACE_AND_SLEEP(ocnt) \ { \ if (1 == ocnt) \ { \ BG_TRACE_PRO(db_csh_getn_rip_wait); \ first_r_epid = latest_r_epid; \ } \ wcs_sleep(ocnt); \ } error_def(ERR_BUFRDTIMEOUT); error_def(ERR_INVALIDRIP); cache_rec_ptr_t db_csh_getn(block_id block) { cache_rec_ptr_t hdr, q0, start_cr, cr; bt_rec_ptr_t bt; unsigned int lcnt, ocnt; int rip, max_ent, pass1, pass2, pass3; int4 flsh_trigger; uint4 first_r_epid, latest_r_epid; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; srch_blk_status *tp_srch_status; ht_ent_int4 *tabent; boolean_t dont_flush_buff; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; csa = cs_addrs; csd = csa->hdr; assert(dba_mm != csd->acc_meth); assert(csa->now_crit); assert(csa == &FILE_INFO(gv_cur_region)->s_addrs); max_ent = csd->n_bts; cr = (cache_rec_ptr_t)GDS_REL2ABS(csa->nl->cur_lru_cache_rec_off); hdr = csa->acc_meth.bg.cache_state->cache_array + (block % csd->bt_buckets); start_cr = csa->acc_meth.bg.cache_state->cache_array + csd->bt_buckets; pass1 = max_ent; /* skip referred or dirty or read-into cache records */ pass2 = 2 * max_ent; /* skip referred cache records */ pass3 = 3 * max_ent; /* skip nothing */ dont_flush_buff = gv_cur_region->read_only UNIX_ONLY(|| (!(dollar_tlevel ? sgm_info_ptr->update_trans : update_trans) && IS_REPL_INST_FROZEN) ); INCR_DB_CSH_COUNTER(csa, n_db_csh_getns, 1); DEFER_INTERRUPTS(INTRPT_IN_DB_CSH_GETN); for (lcnt = 0; ; lcnt++) { if (lcnt > pass3) { BG_TRACE_PRO(wc_blocked_db_csh_getn_loopexceed); assert(FALSE); break; } cr++; if (cr == start_cr + max_ent) cr = start_cr; VMS_ONLY( if ((lcnt == pass1) || (lcnt == pass2)) wcs_wtfini(gv_cur_region); ) if (cr->refer && (lcnt < pass2)) { /* in passes 1 & 2, set refer to FALSE and skip; in the third pass attempt reuse even if TRUE == refer */ cr->refer = FALSE; continue; } if (cr->in_cw_set || cr->in_tend) { /* some process already has this pinned for reading and/or updating. skip it. */ cr->refer = TRUE; continue; } if (CDB_STAGNATE <= t_tries || mu_reorg_process) { /* Prevent stepping on self when crit for entire transaction. * This is done by looking up in sgm_info_ptr->blk_in_use and cw_stagnate for presence of the block. * The following two hashtable lookups are not similar, since in TP, sgm_info_ptr->blks_in_use * is updated to the latest cw_stagnate list of blocks only in "tp_hist". * Also note that the lookup in sgm_info_ptr->blks_in_use reuses blocks that don't have cse's. * This is to allow big-read TP transactions which may use up more than the available global buffers. * There is one issue here in that a block that has been only read till now may be stepped upon here * but may later be needed for update. It is handled by updating the block's corresponding * entry in the set of histories (sgm_info_ptr->first_tp_hist[index] structure) to hold the * "cr" and "cycle" of the t_qread done for the block when it was intended to be changed for the * first time within the transaction since otherwise the transaction would restart due to a * cdb_sc_lostcr status. Note that "tn" (read_tn of the block) in the first_tp_hist will still * remain the "tn" when the block was first read within this transaction to ensure the block * hasn't been modified since the start of the transaction. Once we intend on changing the * block i.e. srch_blk_status->cse is non-NULL, we ensure in the code below not to step on it. * ["tp_hist" is the routine that updates the "cr", "cycle" and "tn" of the block]. * Note that usually in a transaction the first_tp_hist[] structure holds the "cr", "cycle", and "tn" * of the first t_qread of the block within that transaction. The above is the only exception. * Also note that for blocks in cw_stagnate (i.e. current TP mini-action), we don't reuse any of * them even if they don't have a cse. This is to ensure that the current action doesn't * encounter a restart due to cdb_sc_lostcr in "tp_hist" even in the fourth-retry. */ tp_srch_status = NULL; if (dollar_tlevel && (NULL != (tabent = lookup_hashtab_int4(sgm_info_ptr->blks_in_use, (uint4 *)&cr->blk))) && (tp_srch_status = (srch_blk_status *)tabent->value) && (tp_srch_status->cse)) { /* this process is already using the block - skip it */ cr->refer = TRUE; continue; } if (NULL != lookup_hashtab_int4(&cw_stagnate, (uint4 *)&cr->blk)) { /* this process is already using the block for the current gvcst_search - skip it */ cr->refer = TRUE; continue; } if (NULL != tp_srch_status) { /* About to reuse a buffer that is part of the read-set of the current TP transaction. * Reset clue as otherwise the next global reference of that global will use an outofdate clue. * Even though tp_srch_status is available after the sgm_info_ptr->blks_in_use hashtable check, * we dont want to reset the clue in case the cw_stagnate hashtable check causes the same cr * to be skipped from reuse. Hence the placement of this reset logic AFTER the cw_stagnate check. */ tp_srch_status->blk_target->clue.end = 0; } } if (cr->dirty) { /* Note that in Unix, it is possible that we see a stale value of cr->dirty (possible if a * concurrent "wcs_wtstart" has reset dirty to 0 but that update did not reach us yet). In this * case the call to "wcs_get_space" below will do the necessary memory barrier instructions * (through calls to "aswp") which will allow us to see the non-stale value of cr->dirty. * * It is also possible that cr->dirty is non-zero but < cr->flushed_dirty_tn. In this case, wcs_get_space * done below will return FALSE forcing a cache-rebuild which will fix this situation. * * In VMS, another process cannot be concurrently resetting cr->dirty to 0 as the resetting routine * is "wcs_wtfini" which is executed in crit which another process cannot be in as we are in crit now. */ if (dont_flush_buff) continue; if (lcnt < pass1) { if (!csa->timer && (csa->nl->wcs_timers < 1)) wcs_timer_start(gv_cur_region, FALSE); continue; } BG_TRACE_PRO(db_csh_getn_flush_dirty); if (FALSE == wcs_get_space(gv_cur_region, 0, cr)) { /* failed to flush it out - force a rebuild */ BG_TRACE_PRO(wc_blocked_db_csh_getn_wcsstarvewrt); assert(csa->nl->wc_blocked); /* only reason we currently know why wcs_get_space could fail */ assert(gtm_white_box_test_case_enabled); break; } assert(0 == cr->dirty); } UNIX_ONLY( /* the cache-record is not free for reuse until the write-latch value becomes LATCH_CLEAR. * In VMS, resetting the write-latch value occurs in "wcs_wtfini" which is in CRIT, we are fine. * In Unix, this resetting is done by "wcs_wtstart" which is out-of-crit. Therefore, we need to * wait for this value to be LATCH_CLEAR before reusing this cache-record. * Note that we are examining the write-latch-value without holding the interlock. It is ok to do * this because the only two routines that modify the latch value are "bg_update" and * "wcs_wtstart". The former cannot be concurrently executing because we are in crit. * The latter will not update the latch value unless this cache-record is dirty. But in this * case we would have most likely gone through the if (cr->dirty) check above. Most likely * because there is one rare possibility where a concurrent "wcs_wtstart" has set cr->dirty * to 0 but not yet cleared the latch. In that case we wait for the latch to be cleared. * In all other cases, nobody is modifying the latch since when we got crit and therefore * it is safe to observe the value of the latch without holding the interlock. */ if (LATCH_CLEAR != WRITE_LATCH_VAL(cr)) { /* possible if a concurrent "wcs_wtstart" has set cr->dirty to 0 but not yet * cleared the latch. this should be very rare though. */ if (lcnt < pass2) continue; /* try to find some other cache-record to reuse until the 3rd pass */ for (ocnt = 1; (MAXWRTLATCHWAIT >= ocnt) && (LATCH_CLEAR != WRITE_LATCH_VAL(cr)); ocnt++) wcs_sleep(SLEEP_WRTLATCHWAIT); /* since it is a short lock, sleep the minimum */ if (MAXWRTLATCHWAIT <= ocnt) { BG_TRACE_PRO(db_csh_getn_wrt_latch_stuck); assert(FALSE); continue; } } ) /* Note that before setting up a buffer for the requested block, we should make sure the cache-record's * read_in_progress is set. This is so that noone else in t_qread gets access to this empty buffer. * By setting up a buffer, it is meant assigning cr->blk in addition to inserting the cr in the blkques * through "shuffqth" below. * Note that "t_qread" has special code to handle read_in_progress */ LOCK_BUFF_FOR_READ(cr, rip); if (0 != rip) { if (lcnt < pass2) { /* someone is reading into this cache record. leave it for two passes. * this is because if somebody is reading it, it is most likely to be referred to very soon. * if we replace this, we will definitely be causing a restart for the reader. * instead of that, see if some other cache record fits in for us. */ RELEASE_BUFF_READ_LOCK(cr); continue; } for (ocnt = 1; 0 != rip && BUF_OWNER_STUCK >= ocnt; ocnt++) { RELEASE_BUFF_READ_LOCK(cr); /* The owner has been unable to complete the read - check for some things before going to sleep. * Since cr->r_epid can be changing concurrently, take a local copy before using it below, * particularly before calling is_proc_alive as we dont want to call it with a 0 r_epid. */ latest_r_epid = cr->r_epid; if (cr->read_in_progress < -1) { BG_TRACE_PRO(db_csh_getn_out_of_design); /* outside of design; clear to known state */ send_msg(VARLSTCNT(4) ERR_INVALIDRIP, 2, DB_LEN_STR(gv_cur_region)); assert(cr->r_epid == 0); cr->r_epid = 0; INTERLOCK_INIT(cr); } else if (0 != latest_r_epid) { if (is_proc_alive(latest_r_epid, cr->image_count)) { # ifdef DEBUG if ((BUF_OWNER_STUCK / 2) == ocnt) GET_C_STACK_FROM_SCRIPT("BUFRDTIMEOUT", process_id, latest_r_epid, ONCE); # endif TRACE_AND_SLEEP(ocnt); } else { cr->r_epid = 0; INTERLOCK_INIT(cr); /* Process gone, release that process's lock */ } } else { TRACE_AND_SLEEP(ocnt); } LOCK_BUFF_FOR_READ(cr, rip); } if ((BUF_OWNER_STUCK < ocnt) && (0 != rip)) { BG_TRACE_PRO(db_csh_getn_buf_owner_stuck); if (0 != latest_r_epid) { if (first_r_epid != latest_r_epid) GTMASSERT; GET_C_STACK_FROM_SCRIPT("BUFRDTIMEOUT", process_id, latest_r_epid, DEBUG_ONLY(TWICE) PRO_ONLY(ONCE)); RELEASE_BUFF_READ_LOCK(cr); send_msg(VARLSTCNT(8) ERR_BUFRDTIMEOUT, 6, process_id, cr->blk, cr, first_r_epid, DB_LEN_STR(gv_cur_region)); continue; } cr->r_epid = 0; INTERLOCK_INIT(cr); LOCK_BUFF_FOR_READ(cr, rip); assert(0 == rip); /* Since holding crit, we expect to get lock */ if (0 != rip) continue; /* We successfully obtained the lock so can fall out of this block */ } } assert(0 == rip); /* no other process "owns" the block */ if (CDB_STAGNATE <= t_tries || mu_reorg_process) { /* this should probably use cr->in_cw_set with a condition handler to cleanup */ CWS_INSERT(block); } assert(LATCH_CLEAR == WRITE_LATCH_VAL(cr)); /* got a block - set it up */ assert(0 == cr->epid); assert(0 == cr->r_epid); cr->r_epid = process_id; /* establish ownership */ cr->image_count = image_count; cr->blk = block; /* We want cr->read_in_progress to be locked BEFORE cr->cycle is incremented. t_qread relies on this order. * Enforce this order with a write memory barrier. Not doing so might cause the incremented cr->cycle to be * seen by another process even though it sees the unlocked state of cr->read_in_progress. This could cause * t_qread to incorrectly return with an uptodate cr->cycle even though the buffer is still being read in * from disk and this could cause db integ errors as validation (in t_end/tp_tend which relies on cr->cycle) * will detect no problems even though there is one. Note this memory barrier is still needed even though * there is a memory barrier connotation in the LOCK_BUFF_FOR_READ() macro above. LOCK_BUFF_FOR_READ() does * a read type memory barrier whereas here, we need a write barrier. */ SHM_WRITE_MEMORY_BARRIER; cr->cycle++; cr->jnl_addr = 0; cr->refer = TRUE; if (cr->bt_index != 0) { bt = (bt_rec_ptr_t)GDS_REL2ABS(cr->bt_index); bt->cache_index = CR_NOTVALID; cr->bt_index = 0; } q0 = (cache_rec_ptr_t)((sm_uc_ptr_t)cr + cr->blkque.fl); shuffqth((que_ent_ptr_t)q0, (que_ent_ptr_t)hdr); assert(0 == cr->dirty); csa->nl->cur_lru_cache_rec_off = GDS_ABS2REL(cr); if (lcnt > pass1) csa->nl->cache_hits = 0; csa->nl->cache_hits++; if (csa->nl->cache_hits > csd->n_bts) { flsh_trigger = csd->flush_trigger; csd->flush_trigger = MIN(flsh_trigger + MAX(flsh_trigger / STEP_FACTOR, 1), MAX_FLUSH_TRIGGER(csd->n_bts)); csa->nl->cache_hits = 0; } INCR_DB_CSH_COUNTER(csa, n_db_csh_getn_lcnt, lcnt); ENABLE_INTERRUPTS(INTRPT_IN_DB_CSH_GETN); return cr; } /* force a recover */ INCR_DB_CSH_COUNTER(csa, n_db_csh_getn_lcnt, lcnt); csa->nl->cur_lru_cache_rec_off = GDS_ABS2REL(cr); ENABLE_INTERRUPTS(INTRPT_IN_DB_CSH_GETN); return (cache_rec_ptr_t)CR_NOTVALID; } fis-gtm-V6.0-003/sr_port/db_csh_ini.c0000644000032200000250000000145612201176155016265 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" void db_csh_ini(sgmnt_addrs *csa) { assertpro(0 == ((INTPTR_T)csa->hdr & 7)); csa->acc_meth.bg.cache_state = (cache_que_heads_ptr_t)((sm_uc_ptr_t)csa->hdr + csa->nl->cache_off); assert(csa->acc_meth.bg.cache_state); return; } fis-gtm-V6.0-003/sr_port/db_csh_ref.c0000644000032200000250000000736412201176155016266 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "interlock.h" #include "lockconst.h" #include "longset.h" #include "relqop.h" #include "filestruct.h" #include "jnl.h" error_def(ERR_WCFAIL); GBLREF int4 process_id; #if defined(UNIX) && defined(DEBUG) GBLREF jnl_gbls_t jgbl; #endif /* Refresh the database cache records in the shared memory. If init = TRUE, do the longset and initialize all the latches and * forward and backward links. If init = FALSE, just increment the cycle and set the blk to CR_BLKEMPTY. */ void db_csh_ref(sgmnt_addrs *csa, boolean_t init) { sgmnt_data_ptr_t csd; node_local_ptr_t cnl; sm_uc_ptr_t bp, bp_top; cache_rec_ptr_t cr, cr_top, cr1; int4 buffer_size, rec_size; csd = csa->hdr; cnl = csa->nl; if (init) { SET_LATCH_GLOBAL(&cnl->wc_var_lock, LOCK_AVAILABLE); SET_LATCH_GLOBAL(&cnl->db_latch, LOCK_AVAILABLE); if (dba_mm == csd->acc_meth) return; longset((uchar_ptr_t)csa->acc_meth.bg.cache_state, SIZEOF(cache_que_heads) + (csd->bt_buckets + csd->n_bts - 1) * SIZEOF(cache_rec), 0); /* -1 since there is a cache_rec in cache_que_heads */ SET_LATCH_GLOBAL(&csa->acc_meth.bg.cache_state->cacheq_active.latch, LOCK_AVAILABLE); SET_LATCH_GLOBAL(&csa->acc_meth.bg.cache_state->cacheq_wip.latch, LOCK_AVAILABLE); } cr = cr1 = csa->acc_meth.bg.cache_state->cache_array; buffer_size = csd->blk_size; assert(buffer_size > 0); assert(0 == buffer_size % DISK_BLOCK_SIZE); rec_size = SIZEOF(cache_rec); for (cr_top = (cache_rec_ptr_t)((sm_uc_ptr_t)cr + rec_size * csd->bt_buckets); cr < cr_top; cr = (cache_rec_ptr_t)((sm_uc_ptr_t)cr + rec_size)) cr->blk = BT_QUEHEAD; cr_top = (cache_rec_ptr_t)((sm_uc_ptr_t)cr + rec_size * csd->n_bts); if (init) { cnl->cur_lru_cache_rec_off = GDS_ANY_ABS2REL(csa, cr); cnl->cache_hits = 0; } bp = (sm_uc_ptr_t)ROUND_UP((sm_ulong_t)cr_top, OS_PAGE_SIZE); bp_top = bp + (gtm_uint64_t)csd->n_bts * buffer_size; GTMCRYPT_ONLY( if (csd->is_encrypted) { /* In case of an encrypted database, bp_top is actually the beginning of the encrypted global buffer * array (an array maintained parallely with the regular unencrypted global buffer array. */ cnl->encrypt_glo_buff_off = (sm_off_t)((sm_uc_ptr_t)bp_top - (sm_uc_ptr_t)bp); } ) for (; cr < cr_top; cr = (cache_rec_ptr_t)((sm_uc_ptr_t)cr + rec_size), cr1 = (cache_rec_ptr_t)((sm_uc_ptr_t)cr1 + rec_size)) { if (init) INTERLOCK_INIT(cr); cr->cycle++; /* increment cycle whenever buffer's blk number changes (for tp_hist) */ cr->blk = CR_BLKEMPTY; /* Typically db_csh_ref is invoked from db_init (when creating shared memory afresh) in which case cr->bt_index * will be 0 (due to the memset). But, if db_csh_ref is invoked from online rollback where we are invalidating the * cache but do not do the longset (above), bt_index can be a non-zero value. Assert that and set it to zero since * we are invalidating the cache record anyways. */ assert((0 == cr->bt_index) UNIX_ONLY(|| jgbl.onlnrlbk)); cr->bt_index = 0; if (init) { assert(bp <= bp_top); cr->buffaddr = GDS_ANY_ABS2REL(csa, bp); bp += buffer_size; insqt((que_ent_ptr_t)cr, (que_ent_ptr_t)cr1); } cr->refer = FALSE; } cnl->wc_in_free = csd->n_bts; return; } fis-gtm-V6.0-003/sr_port/dbcertify.c0000644000032200000250000000622212201176155016153 0ustar librarygtc/**************************************************************** * * * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /**************************************************************** DBCERTIFY - main driver Parse arguments, invoke required phase routine. Note: Most routines in this utility are self-contained meaning they do not reference GT.M library routines (with some notable exceptions). This is because phase-1 is going to run against live V4 databases and the V5 compilation will be using V5 database structures. ****************************************************************/ #include "mdef.h" #include "gtm_ctype.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "gtm_unistd.h" #include "gtm_stdlib.h" #include #ifdef UNIX # include "continue_handler.h" # include "sig_init.h" #else # include "desblk.h" /* for desblk structure */ #endif #include "gdsroot.h" #include "v15_gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "v15_gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "v15_gdsfhead.h" #include "gdsblkops.h" #include "mupip_exit.h" #include "gtmimagename.h" #include "error.h" #include "iosp.h" #include "gtm_env_init.h" #include "dbcertify.h" #include "cli.h" #include "gtm_imagetype_init.h" #include "gtm_threadgbl_init.h" #include "wbox_test_init.h" GBLREF uint4 process_id; GBLREF boolean_t gtm_utf8_mode; #ifdef VMS GBLREF desblk exi_blk; GBLREF int4 exi_condition; #endif #ifdef UNIX GBLREF CLI_ENTRY dbcertify_cmd_ary[]; #endif GBLDEF phase_static_area *psa_gbl; /* Global anchor for static area */ #ifdef UNIX GBLDEF CLI_ENTRY *cmd_ary = &dbcertify_cmd_ary[0]; /* Define cmd_ary to be the DBCERTIFY specific cmd table */ #endif int UNIX_ONLY(main)VMS_ONLY(dbcertify)(int argc, char **argv) { DCL_THREADGBL_ACCESS; /* Initialization of scaffolding we run on */ GTM_THREADGBL_INIT; gtm_imagetype_init(DBCERTIFY_IMAGE); gtm_env_init(); gtm_utf8_mode = FALSE; /* Only ever runs in V4 database so NO utf8 mode -- ever */ psa_gbl = malloc(SIZEOF(*psa_gbl)); memset(psa_gbl, 0, SIZEOF(*psa_gbl)); UNIX_ONLY(err_init(dbcertify_base_ch)); UNIX_ONLY(sig_init(dbcertify_signal_handler, dbcertify_signal_handler, NULL, continue_handler)); VMS_ONLY(util_out_open(0)); VMS_ONLY(SET_EXIT_HANDLER(exi_blk, dbcertify_exit_handler, exi_condition)); /* Establish exit handler */ VMS_ONLY(ESTABLISH(dbcertify_base_ch)); process_id = getpid(); /* Structure checks .. */ assert((24 * 1024) == SIZEOF(v15_sgmnt_data)); /* Verify V4 file header hasn't suddenly increased for some odd reason */ OPERATOR_LOG_MSG; /* Platform dependent method to get the option scan going and invoke necessary driver routine */ dbcertify_parse_and_dispatch(argc, argv); return SS_NORMAL; } fis-gtm-V6.0-003/sr_port/dbcertify.h0000644000032200000250000004077012201176155016166 0ustar librarygtc/**************************************************************** * * * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef DBCERTIFY_H_INCLUDED #define DBCERTIFY_H_INCLUDED #include "gtm_stdio.h" #ifdef UNIX # include "mu_all_version_standalone.h" #endif #ifdef VMS # define OPTDELIM "/" # define DEFAULT_OUTFILE_SUFFIX "_DBCERTSCAN" # define TMPCMDFILSFX ".com" # define SETDISTLOGENV "$ DEFINE/NOLOG "GTM_DIST" " # define DSE_START "$ RUN "GTM_DIST":DSE.EXE" # define DSE_FIND_REG_ALL "FIND /REG" # define MUPIP_START "$ RUN "GTM_DIST":MUPIP.EXE" # define RUN_CMD "@" # define RESULT_ASGN "$ DEFINE SYS$OUTPUT " # define DUMPRSLTFILE "TYPE " # define RMS_OPEN_BIN ,"rfm=fix","mrs=512","ctx=bin" #else # define SHELL_START "#!/bin/sh" # define SETDISTLOGENV GTM_DIST"=" # define DSE_START_PIPE_RSLT1 "$"GTM_DIST"/dse << EOF > " # define DSE_START_PIPE_RSLT2 " 2>&1" # define OPTDELIM "-" # define DEFAULT_OUTFILE_SUFFIX ".dbcertscan" # define TMPCMDFILSFX ".sh" # define DSE_FIND_REG_ALL "find -reg" # define MUPIP_START "$"GTM_DIST"/mupip << EOF" # define RUN_CMD "./" # define DUMPRSLTFILE "cat " # define RMS_OPEN_BIN #endif #define DSE_BFLUSH "buffer_flush" #define DSE_QUIT "quit" #define DSE_OPEN_RSLT "OPEN "OPTDELIM"FILE="TMPRSLTFILE #define DSE_CLOSE_RSLT "CLOSE" #define DSE_PROMPT "DSE> " #define DSE_REG_LIST_START UNIX_ONLY(DSE_PROMPT)"List of global directory:" #define MUPIP_EXTEND "EXTEND " #define MUPIP_BLOCKS " "OPTDELIM"BLOCKS=" #define TMPFILEPFX "dbcmdx" #define TMPRSLTFILSFX ".out" #define MAX_IEB_CNT 10 /* The "maximum" key that we use to search for righthand children of gvtroot blocks is simply 0xFF, 0x00, 0x00. So we don't need much here.. */ #define MAX_DBC_KEY_SZ 3 /* A restart is triggered when, in the processing of a given block, we discover that some other block in its path needs to be dealt with first. Since the splitting of the higher (tree) level block will take care of anything else higher in the tree (that call may restart but it does not matter how deeply we nest, each level has its own restart counter), we should never need more than 1 restart but it is set to 3 for "cushion". SE 5/2005. */ #define MAX_RESTART_CNT 3 /* The version should be updated anytime the format of the header or underlying records is changed.. **NOTE ** Any change here require changes in v5cbsu.m. */ #define P1HDR_TAG "GTMDBC01" /* Worst case of max level of DT tree + max level of GVT tree plus if every block in a tree gets split plus each split block creates a block in a different bitmap. */ #define MAX_BLOCK_INFO_DEPTH (MAX_BT_DEPTH * 4) #define PREMATURE_EOF "Premature EOF on temporary results file. Command may have failed" enum gdsblk_usage {gdsblk_read = 1, gdsblk_update, gdsblk_create}; /* Note gdsblk_gvtleaf is used in v5cbsu.m so changes here must be reflected there ! */ enum gdsblk_type {gdsblk_gvtgeneric = 1, gdsblk_dtgeneric, gdsblk_gvtroot, gdsblk_gvtindex, gdsblk_gvtleaf, gdsblk_dtroot, gdsblk_dtindex, gdsblk_dtleaf, gdsblk_bitmap}; /* Structure defining the header of the phase 1 output file. Note the char fields in this structure use absolute lengths. This is because of the requirements that this structure be able to be read by the M program vb5cbsu. **NOTE ** Any changes here require changes in v5cbsu.m. */ typedef struct { unsigned char p1hdr_tag[8]; /* We are what we are */ v15_trans_num tn; /* TN at point we started reading blocks */ int4 blk_count; /* number of blocks recorded in this file (records) */ int4 tot_blocks; /* Total blocks we processed (used blocks) */ int4 dt_leaf_cnt; /* Block type counters */ int4 dt_index_cnt; int4 gvt_leaf_cnt; int4 gvt_index_cnt; unsigned char regname[V4_MAX_RN_LEN + 1]; /* Region name for DSE */ unsigned char dbfn[V4_MAX_FN_LEN + 1]; /* Database file name */ int4 uid_len; /* Length of following unique id field (varies across platforms, used by v5cbsu) */ unique_file_id unique_id; /* Make sure this DB doesn't move */ char fillx[32 - SIZEOF(unique_file_id)]; /* Fill out for variable size of unique_id */ char fill512[152]; /* Pad out to 512 for VMS oddities with fixed record IO and hdr rewrite */ } p1hdr; /* Structure defining the header of each record in the phase 1 output file. **NOTE ** Any changes here require changes in v5cbsu.m. */ typedef struct { v15_trans_num tn; /* TN of this block */ block_id blk_num; /* block id (number) for this block */ enum gdsblk_type blk_type; /* Block type */ int4 blk_levl; /* block level for type */ int4 akey_len; /* ASCII key length */ } p1rec; typedef struct { unsigned int top; /* Offset to top of buffer allocated for the key */ unsigned int end; /* End of the current key. Offset to the second null */ unsigned int gvn_len; /* Length of part of key that makes up the GVN */ unsigned char base[1]; /* Base of the key */ } dbc_gv_key; typedef struct { dbc_gv_key *ins_key; /* Describes key part of record */ block_id blk_id; /* Block id to use for value of key */ } dbc_inserted_rec; /* Structure to hold block numbers where an integrity error caused a problem the first time around */ typedef struct integ_error_blk_list_struct { struct integ_error_blk_list_struct *next; /* Chain of such structures if necessary */ int blk_cnt; /* Count of blccks in structure */ block_id blk_list[MAX_IEB_CNT]; /* List of block ids with integ errors */ } integ_error_blk_list; /* Structure we use for pseudo cw_set_element/cache entry - allocated in an array */ typedef struct block_info_struct { v15_trans_num tn; /* transaction number for bit maps */ block_id blk_num; /* Block number or a hint block number for creates */ enum gdsblk_usage usage; /* Read, Update, or Create */ enum gdsblk_type blk_type; /* Type of block */ blk_segment *upd_addr; /* Address of the block segment array containing update info * for this block */ boolean_t found_in_cache; /* This block was found in the cache instead of being read */ uchar_ptr_t old_buff; /* Original buffer before changes */ uchar_ptr_t new_buff; /* New buffer after changes/create */ uchar_ptr_t prev_rec; /* Pointer to previous record in block (in old_buff) */ unsigned int prev_match; /* Match of previous record to search key */ uchar_ptr_t curr_rec; /* Current record being looked at in block (in old_buff) */ unsigned int curr_match; /* Match of current record to search key */ dbc_gv_key *curr_blk_key; /* Key in use to lookup records in this block (last key used) */ dbc_gv_key *prev_blk_key; /* Key as known at previous record (copy of curr_blk_key before it is updated) */ dbc_inserted_rec ins_rec; /* Record to be inserted in this block (if .ins_key.end is not 0) */ int blk_len; /* (old) size of this block */ int blk_levl; /* block's level */ /* When a block splits a new block must be created and the parent must be updated to * to have a record pointing to the new block. The created block number will not be * known until the last possible moment. Thus it is not possible to completely modify * the parent. The following field is used in such a case. When non-zero (and it should only * be non-zero for created blocks), it points to the referring block's ins_key.blk_id field. The * location this field targets is inside the update array for that block. When a block is assigned * at commit time, this field is used to "fixup" the update array so that when the block is * (re)created during commit, it contains the proper block number. */ block_id *ins_blk_id_p; } block_info; /* Single malloc'd structure to hold static fields while we shuffle between our processing routines */ typedef struct { int hint_lcl; /* Hint offset in hint_blk's local bitmap */ int outfd; /* File descriptor for input file */ int blks_processed; /* Counter - blocks from phase-1 we ended up splitting */ int blks_bypassed; /* Counter - blocks from phase-1 no longer needed splitting */ int blks_too_big; /* Counter -- blocks needing to be split */ int blks_read; /* Counter - blocks we read during processing */ int blks_cached; /* Counter - block reads satisfied from cache */ int blks_updated; /* Counter - blocks we updated during processing */ int blks_created; /* Counter - blocks we created during processing */ int dtlvl0; /* Counter - Directory tree level 0 blocks */ int dtlvln0; /* Counter - Directory tree not level 0 blocks */ int gvtlvl0; /* Counter - Global variable tree level 0 blocks */ int gvtlvln0; /* Counter - Global variable tree not level 0 blocks */ int gvtrchildren; /* Counter - Right sibling children of gvtroot processed */ int blk_process_errors; /* Counter - Errors encountered which keep us from certifying DB */ int gvtroot_rchildren_cnt; /* Count of the inhabitants of gvtroot_rchildren[] */ int local_bit_map_cnt; /* Total local bit maps in database */ uint4 blocks_to_process; /* Number of blocks (records) phase two will process */ int tmpcmdfile_len; /* Length of tmpcmdfile */ int tmprsltfile_len; /* Length of tmprsltfile */ unsigned int max_blk_len; /* Max block length (including blk header) */ unsigned int max_rec_len; /* Maximum record length (including rec header) */ boolean_t report_only; /* Copy of input report_only flag */ boolean_t detail; /* Copy of input detail flag */ boolean_t bsu_keys; /* Copy of input bsu_keys flag */ boolean_t final; /* This is the final pass for error blocks */ boolean_t phase_one; /* When we are in phase 1 (aka scan phase)... */ boolean_t dbc_debug; /* The -debug flag was specified */ boolean_t tmp_file_names_gend; /* Whether we have figured out what our temp file names are */ boolean_t keep_temp_files; /* Leave temp files instead of delete on exit */ UNIX_ONLY(sem_info sem_inf[FTOK_ID_CNT];) /* Ftok keys for id 43 and 1 (both used by older versions) */ volatile boolean_t dbc_critical; /* Critical section indicator for condition/signal/exit handlers */ volatile boolean_t dbc_fhdr_dirty; /* If fileheader has been modified, flag it */ uchar_ptr_t curr_lbmap_buff; /* Buffer holding current local bit map block */ uchar_ptr_t block_buff; /* Buffer holding current database block */ unsigned char util_cmd_buff[256]; /* Buffer for DSE and/or MUPIP command creation */ block_info *blk_set; /* Max number of blocks we need per query/update (array) */ int block_depth; /* How many blocks we have ref'd/used this query */ int block_depth_hwm; /* High water mark for block depth */ FILE *tcfp; /* File pointer for temporary command file */ FILE *trfp; /* File pointer for temporary result file */ block_id hint_blk; /* Hint where to start search for next free block */ p1hdr ofhdr; /* Phase-1 output file header (phase-2 input file) */ p1rec rhdr; /* Record in output file */ p1rec gvtroot_rchildren[MAX_BT_DEPTH + 1]; /* List of right hand children for a GVT root block to process */ gd_region *dbc_gv_cur_region; /* our version of gv_cur_region */ v15_sgmnt_data_ptr_t dbc_cs_data; /* our version of cs_data */ dbc_gv_key *first_rec_key; /* Statically allocazted key buffer used for initial search */ file_control *fc; integ_error_blk_list *iebl; /* Chain of blocks describing integ errors we encountered in 1st pass */ dbc_gv_key *gvn_key; /* Used to look up GVN in directory tree */ dbc_gv_key *max_key; /* Maximum possible key value */ unsigned char outfn[MAX_FN_LEN + 1]; /* File name argument (may be db or outfile depending on phase) */ unsigned char regname[MAX_RN_LEN + 1]; /* Buffer for region name */ unsigned char rslt_buff[MAX_ZWR_KEY_SZ + 1]; /* Buffer for reading from result file */ unsigned char tmpcmdfile[MAX_FN_LEN + 1]; /* Temporary command file name */ unsigned char tmprsltfile[MAX_FN_LEN + 1]; /* Temporary command result file name */ unsigned char tmpfiledir[MAX_FN_LEN + 1]; /* Directory where temp files created (defaults to current dir */ } phase_static_area; /* Debug macro. This macro is compiled into even the pro-build. It emits the enclosed message if a debug option has been specified.*/ #define DBC_DEBUG(x) if (psa->dbc_debug) {PRINTF x; FFLUSH(stdout);} /* We need to redefine 2 macros from gdsblkops.h (BLK_INIT and BLK_FINI) because they contain references to the type blk_hdr which for V5 is a different size than the v15_blk_hdr type we are using for V4 databases. */ #ifndef BLK_INIT # error gdsblkops.h must be included prior to dbcertify.h #endif #undef BLK_INIT #undef BLK_FINI /* *************************************************************************** * BLK_INIT(BNUM, ARRAY) allocates: * blk_segment ARRAY[BLK_SEG_ARRAY_SIZE] * at the next octaword-aligned location in the update array and sets * BNUM = &ARRAY[1] */ #define BLK_INIT(BNUM, ARRAY) \ { \ update_array_ptr = (char_ptr_t)ROUND_UP2((INTPTR_T)update_array_ptr, UPDATE_ELEMENT_ALIGN_SIZE); \ (ARRAY) = (blk_segment *)update_array_ptr; \ update_array_ptr += BLK_SEG_ARRAY_SIZE * SIZEOF(blk_segment); \ assert(((update_array + update_array_size) - update_array_ptr) >= 0); \ (BNUM) = (ARRAY + 1); \ blk_seg_cnt = SIZEOF(v15_blk_hdr); \ } /* *************************************************************************** * BLK_FINI(BNUM,ARRAY) finishes the update array by * BNUM->addr = 0 * BNUM-- * if the blk_seg_cnt is within range, then * ARRAY[0].addr = BNUM (address of last entry containing data) * ARRAY[0].len = blk_seg_cnt (total size of all block segments) * and it returns the value of blk_seg_cnt, * otherwise, it returns zero and the caller should invoke t_retry */ #define BLK_FINI(BNUM,ARRAY) \ ( \ (BNUM--)->addr = (uchar_ptr_t)0, \ (blk_seg_cnt <= blk_size && blk_seg_cnt >= SIZEOF(v15_blk_hdr)) \ ? (ARRAY)[0].addr = (uchar_ptr_t)(BNUM), (ARRAY)[0].len = blk_seg_cnt \ : 0 \ ) /* Need to redefine the IS_BML macro in gdsblk.h to use the older header */ #ifndef IS_BML # error gdsblk.h must be included prior to dbcertify.h #endif #undef IS_BML #define IS_BML(b) (BML_LEVL == ((v15_blk_hdr_ptr_t)(b))->levl) CONDITION_HANDLER(dbcertify_base_ch); #ifdef __osf__ #pragma pointer_size (save) #pragma pointer_size (long) #endif void dbcertify_parse_and_dispatch(int argc, char **argv); #ifdef __osf__ #pragma pointer_size (restore) #endif void dbcertify_scan_phase(void); void dbcertify_certify_phase(void); void dbcertify_dbfilop(phase_static_area *psa); #ifdef UNIX #include void dbcertify_signal_handler(int sig, siginfo_t *info, void *context); void dbcertify_deferred_signal_handler(void); #else void dbcertify_exit_handler(void); #endif /* Routines in dbcertify_funcs.c */ void dbc_gen_temp_file_names(phase_static_area *psa); void dbc_open_command_file(phase_static_area *psa); void dbc_write_command_file(phase_static_area *psa, char_ptr_t cmd); void dbc_close_command_file(phase_static_area *psa); void dbc_run_command_file(phase_static_area *psa, char_ptr_t cmdname, char_ptr_t cmdargs, boolean_t piped_result); void dbc_remove_command_file(phase_static_area *psa); void dbc_open_result_file(phase_static_area *psa); void dbc_find_database_filename(phase_static_area *psa, uchar_ptr_t regname, uchar_ptr_t dbfn); uchar_ptr_t dbc_read_result_file(phase_static_area *psa, int errmsg, uchar_ptr_t eofmsg); void dbc_close_result_file(phase_static_area *psa); void dbc_remove_result_file(phase_static_area *psa); int dbc_syscmd(char_ptr_t cmd); int dbc_read_dbblk(phase_static_area *psa, int blk_num, enum gdsblk_type blk_type); void dbc_init_key(phase_static_area *psa, dbc_gv_key **key); void dbc_find_key(phase_static_area *psa, dbc_gv_key *key, uchar_ptr_t rec_p, int blk_levl); boolean_t dbc_match_key(dbc_gv_key *key1, int blk_levl1, dbc_gv_key *key2, unsigned int *matchc); int dbc_find_dtblk(phase_static_area *psa, dbc_gv_key *key, int min_levl); int dbc_find_record(phase_static_area *psa, dbc_gv_key *key, int blk_index, int min_levl, enum gdsblk_type newblk_type, boolean_t fail_ok); void dbc_init_blk(phase_static_area *psa, block_info *blk_set_p, int blk_num, enum gdsblk_usage blk_usage, int blk_len, int blk_levl); void dbc_init_db(phase_static_area *psa); void dbc_close_db(phase_static_area *psa); void dbc_scan_phase_cleanup(void); void dbc_certify_phase_cleanup(void); #ifdef UNIX void dbc_aquire_standalone_access(phase_static_area *psa); void dbc_release_standalone_access(phase_static_area *psa); #endif #endif fis-gtm-V6.0-003/sr_port/dbcertify_base_ch.c0000644000032200000250000000513512201176155017621 0ustar librarygtc/**************************************************************** * * * Copyright 2005, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdlib.h" #ifdef VMS #include #endif #include "gdsroot.h" #include "v15_gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "v15_gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "v15_gdsfhead.h" #include "gdsblkops.h" #include "error.h" #include "gtmimagename.h" #include "filestruct.h" #include "v15_filestruct.h" #include "dbcertify.h" GBLREF boolean_t need_core; GBLREF boolean_t created_core; GBLREF boolean_t dont_want_core; GBLREF int4 exi_condition; GBLREF int4 error_condition; GBLREF enum gtmImageTypes image_type; error_def(ERR_ASSERT); error_def(ERR_GTMASSERT); error_def(ERR_GTMASSERT2); error_def(ERR_GTMCHECK); error_def(ERR_MEMORY); error_def(ERR_OUTOFSPACE); error_def(ERR_STACKOFLOW); error_def(ERR_VMSMEMORY); VMS_ONLY(error_def(ERR_DBCNOFINISH);) CONDITION_HANDLER(dbcertify_base_ch) { VMS_ONLY( unsigned short msglen; uint4 status; unsigned char msginfo[4]; unsigned char msg_buff[MAX_MSG_SIZE + 1]; $DESCRIPTOR(msgbuf, msg_buff); ) START_CH; PRN_ERROR; if (SUCCESS == SEVERITY || INFO == SEVERITY) { CONTINUE; } else { UNIX_ONLY( if ((DUMPABLE) && !SUPPRESS_DUMP) { need_core = TRUE; gtm_fork_n_core(); } /* rts_error sets error_condition, and dbcertify_base_ch is called only if * exiting thru rts_error. Setup exi_condition to reflect error * exit status. Note, if the last eight bits (the only relevant bits * for Unix exit status) of error_condition is non-zero in case of * errors, we make sure that an error exit status (non-zero value -1) * is setup. This is a hack. */ if (0 == exi_condition) exi_condition = (((error_condition & UNIX_EXIT_STATUS_MASK) != 0) ? error_condition : -1); ) VMS_ONLY( if ((DUMPABLE) && !SUPPRESS_DUMP) { gtm_dump(); TERMINATE; } exi_condition = SIGNAL; /* following is a hack to avoid FAO directives getting printed without expanding * in the error message during EXIT() */ if (IS_GTM_ERROR(SIGNAL)) exi_condition = ERR_DBCNOFINISH; ) UNSUPPORTED_PLATFORM_CHECK; EXIT(exi_condition); } } fis-gtm-V6.0-003/sr_port/dbcertify_certify_phase.c0000644000032200000250000022217712201176155021071 0ustar librarygtc/**************************************************************** * * * Copyright 2005, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /**************************************************************** dbcertify_certify_phase2.c - Database certification phase 2 - Verify phase 1 input file. - Locate and open database after getting standalong access. - Read the identified blocks in and if they are still too large, split them. - Certify the database as "clean" if no errors encountered. Note: Most routines in this utility are self-contained meaning they do not reference GT.M library routines (with some notable exceptions). This is because phase-2 is going to run against V4 format databases but any linked routines would be compiled for V5 databases. ****************************************************************/ #include "mdef.h" #ifdef VMS #include #include #include #endif #include #include "gtm_stat.h" #include "gtm_ctype.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "gtm_unistd.h" #include "gtm_stdlib.h" #include "gtm_fcntl.h" #ifdef __MVS__ #include "gtm_zos_io.h" #endif #include "gtmio.h" #include "cli.h" #include "copy.h" #include "iosp.h" #include "gdsroot.h" #include "v15_gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "v15_gdsbt.h" #include "gdsfhead.h" #include "v15_gdsfhead.h" #include "filestruct.h" #include "v15_filestruct.h" #include "gdsblk.h" #include "gdsbml.h" #include "gdscc.h" #include "bmm_find_free.h" #include "gdsblkops.h" #include "bit_set.h" #include "bit_clear.h" #include "min_max.h" #include "gtmmsg.h" #ifdef VMS # include "is_file_identical.h" #endif #include "error.h" #include "mupip_exit.h" #include "util.h" #include "dbcertify.h" GBLREF char_ptr_t update_array, update_array_ptr; GBLREF uint4 update_array_size; GBLREF VSIG_ATOMIC_T forced_exit; /* Signal came in while we were in critical section */ GBLREF int4 exi_condition; GBLREF phase_static_area *psa_gbl; boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_type blk_type, v15_trans_num tn, int blk_levl); void dbc_flush_fhead(phase_static_area *psa); void dbc_read_p1out(phase_static_area *psa, void *obuf, int olen); error_def(ERR_DEVOPENFAIL); error_def(ERR_FILENOTFND); error_def(ERR_DBCSCNNOTCMPLT); error_def(ERR_DBCBADFILE); error_def(ERR_DBCMODBLK2BIG); error_def(ERR_DBCINTEGERR); error_def(ERR_DBCNOEXTND); error_def(ERR_DBCDBCERTIFIED); error_def(ERR_DBCNOTSAMEDB); error_def(ERR_DBCDBNOCERTIFY); error_def(ERR_DBCREC2BIGINBLK); error_def(ERR_SYSCALL); error_def(ERR_TEXT); error_def(ERR_BITMAPSBAD); error_def(ERR_MUPCLIERR); ZOS_ONLY(error_def(ERR_BADTAG);) /* The final certify phase of certification process */ void dbcertify_certify_phase(void) { int save_errno, len, rc, restart_cnt, maxkeystructsize; uint4 rec_num; char_ptr_t errmsg; boolean_t restart_transaction, p1rec_read; unsigned short buff_len; int tmp_cmpc; char ans[2]; unsigned char dbfn[MAX_FN_LEN + 1]; file_control *fc; phase_static_area *psa; ZOS_ONLY(int realfiletag;) psa = psa_gbl; DBC_DEBUG(("DBC_DEBUG: Beginning certification phase\n")); psa->phase_one = FALSE; UNIX_ONLY(atexit(dbc_certify_phase_cleanup)); psa->block_depth = psa->block_depth_hwm = -1; /* Initialize no cache */ /* Check parsing results */ if (CLI_PRESENT == cli_present("BLOCKS")) { if (!cli_get_hex("BLOCKS", &psa->blocks_to_process)) exit(EXIT_FAILURE); /* Error message already raised */ } else psa->blocks_to_process = MAXTOTALBLKS_V4; if (CLI_PRESENT == cli_present("TEMPFILE_DIR")) { /* Want to put temp files in this directory */ buff_len = SIZEOF(psa->tmpfiledir) - 1; if (0 == cli_get_str("TEMPFILE_DIR", (char_ptr_t)psa->tmpfiledir, &buff_len)) mupip_exit(ERR_MUPCLIERR); } psa->keep_temp_files = (CLI_PRESENT == cli_present("KEEP_TEMPS")); buff_len = SIZEOF(psa->outfn) - 1; if (0 == cli_get_str("P1OUTFILE", (char_ptr_t)psa->outfn, &buff_len)) mupip_exit(ERR_MUPCLIERR); /* Open phase-1 output file (our input file) */ psa->outfd = OPEN((char_ptr_t)psa->outfn, O_RDONLY RMS_OPEN_BIN); if (FD_INVALID == psa->outfd) { save_errno = errno; if (save_errno == ENOENT) rts_error(VARLSTCNT(4) ERR_FILENOTFND, 2, RTS_ERROR_STRING((char_ptr_t)psa->outfn)); else { errmsg = STRERROR(save_errno); rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, RTS_ERROR_STRING((char_ptr_t)psa->outfn), ERR_TEXT, 2, RTS_ERROR_STRING(errmsg)); } } #ifdef __MVS__ if (-1 == gtm_zos_tag_to_policy(psa->outfd, TAG_BINARY, &realfiletag)) TAG_POLICY_GTM_PUTMSG((char_ptr_t)psa->outfn, errno, realfiletag, TAG_BINARY); #endif dbc_read_p1out(psa, &psa->ofhdr, SIZEOF(p1hdr)); /* Read phase 1 output file header */ if (0 != memcmp(psa->ofhdr.p1hdr_tag, P1HDR_TAG, SIZEOF(psa->ofhdr.p1hdr_tag))) rts_error(VARLSTCNT(4) ERR_DBCBADFILE, 2, RTS_ERROR_STRING((char_ptr_t)psa->outfn)); if (0 == psa->ofhdr.tot_blocks) /* Sanity check that the output file was finished and completed */ rts_error(VARLSTCNT(4) ERR_DBCSCNNOTCMPLT, 2, RTS_ERROR_STRING((char_ptr_t)psa->outfn)); assert(0 != psa->ofhdr.tn); /* Check if region name still associates to the same file */ dbc_find_database_filename(psa, psa->ofhdr.regname, dbfn); /* Notify user this is a critical change and give them the opportunity to abort */ util_out_print("--------------------------------------------------------------------------------", FLUSH); util_out_print("You must have a backup of database !AD before you proceed!!", FLUSH, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn)); util_out_print("An abnormal termination can damage the database while doing the certification !!", FLUSH); util_out_print("Proceeding will also turn off replication and/or journaling if enabled", FLUSH); util_out_print("--------------------------------------------------------------------------------", FLUSH); util_out_print("Proceed? [y/n]:", FLUSH); SCANF("%1s", ans); /* We only need one char, any more would overflow our buffer */ if ('y' != ans[0] && 'Y' != ans[0]) { util_out_print("Certification phase aborted\n", FLUSH); return; } util_out_print("Certification phase for database !AD beginning", FLUSH, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn)); /* Build database structures */ MALLOC_INIT(psa->dbc_gv_cur_region, SIZEOF(gd_region)); MALLOC_INIT(psa->dbc_gv_cur_region->dyn.addr, SIZEOF(gd_segment)); psa->dbc_gv_cur_region->dyn.addr->acc_meth = dba_bg; len = STRLEN((char_ptr_t)psa->ofhdr.dbfn); strcpy((char_ptr_t)psa->dbc_gv_cur_region->dyn.addr->fname, (char_ptr_t)dbfn); psa->dbc_gv_cur_region->dyn.addr->fname_len = len; FILE_CNTL_INIT(psa->dbc_gv_cur_region->dyn.addr); psa->dbc_gv_cur_region->dyn.addr->file_cntl->file_type = dba_bg; psa->dbc_cs_data = malloc(SIZEOF(*psa->dbc_cs_data)); fc = psa->fc = psa->dbc_gv_cur_region->dyn.addr->file_cntl; fc->file_type = psa->dbc_gv_cur_region->dyn.addr->acc_meth = dba_bg; /* Always treat as BG mode */ /* Initialize for db processing - open and read in file-header, get "real" filename for comparison */ dbc_init_db(psa); if (0 != strcmp((char_ptr_t)psa->dbc_gv_cur_region->dyn.addr->fname, (char_ptr_t)psa->ofhdr.dbfn)) /* File name change means db was moved or at least is not as it was when it was scanned */ rts_error(VARLSTCNT(1) ERR_DBCNOTSAMEDB); if (psa->ofhdr.tn > psa->dbc_cs_data->trans_hist.curr_tn) rts_error(VARLSTCNT(1) ERR_DBCNOTSAMEDB); psa->max_blk_len = psa->dbc_cs_data->blk_size - psa->dbc_cs_data->reserved_bytes; /* Initialize maximum key we may need later if we encounter gvtroot blocks */ maxkeystructsize = SIZEOF(dbc_gv_key) + MAX_DBC_KEY_SZ - 1; MALLOC_INIT(psa->max_key, maxkeystructsize); psa->max_key->top = maxkeystructsize; psa->max_key->gvn_len = 1; *psa->max_key->base = (unsigned char)0xFF; /* Key format: 0xFF, 0x00, 0x00 : This is higher than any valid key would be */ psa->max_key->end = MAX_DBC_KEY_SZ - 1; /* Allocate update array based on fileheader values */ psa->dbc_cs_data->max_update_array_size = psa->dbc_cs_data->max_non_bm_update_array_size = (uint4)ROUND_UP2(MAX_NON_BITMAP_UPDATE_ARRAY_SIZE(psa->dbc_cs_data), UPDATE_ARRAY_ALIGN_SIZE); psa->dbc_cs_data->max_update_array_size += (int4)(ROUND_UP2(MAX_BITMAP_UPDATE_ARRAY_SIZE, UPDATE_ARRAY_ALIGN_SIZE)); update_array = malloc(psa->dbc_cs_data->max_update_array_size); update_array_size = psa->dbc_cs_data->max_update_array_size; /* Now to the real work -- Read and split each block the phase 1 file recorded that still needs to be split (concurrent updates may have "fixed" some blocks). */ psa->hint_blk = psa->hint_lcl = 1; restart_transaction = p1rec_read = FALSE; restart_cnt = 0; for (rec_num = 0; rec_num < psa->ofhdr.blk_count || 0 < psa->gvtroot_rchildren_cnt;) { /* There is the possibility that we are restarting the processing of a given record. In that case we will not read the next record in but process what is already in the buffer. This can occur if we have extended the database. */ if (!restart_transaction) { /* First to check is if we have any queued gvtroot_rchildren to process (described elsewhere). If we have these, we process them now without bumping the record count. */ p1rec_read = FALSE; /* Assume we did NOT read from the file */ if (0 < psa->gvtroot_rchildren_cnt) { psa->gvtroot_rchildren_cnt--; memcpy((char *)&psa->rhdr, (char *)&psa->gvtroot_rchildren[psa->gvtroot_rchildren_cnt], SIZEOF(p1rec)); psa->gvtrchildren++; /* counter */ DBC_DEBUG(("DBC_DEBUG: Pulling p1rec from queued gvtroot_rchildren array (%d)\n", psa->gvtroot_rchildren_cnt)); } else { /* Normal processing - read record from phase one file */ if (rec_num == psa->blocks_to_process) { /* Maximum records processed */ DBC_DEBUG(("DBC_DEBUG: Maximum records to process limit reached " "- premature exit to main loop\n")); break; } DBC_DEBUG(("DBC_DEBUG: ****************** Reading new p1out record (%d) *****************\n", (rec_num + 1))); dbc_read_p1out(psa, &psa->rhdr, SIZEOF(p1rec)); if (0 != psa->rhdr.akey_len) { /* This module does not need the ascii key so just bypass it if it exists */ if (0 != psa->rhdr.blk_levl || SIZEOF(psa->rslt_buff) < psa->rhdr.akey_len ) GTMASSERT; /* Must be corrupted file? */ dbc_read_p1out(psa, (char_ptr_t)psa->rslt_buff, psa->rhdr.akey_len); } p1rec_read = TRUE; /* Note, not reset by restarted transaction */ } /* Don't want to reset the high water mark on a restarted transaction */ if (psa->block_depth > psa->block_depth_hwm) psa->block_depth_hwm = psa->block_depth; /* Keep track of maximum indexes we have used */ restart_cnt = 0; } else { ++restart_cnt; if (MAX_RESTART_CNT < restart_cnt) GTMASSERT; /* No idea what could cause this.. */ DBC_DEBUG(("DBC_DEBUG: ****************** Restarted transaction (%d) *****************\n", (rec_num + 1))); /* "restart_transaction" is either set or cleared by dbc_split_blk() below */ } assert((int)psa->rhdr.blk_type); /* Note assignment in "if" below */ if (restart_transaction = dbc_split_blk(psa, psa->rhdr.blk_num, psa->rhdr.blk_type, psa->rhdr.tn, psa->rhdr.blk_levl)) psa->block_depth_hwm = -1; /* Zaps cache so all blocks are re-read */ else if (p1rec_read) /* If rec processed was from scan phase, bump record counter */ rec_num++; } /* for each record in phase-1 output file or each restart or each queued rh child */ /* Reaching this point, the database has been updated, with no errors. We can now certify this database as ready for the current version of GT.M */ util_out_print("", FLUSH); /* New line for below message in case MUPIP extension leaves prompt */ if (0 == psa->blk_process_errors) { if (psa->blocks_to_process != rec_num) { ((sgmnt_data_ptr_t)psa->dbc_cs_data)->certified_for_upgrade_to = GDSV6; psa->dbc_fhdr_dirty = TRUE; gtm_putmsg(VARLSTCNT(6) ERR_DBCDBCERTIFIED, 4, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn), RTS_ERROR_LITERAL("GT.M V5")); } else { DBC_DEBUG(("DBC_DEBUG: Database certification bypassed due to records to process limit being reached\n")); } } else gtm_putmsg(VARLSTCNT(4) ERR_DBCDBNOCERTIFY, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn)); dbc_flush_fhead(psa); dbc_close_db(psa); CLOSEFILE_RESET(psa->outfd, rc); /* resets "psa->outfd" to FD_INVALID */ PRINTF("\n"); PRINTF("Total blocks in scan phase file -- %12d [0x%08x]\n", psa->ofhdr.blk_count, psa->ofhdr.blk_count); PRINTF("Blocks bypassed ------------------ %12d [0x%08x]\n", psa->blks_bypassed, psa->blks_bypassed); PRINTF("Blocks processed ----------------- %12d [0x%08x]\n", psa->blks_processed, psa->blks_processed); PRINTF("Blocks read ---------------------- %12d [0x%08x]\n", psa->blks_read, psa->blks_read); PRINTF("Blocks read from cache ----------- %12d [0x%08x]\n", psa->blks_cached, psa->blks_cached); PRINTF("Blocks updated ------------------- %12d [0x%08x]\n", psa->blks_updated, psa->blks_updated); PRINTF("Blocks created ------------------- %12d [0x%08x]\n", psa->blks_created, psa->blks_created); PRINTF("GVTROOT right children processed - %12d [0x%08x]\n", psa->gvtrchildren, psa->gvtrchildren); /* Release resources */ free(update_array); free(psa->dbc_cs_data); #ifdef VMS /* Some extra freeing of control blocks on VMS */ if (NULL != FILE_INFO(psa->dbc_gv_cur_region)->fab) free(FILE_INFO(psa->dbc_gv_cur_region)->fab); if (NULL != FILE_INFO(psa->dbc_gv_cur_region)->nam) { if (NULL != FILE_INFO(psa->dbc_gv_cur_region)->nam->nam$l_esa) free(FILE_INFO(psa->dbc_gv_cur_region)->nam->nam$l_esa); free(FILE_INFO(psa->dbc_gv_cur_region)->nam); } if (NULL != FILE_INFO(psa->dbc_gv_cur_region)->xabfhc) free(FILE_INFO(psa->dbc_gv_cur_region)->xabfhc); if (NULL != FILE_INFO(psa->dbc_gv_cur_region)->xabpro) free(FILE_INFO(psa->dbc_gv_cur_region)->xabpro); #endif free(psa->dbc_gv_cur_region->dyn.addr->file_cntl->file_info); free(psa->dbc_gv_cur_region->dyn.addr->file_cntl); free(psa->dbc_gv_cur_region->dyn.addr); free(psa->dbc_gv_cur_region); psa->dbc_gv_cur_region = NULL; if (psa->first_rec_key) free(psa->first_rec_key); free(psa); } /* Routine to handle the processing (splitting) of a given database block. If the current block process needs to be restarted, this function returns TRUE. else if processing completed normally, returns FALSE. Routine notes: This routine implements a "simplistic" mini database engine. It is "simplistic" in the regards to fact that it doesn't need to worry about concurrency issues. It also has one design assumption that we will NEVER add a record to a level 0 block (either DT or GVT). Because of this assumption, many complications from gvcst_put(), on which it is largely based, were non-issues and were removed (e.g. no TP). This routine has its own concepts of "cache", cw_set elements, update arrays, etc. Following is a brief description of how these things are implemented in this routine: The primary control block in this scheme is the block_info block which serves as a cache record, change array anchor, gv_target, and so on. In short, everything that is known about a given database block is contained in this one structure. There is an array of these structures with the name "blk_set" which is a global variable array dimensioned at a thoroughly outrageous amount for the worst case scenario. There are areas within the blk_set array that are worth describing: - The block_depth global variable always holds the top in use index into blk_set. - blk_set[0] describes the block that was fed to us from the phase 1 scan. It is the primary block that needs to be split. If nothing needs to happen to it, we go to the next record and blk_set[0] get a new block in it. - Starting with blk_set[1] through blk_set[bottom_tree_index] are first the directory tree (DT) blocks and then (if primary was a GVT block) the global variable tree (GVT) blocks. - Starting with blk_set[bottom_tree_index + 1] through blk_set[bottom_created_index] are newly created blocks during split processing. - Starting with blk_set[bottom_created_index + 1] through blk_set[block_depth] are local bit map blocks that are being modified for the "transaction". This engine has a very simple cache mechanism. If a block we need is somewhere in the blk_set array (a global variable block_depth_hwm maintains a high water mark), the cache version is used rather than forcing a re-read from disk. It is fairly simple but seems to save a lot of reads, especially of the directory tree and the local bit_maps. Like gvcst_put(), once we have the blocks from the tree loaded, they are processed in reverse order as a split in one block requires a record to be inserted into the parent block. We start with the primary block (blk_set[0]) and then move to blk_set[bottom_tree_index] and work backwards from there until either we get to a block for which there are no updates or we hit a root block (GVT or DT depending) at which time we are done with the primary update loop. After performing the block splits and creating new blocks, we double check that we have room to hold them all. If not, we make a call to MUPIP EXTEND to extend the database for us. Since this means we have to close the file and give up our locks on it, we also restart the transaction and force all blocks to be re-read from disk. Once assured we have sufficient free blocks, we start at blk_set[bottom_created_index] and work down to blk_set[bottom_tree_index + 1] allocating and assigning block numbers to the created blocks. Part of this process also puts the block numbers into places where the update arrays will pick them up when the referencing blocks are built. Once all the new blocks have been assigned, we loop through blk_set[bottom_tree_index] to blk_set[0] and create the new versions of the blocks (for those blocks marked as being updated). A note here is that this engine does not build update array entries for bitmap blocks, preferring instead to just update the local bitmap block buffers directly. The last major loop is to write to disk all the new and changed blocks to disk. There is no processing but simple IO in this loop to minimize the potential of something going wrong. There is no recovery at this point. If this loop fails in mid-stream, the database is toast. */ boolean_t dbc_split_blk(phase_static_area *psa, block_id blk_num, enum gdsblk_type blk_type, v15_trans_num tn, int blk_levl) { int blk_len, blk_size, restart_cnt, save_block_depth; int gvtblk_index, dtblk_index, blk_index, bottom_tree_index, bottom_created_index; int curr_blk_len, curr_blk_levl, curr_rec_len, ins_key_len, ins_rec_len; int curr_rec_shrink, curr_rec_offset, blks_this_lmap; int prev_rec_offset, new_blk_len, new_rec_len, remain_offset, remain_len, blk_seg_cnt; int new_lh_blk_len, new_rh_blk_len, created_blocks, extent_size; int local_map_max, lbm_blk_index, lcl_blk, curr_rec_cmpc, cmpc; int tmp_cmpc; int4 lclmap_not_full; uint4 total_blks; boolean_t dummy_bool; boolean_t got_root, level_0, completed, insert_point, restart_transaction; blk_segment *bs_ptr, *bs1, *blk_sega_p, *blk_array_top; rec_hdr_ptr_t ins_rec_hdr, next_rec_hdr, new_star_hdr; dbc_gv_key *last_rec_key; uchar_ptr_t rec_p, next_rec_p, mid_point, cp1, lcl_map_p, new_blk_p, blk_p, blk_endp, chr_p; unsigned short us_rec_len; v15_trans_num curr_tn; block_id blk_ptr; block_id bitmap_blk_num, *lhs_block_id_p, *rhs_block_id_p, allocated_blk_num; block_info *blk_set_p, *blk_set_new_p, *blk_set_prnt_p, *blk_set_bm_p, *blk_set_rhs_p; block_info restart_blk_set; DEBUG_ONLY( boolean_t first_time = FALSE; ) /* First order of business is to read the required block in */ psa->block_depth = -1; blk_size = psa->dbc_cs_data->blk_size; /* BLK_FINI macro needs a local copy */ dbc_read_dbblk(psa, blk_num, blk_type); /* Now that we have read the block in, let us see if it is still a "problem" block. If its TN has changed, that is an indicator that is should NOT be a problem block any longer with the sole exception of a TN RESET having been done on the DB since phase 1. In that case, we will still insist on a phase 1 rerun as some of our sanity checks have disappeared. */ assert(0 == psa->block_depth); blk_p = psa->blk_set[0].old_buff; assert(blk_p); blk_len = psa->blk_set[0].blk_len; /* If the block is still too large, sanity check on TN at phase 1 and now. Note that it is possible in an index block for the TN to have changed yet the block is otherwise unmodified if (1) this is an index block and (2) a record is being inserted before the first record in the block. In this case, the new record is put into the new (LH) sibling and the entire existing block is put unmodified into the RH side in the existing block. The net result is that only the TN changes in this block and if the block is too full it is not split. This will never happen for a created block though. It can only hapen for existing index blocks. Note if the block is not (still) too full that we cannot yet say this block has nothing to happen to it because if it is a gvtroot block, we need to record its right side children further down. */ GET_ULONG(curr_tn, &((v15_blk_hdr_ptr_t)blk_p)->tn); if ((UNIX_ONLY(8) VMS_ONLY(9) > blk_size - blk_len) && (curr_tn != tn) && (gdsblk_gvtleaf == blk_type)) { /* Block has been modified: Three possible reasons it is not fixed: 1) The user was playing with reserved bytes and set it too low allowing some large blocks to be created we did not know about (but thankfully just caught). 2) User ran a recover after running phase 1 that re-introduced some too-large blocks. This is a documented no-no but we have no way to enforce it on V4. 3) There was a TN reset done. All three of these causes require a rerun of the scan phase. */ rts_error(VARLSTCNT(3) ERR_DBCMODBLK2BIG, 1, blk_num); } /* Isolate the full key in the first record of the block */ dbc_init_key(psa, &psa->first_rec_key); dbc_find_key(psa, psa->first_rec_key, blk_p + SIZEOF(v15_blk_hdr), psa->blk_set[0].blk_levl); if ((0 < psa->blk_set[0].blk_levl) && (0 == psa->first_rec_key->end)) { /* dbc_find_key found just a star-key in this index block. dbc_find_record/dbc_match_key (invoked later) * does not know to handle this scenario so we finish this case off right away. No need to do any splits * anyways since the block is obviously not too full. */ DBC_DEBUG(("DBC_DEBUG: Block not processed as it now has sufficient room (index block with only *-key)\n")); psa->blks_bypassed++; psa->blks_read++; if (psa->blk_set[0].found_in_cache) psa->blks_cached++; return FALSE; /* No restart needed */ } psa->first_rec_key->gvn_len = USTRLEN((char_ptr_t)psa->first_rec_key->base); /* The GVN we need to lookup in the DT */ if (UNIX_ONLY(8) VMS_ONLY(9) <= blk_size - blk_len) { /* This block has room now - no longer need to split it */ DBC_DEBUG(("DBC_DEBUG: Block not processed as it now has sufficient room\n")); psa->blks_bypassed++; psa->blks_read++; if (psa->blk_set[0].found_in_cache) psa->blks_cached++; return FALSE; /* No restart needed */ } /* Possibilities at this point: 1) We are looking for a DT (directory tree) block. 2) We are looking for a GVT (global variable tree) block. We lookup first_rec_key in the directory tree. If (1) we pass the block level we are searching for as a parameter. If (2), we pass -1 as the block level we are searching for as we need a complete search of the leaf level DT in order to find the GVN. If (1) then the lookup is complete and verification and (later) block splitting can begin. If (2), we need to take the pointer from the found DT record which points to the GVT root block and start our search again from there using the level from the original block as a stopping point. One special case here is if our target block was a gvtroot block, we don't need to traverse the GVT tree to find it. We get it from the directory tree and stop our search there. */ switch(blk_type) { case gdsblk_dtindex: case gdsblk_dtleaf: case gdsblk_dtroot: /* Since our search is to end in the dt tree, stop when we get to the requisite level */ blk_index = dbc_find_dtblk(psa, psa->first_rec_key, blk_levl); if (0 > blk_index) { /* Integrity error encountered or record not found. We cannot proceed */ assert(FALSE); rts_error(VARLSTCNT(8) ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn), ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to find index (DT) record for an existing global")); } break; case gdsblk_gvtindex: case gdsblk_gvtleaf: /* Search all the way down to lvl 0 to get a dtleaf block */ dtblk_index = dbc_find_dtblk(psa, psa->first_rec_key, 0); if (0 > dtblk_index) { /* Integrity error encountered or record not found. We cannot proceed */ assert(FALSE); rts_error(VARLSTCNT(8) ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn), ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to locate DT leaf (root) block")); } assert(0 == ((v15_blk_hdr_ptr_t)psa->blk_set[dtblk_index].old_buff)->levl); /* Note level 0 directory blocks can have collation data in them but it would be AFTER the block pointer which is the first thing in the record after the key. */ GET_ULONG(blk_ptr, (psa->blk_set[dtblk_index].curr_rec + SIZEOF(rec_hdr) + psa->blk_set[dtblk_index].curr_blk_key->end + 1 - EVAL_CMPC((rec_hdr *)psa->blk_set[dtblk_index].curr_rec))); gvtblk_index = dbc_read_dbblk(psa, blk_ptr, gdsblk_gvtroot); assert(-1 != gvtblk_index); /* If our target block was not the gvtroot block we just read in then we keep scanning for our target record. Otherwise, the scan stops here. */ if (0 != gvtblk_index) { blk_index = dbc_find_record(psa, psa->first_rec_key, gvtblk_index, blk_levl, gdsblk_gvtroot, FALSE); if (0 > blk_index) { if (-1 == blk_index) { /* Integrity error encountered. We cannot proceed */ assert(FALSE); rts_error(VARLSTCNT(8) ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn), ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to find index record for an existing global")); } else if (-2 == blk_index) { /* Record was not found. Record has been deleted since we last found it. Elicits a warning message in DEBUG mode but is otherwise ignored. */ assert(FALSE); DBC_DEBUG(("DBC_DEBUG: Block split of blk 0x%x bypassed because its " "key could not be located in the GVT\n", blk_num)); psa->blks_bypassed++; psa->blks_read += psa->block_depth; /* Only way to properly update the count of cached records is to run the list and check them. */ for (blk_index = psa->block_depth, blk_set_p = &psa->blk_set[blk_index]; 0 <= blk_index; --blk_index, --blk_set_p) { /* Check each block we read */ if (gdsblk_create != blk_set_p->usage && blk_set_p->found_in_cache) psa->blks_cached++; } return FALSE; /* No restart necessary */ } else GTMASSERT; } } else { /* This is a gvtroot block and is the subject of our search */ blk_index = gvtblk_index; assert(gdsblk_gvtroot == psa->blk_set[0].blk_type); } break; default: GTMASSERT; } /* The most recently accessed block (that terminated the search) should be the block we are looking for (which should have been found in the cache as block 0. If not, there is an integrity error and we should not continue. */ if (0 != blk_index) { /* Integrity error encountered. We cannot proceed */ assert(FALSE); rts_error(VARLSTCNT(8) ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn), ERR_TEXT, 2, RTS_ERROR_LITERAL("Did not locate record in same block as we started searching for")); } /* If this is a gvtroot type block, we have some extra processing to do. Following is a description of the issue we are addressing here. If a gvtroot block is "too large" and was too large at the time the scan was run, it will of course be identified by the scan as too large. Prior to running the scan, the reserved bytes field was set so no more too-full blocks can be created. But if a gvtroot block is identified by the scan and subsequently has to be split by normal GTM processing before the certify can be done, the too-full part of the block can (in totality) end up in the right hand child of the gvtroot block (not obeying the reserved bytes rule). But the gvtroot block is the only one that was identified by the scan and certify may now miss the too-full block in the right child. Theoretically, the entire right child chain of the gvtroot block can be too full. Our purpose here is that when we have identified a gvtblock as being too full, we pause here to read the right child chain coming off of that block all the way down to (but not including) block level 0. Each of these blocks will be processed to check for being too full. The way we do this is to run the chain and build p1rec entries in the gvtroot_rchildren[] array. When we are at the top of the processing loop, we will take these array entries over records from the phase one input file. We only load up the array if it is empty. Otherwise, the assumption is that we are re-processing and the issue has already been handled. */ blk_set_p = &psa->blk_set[0]; if (gdsblk_gvtroot == blk_set_p->blk_type && 0 == psa->gvtroot_rchildren_cnt) { DBC_DEBUG(("DBC_DEBUG: Encountered gvtroot block (block %d [0x%08x]), finding/queueing children\n", blk_set_p->blk_num, blk_set_p->blk_num)); save_block_depth = psa->block_depth; /* These reads are temporary and should not remain in cache so we will restore block_depth after we are done. */ /* Attempting to locate the maximum possible key for this database should read the list of right children into the cache. Pretty much any returncode from dbc_find_record is possible. We usually aren't going to find the global which may come up as not found or an integrity error or it could possibly even be found. Just go with what it gives us. Not much verification we can do on it. */ blk_index = dbc_find_record(psa, psa->max_key, 0, 0, gdsblk_gvtroot, TRUE); /* Pull children (if any) out of cache and put into queue for later processing */ for (blk_index = save_block_depth + 1; blk_index <= psa->block_depth && gdsblk_gvtleaf != psa->blk_set[blk_index].blk_type; ++blk_index, ++psa->gvtroot_rchildren_cnt) { /* Fill in p1rec type entry in gvtroot_rchildren[] for later */ DBC_DEBUG(("DBC_DEBUG: Right child block: blk_index: %d blk_num: %d [0x%08x] blk_levl: %d\n", blk_index, psa->blk_set[blk_index].blk_num, psa->blk_set[blk_index].blk_num, psa->blk_set[blk_index].blk_levl)); psa->gvtroot_rchildren[psa->gvtroot_rchildren_cnt].tn = psa->blk_set[blk_index].tn; psa->gvtroot_rchildren[psa->gvtroot_rchildren_cnt].blk_num = psa->blk_set[blk_index].blk_num; psa->gvtroot_rchildren[psa->gvtroot_rchildren_cnt].blk_type = psa->blk_set[blk_index].blk_type; psa->gvtroot_rchildren[psa->gvtroot_rchildren_cnt].blk_levl = psa->blk_set[blk_index].blk_levl; psa->gvtroot_rchildren[psa->gvtroot_rchildren_cnt].akey_len = 0; } psa->block_depth = save_block_depth; blk_index = 0; /* reset to start *our* work in the very first block */ } /* Now we have done the gvtroot check if we were going to. If this particular block has sufficient room in it * we don't need to split it of course. */ if (UNIX_ONLY(8) VMS_ONLY(9) <= blk_size - blk_len) { /* This block has room now - no longer need to split it */ DBC_DEBUG(("DBC_DEBUG: Block not processed as it now has sufficient room\n")); psa->blks_bypassed++; psa->blks_read++; if (psa->blk_set[0].found_in_cache) psa->blks_cached++; return FALSE; /* No restart needed */ } /* Beginning of block update/split logic. We need to process the blocks in the reverse order from the tree path. This means blk_set[0] which is actually the block we want to split must be the first in our path. We then need to process the block array backwards in case the changes made to those records cause subsequent splits. First order of business is to find a suitable place to split this block .. Run through the records in the block until we are "halfway" through the block. Split so that the first record (after the first) whose end point is in the "second half" of the block will be the first record of the second half or right hand side block after the split. This makes sure that the left side has at least one record in it. We already know that this block has at least 2 records in it or it would not need splitting. */ rec_p = blk_p + SIZEOF(v15_blk_hdr); blk_set_p->curr_rec = rec_p; dbc_find_key(psa, blk_set_p->curr_blk_key, rec_p, blk_set_p->blk_levl); GET_USHORT(us_rec_len, &((rec_hdr *)rec_p)->rsiz); curr_rec_len = us_rec_len; next_rec_p = rec_p + curr_rec_len; blk_set_p->curr_match = 0; /* First record of block always cmpc 0 */ blk_len = ((v15_blk_hdr_ptr_t)blk_p)->bsiz; blk_endp = blk_p + blk_len; mid_point = blk_p + blk_size / 2; do { /* Keep scanning the next record until you find the split point which is the first record that straddles the * mid-point of the block. This loop makes sure the prev_key and curr_key fields are correctly set when we * enter the processing loop below. */ blk_set_p->prev_match = blk_set_p->curr_match; memcpy(blk_set_p->prev_blk_key, blk_set_p->curr_blk_key, (SIZEOF(dbc_gv_key) + blk_set_p->curr_blk_key->end)); rec_p = next_rec_p; /* Must be at least one record in LHS and one in RHS */ blk_set_p->prev_rec = blk_set_p->curr_rec; blk_set_p->curr_rec = rec_p; GET_USHORT(us_rec_len, &((rec_hdr *)rec_p)->rsiz); curr_rec_len = us_rec_len; dbc_find_key(psa, blk_set_p->curr_blk_key, rec_p, blk_set_p->blk_levl); blk_set_p->curr_match = EVAL_CMPC((rec_hdr *)rec_p); next_rec_p = rec_p + curr_rec_len; if (next_rec_p >= blk_endp) /* We have reached the last record in the block. Cannot skip anymore. */ break; if (next_rec_p >= mid_point) { /* The current record straddles the mid-point of the almost-full block. This is most likely going * to be the split point. If splitting at the current record causes the RHS block to continue to * be too-full and there is still room in the LHS block we will scan one more record in this loop. * Scanning this one more record should make the RHS block no longer too-full. This is asserted below. */ /* Compute the sizes of the LHS and RHS blocks assuming the current record moves into each of them */ if (blk_set_p->blk_levl) { /* Index block. The current record is changed into a *-key (a simple star key rec) */ new_lh_blk_len = (int)((rec_p - blk_p) + BSTAR_REC_SIZE); } else { /* Data block. Always simple split (no inserted record) */ new_lh_blk_len = (int)(next_rec_p - blk_p); assert(gdsblk_gvtleaf == blk_set_p->blk_type || gdsblk_dtleaf == blk_set_p->blk_type); } assert(0 < new_lh_blk_len); /* assert that the LHS block without the current record is guaranteed not to be too-full */ assert((new_lh_blk_len - (next_rec_p - rec_p)) <= psa->max_blk_len); /* Right hand side has key of curr_rec expanded since is first key of blcok */ new_rh_blk_len = (int)(SIZEOF(v15_blk_hdr) + blk_set_p->curr_match + blk_len - (rec_p - blk_p) ); assert(0 < new_rh_blk_len); if ((new_rh_blk_len <= psa->max_blk_len) || (new_lh_blk_len > psa->max_blk_len)) break; assert(FALSE == first_time); /* assert we never scan more than one record past mid-point of the block */ DEBUG_ONLY(first_time = TRUE;) } } while (TRUE); assert((rec_p - blk_p) < ((v15_blk_hdr_ptr_t)blk_p)->bsiz); /* Block processing loop */ bottom_tree_index = psa->block_depth; /* Record end of the tree in case need bit map blocks later */ update_array_ptr = update_array; /* Reset udpate array */ DBC_DEBUG(("DBC_DEBUG: Beginning split processing loop\n")); for (completed = FALSE; !completed;) { /* Backwards process until we hit a block with no changes to it */ DBC_DEBUG(("DBC_DEBUG: ******** Top of blk process loop for block index %d\n", blk_index)); assert(0 <= blk_index); blk_set_p = &psa->blk_set[blk_index]; assert(blk_set_p->blk_len == ((v15_blk_hdr_ptr_t)blk_set_p->old_buff)->bsiz); assert(blk_set_p->blk_levl == ((v15_blk_hdr_ptr_t)blk_set_p->old_buff)->levl); curr_blk_len = blk_set_p->blk_len; curr_blk_levl = blk_set_p->blk_levl; if (0 != blk_set_p->ins_rec.ins_key->end) { ins_key_len = blk_set_p->ins_rec.ins_key->end + 1; ins_rec_len = ins_key_len + SIZEOF(block_id); /* We only ever insert index records */ } else ins_key_len = ins_rec_len = 0; blk_p = blk_set_p->old_buff; /* If ins_rec_len has a non-zero value, then we need to reset the values for prev_match and key_match. These values were computed using the original scan key as their basis. Now we are using these fields to insert a new key. The positioning is still correct but the number of matching characters is potentially different. */ if (ins_rec_len) { if (0 != blk_set_p->prev_blk_key->end) { /* There is a "previous record" */ insert_point = dbc_match_key(blk_set_p->prev_blk_key, blk_set_p->blk_levl, blk_set_p->ins_rec.ins_key, &blk_set_p->prev_match); assert(!insert_point); /* This is prior to insert point (sanity check) */ } insert_point = dbc_match_key(blk_set_p->curr_blk_key, blk_set_p->blk_levl, blk_set_p->ins_rec.ins_key, &blk_set_p->curr_match); assert(insert_point); /* This is supposed to *be* the insert point */ } /* Make convenient copies of some commonly used record fields */ curr_rec_cmpc = EVAL_CMPC((rec_hdr *)blk_set_p->curr_rec); curr_rec_shrink = blk_set_p->curr_match - curr_rec_cmpc; curr_rec_offset = (int)(blk_set_p->curr_rec - blk_set_p->old_buff); GET_USHORT(us_rec_len, &((rec_hdr *)blk_set_p->curr_rec)->rsiz); curr_rec_len = us_rec_len; prev_rec_offset = (int)(blk_set_p->prev_rec - blk_set_p->old_buff); got_root = (gdsblk_dtroot == blk_set_p->blk_type) || (gdsblk_gvtroot == blk_set_p->blk_type); /* Decide if this record insert (if an insert exists) will cause a block split or not. If this is the first block in the tree (the one we got from the phase 1 file), there will be no insert. If we find a block that does not need to change, we are done and can exit the loop. This differs from the regular GT.M runtime which must keep checking even the split blocks but since we never add data to a level 0 block being split, we will never create split-off blocks that themselves are (still) too full. */ assert(gdsblk_read == blk_set_p->usage); new_blk_len = (int)(ins_rec_len ? (curr_blk_len + curr_rec_cmpc + SIZEOF(rec_hdr) + ins_rec_len - blk_set_p->prev_match - blk_set_p->curr_match) : curr_blk_len); /* No inserted rec, size does not change */ if (new_blk_len <= psa->max_blk_len) { /* "Simple" case .. we do not need a block split - only (possibly) a record added. Note that this is the only path where there may not be a "previous" record so we have to watch for that possibility. */ assert(0 != blk_index); /* Never insert a record into target blk so should never be here */ /* In this path we should always have an inserted record length. We should have detected we were done in an earlier loop iteration. */ assert(ins_rec_len); DBC_DEBUG(("DBC_DEBUG: Block index %d is a simple update\n", blk_index)); /* We must have an insert at this point and since we only ever insert records into index blocks, we must be in that situation */ assert(0 != curr_blk_levl); blk_set_p->usage = gdsblk_update; /* It's official .. blk is being modified */ /* We have a record to insert into this block but no split is needed */ BLK_INIT(bs_ptr, bs1); blk_set_p->upd_addr = bs1; /* Save address of our update array */ if (0 != blk_set_p->prev_blk_key->end) { /* First piece is block prior to the record + key + value */ BLK_SEG(bs_ptr, blk_set_p->old_buff + SIZEOF(v15_blk_hdr), (curr_rec_offset - SIZEOF(v15_blk_hdr))); } BLK_ADDR(ins_rec_hdr, SIZEOF(rec_hdr), rec_hdr); /* Setup new record header */ new_rec_len = (int)(SIZEOF(rec_hdr) + ins_rec_len - blk_set_p->prev_match); ins_rec_hdr->rsiz = new_rec_len; SET_CMPC(ins_rec_hdr, blk_set_p->prev_match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)ins_rec_hdr, SIZEOF(rec_hdr)); /* Setup key */ BLK_ADDR(cp1, blk_set_p->ins_rec.ins_key->end + 1 - blk_set_p->prev_match, unsigned char); memcpy(cp1, blk_set_p->ins_rec.ins_key->base + blk_set_p->prev_match, blk_set_p->ins_rec.ins_key->end + 1 - blk_set_p->prev_match); BLK_SEG(bs_ptr, cp1, blk_set_p->ins_rec.ins_key->end + 1 - blk_set_p->prev_match); /* Setup value (all index records have value of size "block_id". The proper value is either there already or will be when we go to commit these changes. */ BLK_SEG(bs_ptr, (sm_uc_ptr_t)&blk_set_p->ins_rec.blk_id, SIZEOF(block_id)); /* For index blocks, we know that since a star key is the last record in the block (which is the last record that can be curr_rec) that there is a trailing portion of the block we need to output. */ BLK_ADDR(next_rec_hdr, SIZEOF(rec_hdr), rec_hdr); /* Replacement rec header */ next_rec_hdr->rsiz = curr_rec_len - curr_rec_shrink; SET_CMPC(next_rec_hdr, blk_set_p->curr_match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)next_rec_hdr, SIZEOF(rec_hdr)); remain_offset = curr_rec_shrink + SIZEOF(rec_hdr); /* Where rest of record plus any further records begin */ remain_len = curr_blk_len - curr_rec_offset; BLK_SEG(bs_ptr, blk_set_p->curr_rec + remain_offset, remain_len - remain_offset); if (0 == BLK_FINI(bs_ptr, bs1)) GTMASSERT; assert(blk_seg_cnt == new_blk_len); DBC_DEBUG(("DBC_DEBUG: Stopping block scan after simple update (no further inserts to previous lvls)\n")); completed = TRUE; break; } else { /* The block is either already too large or would be too large when the record is inserted and so it must be split. There are two different ways a block can be split. It can either be split so that: (1) the inserted record is at the end of the left block or, (2) the record is the first record in the right half. Compute the left/right block sizes for these two options and see which one does not force a secondary block split (one of them must be true here unlike in GT.M code because here we are NEVER adding a record to a level 0 block, we only split lvl 0 blocks as needed). Note that the case where we are splitting a level 0 block with no record insert is treated as an unremarkable variant of option (1) as described above. Follow the conventions of gvcst_put (LHS to new block, RHS to old block): (1) If we are inserting the record into the lefthand side then a new split-off block will receive the first part of the block including the record. The remainder of the block is placed into the current (existing) block. (2) If we are putting the record into the righthand side, then a new split-off block will receive the first part of the block. The new record plus the remainder of the block is placed into the current block. The sole exception to the above is if a root block (either DT or GVT) is being split. In that case, BOTH the LHS and RHS become NEW blocks and the root block is (a) increased in level and (b) contains only entries for the two created blocks. Note that gvcst_put has several additional checks and balances here that we are forgoing such as making sure the blocks are as balanced as possible, concurrency concerns, etc. They add un-needed complications to this one-time code. Any inefficiencies here can be undone with a pass of MUPIP REORG. */ DBC_DEBUG(("DBC_DEBUG: Block index %d needs to be split\n", blk_index)); /* First up is split so that the inserted record (if any) is the last record in the left hand block. Note if this is an index block, the last record must be a star key rec as per option (1) above. */ if (curr_blk_levl) /* Index block. Two cases: (a) We are adding a key to the end in which case it is just a simple star key rec or (b) No record is being added so the previous record is changed into a star key rec. */ new_lh_blk_len = (int)(curr_rec_offset + BSTAR_REC_SIZE - (ins_rec_len ? 0 : (blk_set_p->curr_rec - blk_set_p->prev_rec))); else { /* Data block. Always simple split (no inserted record) */ new_lh_blk_len = curr_rec_offset; assert(gdsblk_gvtleaf == blk_set_p->blk_type || gdsblk_dtleaf == blk_set_p->blk_type); } assert(0 < new_lh_blk_len); /* Right hand side has key of curr_rec expanded since is first key of blcok */ new_rh_blk_len = (int)(SIZEOF(v15_blk_hdr) + EVAL_CMPC((rec_hdr *)blk_set_p->curr_rec) + (curr_blk_len - curr_rec_offset)); assert(0 < new_rh_blk_len); /* Common initialization */ ++psa->block_depth; /* Need a new block to split into */ if (MAX_BLOCK_INFO_DEPTH <= psa->block_depth) GTMASSERT; DBC_DEBUG(("DBC_DEBUG: Block index %d used for newly created split (lhs) block\n", psa->block_depth)); blk_set_new_p = &psa->blk_set[psa->block_depth]; dbc_init_blk(psa, blk_set_new_p, -1, gdsblk_create, new_lh_blk_len, curr_blk_levl); if (got_root) /* If root, the LHS sub-block is a different type */ blk_set_new_p->blk_type = (gdsblk_gvtroot == blk_set_p->blk_type) ? gdsblk_gvtindex : gdsblk_dtindex; else blk_set_new_p->blk_type = blk_set_p->blk_type; /* Complete our LHS block */ BLK_INIT(bs_ptr, bs1); /* Our new block to create */ blk_set_new_p->upd_addr = bs1; level_0 = (0 == curr_blk_levl); /* See if they fit in their respective blocks */ if (level_0 || (new_lh_blk_len <= psa->max_blk_len) && (new_rh_blk_len <= psa->max_blk_len)) { /* Method 1 - record goes to left-hand side */ DBC_DEBUG(("DBC_DEBUG: Method 1 block lengths: lh: %d rh: %d max_blk_len: %d\n", new_lh_blk_len, new_rh_blk_len, psa->max_blk_len)); /* New update array for new block */ if (level_0) { /* Level 0 block, we are only splitting it -- never adding a record */ assert(curr_rec_offset <= psa->max_blk_len); BLK_SEG(bs_ptr, blk_set_p->old_buff + SIZEOF(v15_blk_hdr), curr_rec_offset - SIZEOF(v15_blk_hdr)); assert(0 == ins_rec_len); /* Never insert records to lvl0 */ if (new_rh_blk_len > psa->max_blk_len) { /* Case of a data block that has a DBCREC2BIG error unnoticed by DBCERTIFY SCAN. * Should not happen normally. But in case it does in production, we will handle * it by NOT certifying the database and requiring a rerun of the SCAN */ assert(FALSE); gtm_putmsg(VARLSTCNT(6) ERR_DBCREC2BIGINBLK, 4, blk_num, psa->dbc_cs_data->max_rec_size, psa->dbc_gv_cur_region->dyn.addr->fname_len, psa->dbc_gv_cur_region->dyn.addr->fname); psa->blk_process_errors++; /* must be zero to certify db at end */ } } else { /* Index block -- may or may not be adding a record. If adding a record, the inserted record becomes a star key record. If not adding a record the last record is morphed into a star key record. */ BLK_SEG(bs_ptr, blk_set_p->old_buff + SIZEOF(v15_blk_hdr), (ins_rec_len ? curr_rec_offset : prev_rec_offset) - SIZEOF(v15_blk_hdr)); BLK_ADDR(new_star_hdr, SIZEOF(rec_hdr), rec_hdr); new_star_hdr->rsiz = BSTAR_REC_SIZE; SET_CMPC(new_star_hdr, 0); BLK_SEG(bs_ptr, (uchar_ptr_t)new_star_hdr, SIZEOF(rec_hdr)); BLK_SEG(bs_ptr, (ins_rec_len ? (uchar_ptr_t)&blk_set_p->ins_rec.blk_id : (blk_set_p->prev_rec + SIZEOF(rec_hdr) + blk_set_p->prev_blk_key->end + 1 - EVAL_CMPC((rec_hdr *)blk_set_p->prev_rec))), SIZEOF(block_id)); } /* Complete our LHS block */ if (0 == BLK_FINI(bs_ptr, bs1)) GTMASSERT; assert(blk_seg_cnt == new_lh_blk_len); /* Remember key of last record in this block */ if (0 == ins_rec_len) last_rec_key = blk_set_p->prev_blk_key; else last_rec_key = blk_set_p->ins_rec.ins_key; if (!got_root) { /* New block created, insert record to it in parent block. To do this we create a record with the last key in this LH block to be inserted between curr_rec and prev_rec of the parent block. */ if (0 == blk_index) blk_set_prnt_p = &psa->blk_set[bottom_tree_index]; /* Cycle back up to parent */ else blk_set_prnt_p = blk_set_p - 1; assert(blk_set_prnt_p != &psa->blk_set[0]); assert(NULL != last_rec_key); /* Note: We do not need the "+ 1" on the key length since SIZEOF(dbc_gv_key) contains the first character of the key so the "+ 1" to get the last byte of the key is already integrated into the length */ memcpy(blk_set_prnt_p->ins_rec.ins_key, last_rec_key, SIZEOF(dbc_gv_key) + last_rec_key->end); /* Setup so that creation of the blk_set_new_p block can then set its block id into our parent block's insert rec buffer which will be made part of the inserted record at block build time */ blk_set_new_p->ins_blk_id_p = &blk_set_prnt_p->ins_rec.blk_id; blk_set_rhs_p = blk_set_p; /* Use original block for rhs */ blk_set_rhs_p->usage = gdsblk_update; } else { /* Have root block: need to put the RHS into a new block too */ DBC_DEBUG(("DBC_DEBUG: Splitting root block, extra block to be created\n")); ++psa->block_depth; /* Need a new block to split into */ if (MAX_BLOCK_INFO_DEPTH <= psa->block_depth) GTMASSERT; blk_set_rhs_p = &psa->blk_set[psa->block_depth]; dbc_init_blk(psa, blk_set_rhs_p, -1, gdsblk_create, new_rh_blk_len, curr_blk_levl); /* We will put the pointers to both this block and the RHS we build next into the original root block -- done later when RHS is complete */ /* If root, the RHS sub-block is a different type */ blk_set_rhs_p->blk_type = (gdsblk_gvtroot == blk_set_p->blk_type) ? gdsblk_gvtindex : gdsblk_dtindex; } /**** Now build RHS into either current or new block ****/ BLK_INIT(bs_ptr, bs1); blk_set_rhs_p->upd_addr = bs1; /* Block building roadmap.. */ BLK_ADDR(next_rec_hdr, SIZEOF(rec_hdr), rec_hdr); next_rec_hdr->rsiz = curr_rec_len + curr_rec_cmpc; SET_CMPC(next_rec_hdr, 0); BLK_SEG(bs_ptr, (uchar_ptr_t)next_rec_hdr, SIZEOF(rec_hdr)); /* Copy the previously compressed part of the key out of curr_rec. Note, if this key is a star rec key, nothing is written because cmpc is zero */ if (curr_rec_cmpc) { BLK_ADDR(cp1, curr_rec_cmpc, unsigned char); memcpy(cp1, blk_set_p->curr_blk_key->base, curr_rec_cmpc); BLK_SEG(bs_ptr, cp1, curr_rec_cmpc); } /* Remainder of existing block */ BLK_SEG(bs_ptr, blk_set_p->curr_rec + SIZEOF(rec_hdr), curr_blk_len - curr_rec_offset - SIZEOF(rec_hdr)); /* Complete update array */ if (0 == BLK_FINI(bs_ptr, bs1)) GTMASSERT; assert(blk_seg_cnt == new_rh_blk_len); } else { /* Recompute sizes for inserted record being in righthand block as per method (2) */ DBC_DEBUG(("DBC_DEBUG: Method 1 created invalid blocks: lh: %d rh: %d " "max_blk_len: %d -- trying method 2\n", new_lh_blk_len, new_rh_blk_len, psa->max_blk_len)); /* By definition we *must* have an inserted record in this path */ assert(0 != ins_rec_len); /* New block sizes - note because we *must* be inserting a record in this method, the only case considered here is when we are operating on an index block. */ assert(!level_0); /* Last record turns into star key record */ new_lh_blk_len = (int)(curr_rec_offset + BSTAR_REC_SIZE - (blk_set_p->curr_rec - blk_set_p->prev_rec) ); assert(0 < new_lh_blk_len); new_rh_blk_len = (int)(SIZEOF(v15_blk_hdr) + SIZEOF(rec_hdr) + ins_rec_len + curr_blk_len - (curr_rec_offset) - curr_rec_shrink); assert(0 < new_rh_blk_len); if (new_lh_blk_len > psa->max_blk_len || new_rh_blk_len > psa->max_blk_len) { /* This is possible if we are inserting a record into a block (and thus we are not picking the insertion point) and the insertion point is either the first or next-to-last record in the block such that neither method 1 nor 2 can create blocks of acceptable size. In this case, although this problem block is likely on the list of blocks to process, we cannot wait and thus must perform the split now. To do that, we call this same routine recursively with the necessary parms to process *THIS* block. Since this will destroy all the structures we had built up, signal a transaction restart which will re-read everything and should allow the transaction we were processing to proceed. */ if (curr_blk_len <= psa->max_blk_len) /* Well, that wasn't the problem, something else is wrong */ rts_error(VARLSTCNT(8) ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn), ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to split block appropriately")); /* If we do have to restart, we won't be able to reinvoke dbc_split_blk() with the parms taken from the current blk_set_p as that array will be overwritten by the recursion. Save the current blk_set_p so we can use it in a restartable context. */ restart_blk_set = *blk_set_p; for (restart_cnt = 0, restart_transaction = TRUE; restart_transaction; ++restart_cnt) { if (MAX_RESTART_CNT < restart_cnt) GTMASSERT; /* No idea what could cause this */ DBC_DEBUG(("DBC_DEBUG: *** *** Recursive call to handle too large block 0x%x\n", restart_blk_set.blk_num)); psa->block_depth_hwm = -1; /* Zaps cache so all blocks are re-read */ restart_transaction = dbc_split_blk(psa, restart_blk_set.blk_num, restart_blk_set.blk_type, restart_blk_set.tn, restart_blk_set.blk_levl); } return TRUE; /* This transaction must restart */ } DBC_DEBUG(("DBC_DEBUG: Method 2 block lengths: lh: %d rh: %d max_blk_len: %d\n", new_lh_blk_len, new_rh_blk_len, psa->max_blk_len)); /* Start building (new) LHS block - for this index record, the record before the split becomes a new *-key. Note: If the block split was caused by our appending the new record to the end of the block, this code causes the record PRIOR to the current *-key to become the new *-key. */ BLK_SEG(bs_ptr, blk_set_p->old_buff + SIZEOF(v15_blk_hdr), prev_rec_offset - SIZEOF(v15_blk_hdr)); /* Replace last record with star key rec */ BLK_ADDR(new_star_hdr, SIZEOF(rec_hdr), rec_hdr); new_star_hdr->rsiz = BSTAR_REC_SIZE; SET_CMPC(new_star_hdr, 0); BLK_SEG(bs_ptr, (uchar_ptr_t)new_star_hdr, SIZEOF(rec_hdr)); /* Output pointer from prev_rec as star key record's value */ BLK_SEG(bs_ptr, blk_set_p->curr_rec - SIZEOF(block_id), SIZEOF(block_id)); /* Complete our LHS block */ if (0 == BLK_FINI(bs_ptr, bs1)) GTMASSERT; assert(blk_seg_cnt == new_lh_blk_len); if (!got_root) { /* New block created, insert record to it in parent block. To do this we create a record with the last key in this LH block to be inserted between curr_rec and prev_rec of the parent block. */ if (0 == blk_index) blk_set_prnt_p = &psa->blk_set[bottom_tree_index]; /* Cycle back up to parent */ else blk_set_prnt_p = blk_set_p - 1; assert(blk_set_prnt_p != &psa->blk_set[0]); assert(NULL != blk_set_p->prev_blk_key); /* Note: We do not need the "+ 1" on the key length since SIZEOF(dbc_gv_key) contains the first character of the key so the "+ 1" to get the last byte of the key is already integrated into the length */ memcpy(blk_set_prnt_p->ins_rec.ins_key, blk_set_p->prev_blk_key, SIZEOF(dbc_gv_key) + blk_set_p->prev_blk_key->end); /* Setup so that creation of the blk_set_new_p block can then set its block id into our parent block's insert rec buffer which will be made part of the inserted record at block build time */ blk_set_new_p->ins_blk_id_p = &blk_set_prnt_p->ins_rec.blk_id; blk_set_rhs_p = blk_set_p; /* Use original block for rhs */ blk_set_rhs_p->usage = gdsblk_update; } else { /* Have root block: need to put the RHS into a new block too */ DBC_DEBUG(("DBC_DEBUG: Splitting root block, extra block to be created\n")); ++psa->block_depth; /* Need a new block to split into */ if (MAX_BLOCK_INFO_DEPTH <= psa->block_depth) GTMASSERT; blk_set_rhs_p = &psa->blk_set[psa->block_depth]; /* Key for last record in the LHS block used to (re)construct root block */ last_rec_key = blk_set_p->curr_blk_key; dbc_init_blk(psa, blk_set_rhs_p, -1, gdsblk_create, new_rh_blk_len, curr_blk_levl); /* We will put the pointers to both this block and the RHS we build next into the original root block -- done later when RHS is complete */ /* If root, the RHS sub-block is a different type */ blk_set_rhs_p->blk_type = (gdsblk_gvtroot == blk_set_p->blk_type) ? gdsblk_gvtindex : gdsblk_dtindex; } /**** Now build RHS into current block ****/ BLK_INIT(bs_ptr, bs1); blk_set_rhs_p->upd_addr = bs1; /* Block building roadmap.. */ /* Build record header for inserted record. Inserted record is always for index type blocks */ BLK_ADDR(ins_rec_hdr, SIZEOF(rec_hdr), rec_hdr); ins_rec_hdr->rsiz = SIZEOF(rec_hdr) + blk_set_p->ins_rec.ins_key->end + 1 + SIZEOF(block_id); SET_CMPC(ins_rec_hdr, 0); BLK_SEG(bs_ptr, (uchar_ptr_t)ins_rec_hdr, SIZEOF(rec_hdr)); /* Now for the inserted record key */ BLK_SEG(bs_ptr, blk_set_p->ins_rec.ins_key->base, blk_set_p->ins_rec.ins_key->end + 1); /* Finally the inserted record value always comes from the block_id field. It is not filled in now but will be when the block it refers to is created. */ BLK_SEG(bs_ptr, (uchar_ptr_t)&blk_set_p->ins_rec.blk_id, SIZEOF(block_id)); /* Record that was first in RH side now needs its cmpc (and length) reset since it is now the second record in the new block. */ BLK_ADDR(next_rec_hdr, SIZEOF(rec_hdr), rec_hdr); next_rec_hdr->rsiz = curr_rec_len - curr_rec_shrink; SET_CMPC(next_rec_hdr, blk_set_p->curr_match); BLK_SEG(bs_ptr, (uchar_ptr_t)next_rec_hdr, SIZEOF(rec_hdr)); remain_offset = curr_rec_shrink + SIZEOF(rec_hdr); /* Where rest of record plus any further records begin */ remain_len = curr_blk_len - curr_rec_offset; BLK_SEG(bs_ptr, blk_set_p->curr_rec + remain_offset, remain_len - remain_offset); if (0 == BLK_FINI(bs_ptr, bs1)) GTMASSERT; assert(blk_seg_cnt == new_rh_blk_len); } /* else method (2) */ if (got_root) { /* If we have split a root block, we need to now set the pointers to the new LHS and RHS blocks into the root block as the only records. Note this requires a level increase of the tree. Hopefully we will not come across a database that is already at maximum level. If so, the only way to reduce the level is to run MUPIP REORG with a fairly recent vintage of GT.M */ BLK_INIT(bs_ptr, bs1); blk_set_p->usage = gdsblk_update; /* It's official .. blk is being modified */ blk_set_p->upd_addr = bs1; /* Block building roadmap.. */ blk_set_p->blk_levl++; /* Needs to be at a new level */ if (MAX_BT_DEPTH <= blk_set_p->blk_levl) /* Tree is too high */ GTMASSERT; /* First record will have last key in LHS block */ BLK_ADDR(next_rec_hdr, SIZEOF(rec_hdr), rec_hdr); next_rec_hdr->rsiz = SIZEOF(rec_hdr) + last_rec_key->end + 1 + SIZEOF(block_id); SET_CMPC(next_rec_hdr, 0); BLK_SEG(bs_ptr, (uchar_ptr_t)next_rec_hdr, SIZEOF(rec_hdr)); BLK_SEG(bs_ptr, last_rec_key->base, (last_rec_key->end + 1)); BLK_ADDR(lhs_block_id_p, SIZEOF(block_id), block_id); /* First record's value */ BLK_SEG(bs_ptr, (uchar_ptr_t)lhs_block_id_p, SIZEOF(block_id)); blk_set_new_p->ins_blk_id_p = lhs_block_id_p; /* Receives block id when created */ /* Second record is a star key record pointing to the RHS block */ BLK_ADDR(new_star_hdr, SIZEOF(rec_hdr), rec_hdr); new_star_hdr->rsiz = BSTAR_REC_SIZE; SET_CMPC(new_star_hdr, 0); BLK_SEG(bs_ptr, (uchar_ptr_t)new_star_hdr, SIZEOF(rec_hdr)); BLK_ADDR(rhs_block_id_p, SIZEOF(block_id), block_id); /* First record's value */ BLK_SEG(bs_ptr, (uchar_ptr_t)rhs_block_id_p, SIZEOF(block_id)); blk_set_rhs_p->ins_blk_id_p = rhs_block_id_p; /* Receives block id when created */ /* Complete update array */ if (0 == BLK_FINI(bs_ptr, bs1)) GTMASSERT; /* The root block is the last one we need to change */ DBC_DEBUG(("DBC_DEBUG: Stopping block scan as blk_index %d is a root block\n", blk_index)); completed = TRUE; break; } } /* else need block split */ if (0 != blk_index) blk_index--; /* working backwards.. */ else blk_index = bottom_tree_index; } /* while !completed */ assert(completed); /* Check that we have sufficient free blocks to create the blccks we need (if any) */ created_blocks = psa->block_depth - bottom_tree_index; if (created_blocks > psa->dbc_cs_data->trans_hist.free_blocks) { /* We have a slight problem in that this transaction requires more free blocks than are available. Our recourse is to flush the current file-header preserving any changes we have already made, close the file and execute a mupip command to perform an extension before re-opening the db for further processing. */ DBC_DEBUG(("DBC_DEBUG: Insufficient free blocks for this transaction - calling MUPIP EXTEND\n")); dbc_flush_fhead(psa); dbc_close_db(psa); extent_size = MAX(psa->dbc_cs_data->extension_size, created_blocks); /* Now build command file to perform the MUPIP EXTEND for the region */ dbc_open_command_file(psa); dbc_write_command_file(psa, MUPIP_START); strcpy((char_ptr_t)psa->util_cmd_buff, MUPIP_EXTEND); strcat((char_ptr_t)psa->util_cmd_buff, (char_ptr_t)psa->ofhdr.regname); strcat((char_ptr_t)psa->util_cmd_buff, " "OPTDELIM"B="); chr_p = psa->util_cmd_buff + strlen((char_ptr_t)psa->util_cmd_buff); chr_p = i2asc(chr_p, extent_size); *chr_p = 0; dbc_write_command_file(psa, (char_ptr_t)psa->util_cmd_buff); UNIX_ONLY(dbc_write_command_file(psa, "EOF")); dbc_close_command_file(psa); dbc_run_command_file(psa, "MUPIP", (char_ptr_t)psa->util_cmd_buff, FALSE); /* Seeing as how it is very difficult to (in portable code) get a coherent error code back from an executed command, we will just assume it worked, open the database back in and see if in fact it did actually extend sufficiently. If not, this is a perm error and we stop here. */ dbc_init_db(psa); if (created_blocks > psa->dbc_cs_data->trans_hist.free_blocks) rts_error(VARLSTCNT(4) ERR_DBCNOEXTND, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn)); /* Database is now extended -- safest bet is to restart this particular update so that it is certain nothing else got in besides the extention. */ DBC_DEBUG(("DBC_DEBUG: Restarting processing of this p1rec due to DB extension\n")); return TRUE; } /* The update arrarys are complete, we know there are sufficient free blocks in the database to accomodate the splitting we have to do. */ bottom_created_index = psa->block_depth; /* From here on out are bit map blocks */ if (0 != created_blocks) { /* Run through the created blocks assigning block numbers and filling the numbers into the buffers that need them. If we didn't create any blocks, we know we didn't split any and there is nothing to do for this p1 record. */ total_blks = psa->dbc_cs_data->trans_hist.total_blks; local_map_max = DIVIDE_ROUND_UP(total_blks, psa->dbc_cs_data->bplmap); DBC_DEBUG(("DBC_DEBUG: Assigning block numbers to created DB blocks\n")); for (blk_index = psa->block_depth, blk_set_p = &psa->blk_set[blk_index]; bottom_tree_index < blk_index; --blk_index, --blk_set_p) { assert(gdsblk_create == blk_set_p->usage); assert(NULL != blk_set_p->upd_addr); /* Find and allocate a database block for this created block */ assert(NULL != blk_set_p->ins_blk_id_p); /* Must be a place to put the block id */ /* First find local bit map with some room in it */ lclmap_not_full = bmm_find_free(psa->hint_blk / psa->dbc_cs_data->bplmap, (sm_uc_ptr_t)psa->dbc_cs_data->master_map, local_map_max); if (NO_FREE_SPACE == lclmap_not_full) { assert(FALSE); rts_error(VARLSTCNT(5) ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn), ERR_BITMAPSBAD); } if (ROUND_DOWN2(psa->hint_blk, psa->dbc_cs_data->bplmap) != lclmap_not_full) psa->hint_lcl = 1; bitmap_blk_num = lclmap_not_full * psa->dbc_cs_data->bplmap; /* Read this bitmap in. Note it may already exist in the cache (likely for multiple creates) */ lbm_blk_index = dbc_read_dbblk(psa, bitmap_blk_num, gdsblk_bitmap); blk_set_bm_p = &psa->blk_set[lbm_blk_index]; assert(IS_BML(blk_set_bm_p->old_buff)); /* Verify we have a bit map block */ assert(ROUND_DOWN2(blk_set_bm_p->blk_num, psa->dbc_cs_data->bplmap) == blk_set_bm_p->blk_num); if (ROUND_DOWN2(psa->dbc_cs_data->trans_hist.total_blks, psa->dbc_cs_data->bplmap) == bitmap_blk_num) /* This bitmap is the last one .. compute total blks in partial this bitmap */ blks_this_lmap = (psa->dbc_cs_data->trans_hist.total_blks - bitmap_blk_num); else /* Regular bitmap (not last one) */ blks_this_lmap = psa->dbc_cs_data->bplmap; lcl_map_p = blk_set_bm_p->old_buff + SIZEOF(v15_blk_hdr); lcl_blk = psa->hint_lcl = bm_find_blk(psa->hint_lcl, lcl_map_p, blks_this_lmap, &dummy_bool); if (NO_FREE_SPACE == lcl_blk) { assert(FALSE); rts_error(VARLSTCNT(5) ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn), ERR_BITMAPSBAD); } /* Found a free block, mark it busy. Note that bitmap blocks are treated somewhat differently than other blocks. We do not create an update array for them but just change the copy in old_buff as appropriate. */ bml_busy(lcl_blk, lcl_map_p); blk_set_bm_p->usage = gdsblk_update; /* See if entire block is full - if yes, we need to mark master map too */ psa->hint_lcl = bml_find_free(psa->hint_lcl, lcl_map_p, blks_this_lmap); if (NO_FREE_SPACE == psa->hint_lcl) { /* Local map was filled .. clear appropriate master map bit */ DBC_DEBUG(("DBC_DEBUG: -- Local map now full - marking master map\n")); bit_clear(bitmap_blk_num / psa->dbc_cs_data->bplmap, psa->dbc_cs_data->master_map); } assert(lcl_blk); /* Shouldn't be zero as that is for the lcl bitmap itself */ allocated_blk_num = psa->hint_blk = bitmap_blk_num + lcl_blk; DBC_DEBUG(("DBC_DEBUG: -- The newly allocated block for block index %d is 0x%x\n", blk_index, allocated_blk_num)); /* Fill this block number in the places it needs to be filled */ assert(-1 == blk_set_p->blk_num); blk_set_p->blk_num = allocated_blk_num; *blk_set_p->ins_blk_id_p = allocated_blk_num; psa->dbc_cs_data->trans_hist.free_blocks--; /* There is one fewer free blocks tonite */ assert(0 <= (int)psa->dbc_cs_data->trans_hist.free_blocks); psa->dbc_fhdr_dirty = TRUE; } /* Now that all the block insertions have been filled in, run the entire chain looking for both created and updated blocks. Build the new versions of their blocks in new_buff. */ DBC_DEBUG(("DBC_DEBUG: Create new and changed blocks via their update arrays\n")); for (blk_index = psa->block_depth, blk_set_p = &psa->blk_set[blk_index]; 0 <= blk_index; --blk_index, --blk_set_p) { /* Run through the update array for this block */ blk_sega_p = (blk_segment *)blk_set_p->upd_addr; if (gdsblk_bitmap == blk_set_p->blk_type || gdsblk_read == blk_set_p->usage) { /* Bitmap blocks are updated in place and of course read blocks have no updates */ DBC_DEBUG(("DBC_DEBUG: -- Block index %d bypassed for type (%d) or usage (%d)\n", blk_index, blk_set_p->blk_type, blk_set_p->usage)); assert(NULL == blk_sega_p); continue; } DBC_DEBUG(("DBC_DEBUG: -- Block index %d being (re)built\n", blk_index)); assert(NULL != blk_sega_p); new_blk_len = INTCAST(blk_sega_p->len); new_blk_p = blk_set_p->new_buff; ((v15_blk_hdr_ptr_t)new_blk_p)->bsiz = blk_set_p->blk_len = new_blk_len; ((v15_blk_hdr_ptr_t)new_blk_p)->levl = blk_set_p->blk_levl; /* VMS has an unalighed tn. All UNIX variants have an aligned TN */ VMS_ONLY(PUT_ULONG(&((v15_blk_hdr_ptr_t)new_blk_p)->tn, psa->dbc_cs_data->trans_hist.curr_tn)); UNIX_ONLY(((v15_blk_hdr_ptr_t)new_blk_p)->tn = psa->dbc_cs_data->trans_hist.curr_tn); new_blk_p += SIZEOF(v15_blk_hdr); for (blk_array_top = (blk_segment *)blk_sega_p->addr, blk_sega_p++; blk_sega_p <= blk_array_top; blk_sega_p++) { /* Start with first subtantive array entry ([1]) and do the segment move thing */ memcpy(new_blk_p, blk_sega_p->addr, blk_sega_p->len); new_blk_p += blk_sega_p->len; } assert((new_blk_p - blk_set_p->new_buff) == new_blk_len); } /* One last pass through the block list to do the physical IO on the database */ psa->fc->op = FC_WRITE; psa->fc->op_len = blk_size; /* Just write the full block out regardless */ DBC_DEBUG(("DBC_DEBUG: Flush all modified blocks out to disk for this transaction\n")); psa->dbc_critical = TRUE; for (blk_index = psa->block_depth, blk_set_p = &psa->blk_set[blk_index]; 0 <= blk_index; --blk_index, --blk_set_p) { /* Output all modified/created blocks */ if (gdsblk_create != blk_set_p->usage) { /* We read everything but created blocks and some of them were found in cache */ psa->blks_read++; if (blk_set_p->found_in_cache) psa->blks_cached++; } if (gdsblk_read == blk_set_p->usage) { DBC_DEBUG(("DBC_DEBUG: -- Block index %d bypassed for usage (read)\n", blk_index)); continue; /* Nothing to do for read-only block */ } if (gdsblk_bitmap == blk_set_p->blk_type) { /* Bitmap blocks are built in old_buff, swap with new_buff. This also lets the buffer be reused correctly (by dbc_read_dbblk) if we read this block into the same place later. */ blk_p = blk_set_p->new_buff; blk_set_p->new_buff = blk_set_p->old_buff; blk_set_p->old_buff = blk_p; } DBC_DEBUG(("DBC_DEBUG: -- Block index %d being written as block 0x%x\n", blk_index, blk_set_p->blk_num)); psa->fc->op_buff = blk_set_p->new_buff; psa->fc->op_pos = psa->dbc_cs_data->start_vbn + ((gtm_int64_t)(blk_size / DISK_BLOCK_SIZE) * blk_set_p->blk_num); dbcertify_dbfilop(psa); if (gdsblk_create == blk_set_p->usage) psa->blks_created++; else psa->blks_updated++; } psa->dbc_critical = FALSE; if (forced_exit) { /* Our exit was deferred until we cleared the critical section area */ UNIX_ONLY(dbcertify_deferred_signal_handler()); VMS_ONLY(sys$exit(exi_condition)); } /* Update the transaction number in the fileheader for the next transaction */ psa->dbc_cs_data->trans_hist.curr_tn++; psa->dbc_fhdr_dirty = TRUE; } else GTMASSERT; /* If we got this far we should have split a block which would create a block */ DBC_DEBUG(("DBC_DEBUG: Block processing completed\n")); psa->blks_processed++; return FALSE; /* No transaction restart necessary */ } /* Flush the file-header back out to the database */ void dbc_flush_fhead(phase_static_area *psa) { if (!psa->dbc_fhdr_dirty) return; /* Nothing to do if it wasn't dirtied */ psa->fc->op = FC_WRITE; psa->fc->op_buff = (uchar_ptr_t)psa->dbc_cs_data; psa->fc->op_pos = 1; psa->fc->op_len = SIZEOF(v15_sgmnt_data); dbcertify_dbfilop(psa); psa->dbc_fhdr_dirty = FALSE; return; } /* Read the next output record into the buffer provided */ void dbc_read_p1out(phase_static_area *psa, void *obuf, int olen) { int rc, save_errno; char_ptr_t errmsg; DOREADRC(psa->outfd, obuf, olen, rc); if (-1 == rc) { save_errno = errno; errmsg = STRERROR(save_errno); assert(FALSE); rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("read()"), CALLFROM, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg)); } } /* Exit/cleanup routine */ void dbc_certify_phase_cleanup(void) { phase_static_area *psa; psa = psa_gbl; if (psa->dbc_gv_cur_region && psa->dbc_gv_cur_region->dyn.addr && psa->dbc_gv_cur_region->dyn.addr->file_cntl) { dbc_flush_fhead(psa); dbc_close_db(psa); if (psa->dbc_critical) rts_error(VARLSTCNT(4) ERR_TEXT, 2, RTS_ERROR_LITERAL("Failure while in critical section -- database damage likely")); } UNIX_ONLY(dbc_release_standalone_access(psa)); if (psa_gbl->tmp_file_names_gend) { /* Only close/delete if we know what they are */ if (psa->tcfp) dbc_close_command_file(psa); if (!psa->keep_temp_files) dbc_remove_command_file(psa); if (psa->trfp) dbc_close_result_file(psa); if (!psa->keep_temp_files) dbc_remove_result_file(psa); } } fis-gtm-V6.0-003/sr_port/dbcertify_funcs.c0000644000032200000250000011405212201176155017352 0ustar librarygtc/**************************************************************** * * * Copyright 2005, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #define _POSIX_EXIT /* Needed for VMS system() call */ /* BYPASSOK: system() used insode the comment, no SYSTEM() needed */ #include "mdef.h" #ifdef VMS #include #include #include #endif #include #include "sys/wait.h" #include "gtm_stat.h" #include "gtm_ctype.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "gtm_unistd.h" #include "gtm_stdlib.h" #include "gtm_fcntl.h" #include "gtmio.h" #include "copy.h" #include "iosp.h" #include "gdsroot.h" #include "v15_gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "v15_gdsbt.h" #include "gdsfhead.h" #include "v15_gdsfhead.h" #include "gdsblk.h" #include "patcode.h" #include "gdsblkops.h" #include "filestruct.h" #include "v15_filestruct.h" #include "gtmmsg.h" #include "eintr_wrappers.h" #include "min_max.h" #include "error.h" #include "jnl.h" #include "trans_log_name.h" #include "dbcertify.h" #define FILETAB "File " #define REGIONTAB "Region " error_def(ERR_DEVOPENFAIL); error_def(ERR_SYSCALL); error_def(ERR_DBRDONLY); error_def(ERR_DBOPNERR); error_def(ERR_DBCCMDFAIL); error_def(ERR_DBCINTEGERR); error_def(ERR_PREMATEOF); error_def(ERR_TEXT); error_def(ERR_TRNLOGFAIL); error_def(ERR_NOREGION); error_def(ERR_DBNOTGDS); error_def(ERR_BADDBVER); error_def(ERR_DBMINRESBYTES); error_def(ERR_DBMAXREC2BIG); error_def(ERR_DBCKILLIP); error_def(ERR_DBCNOTSAMEDB); error_def(ERR_LOGTOOLONG); error_def(ERR_GTMDISTUNDEF); /* Open the temporary file that hold the command(s) we are going to execute */ void dbc_open_command_file(phase_static_area *psa) { char_ptr_t errmsg; int rc, save_errno; int4 status; char *dist_ptr; mstr gtm_dist_m, gtm_dist_path; char gtm_dist_path_buff[MAX_FN_LEN + 1]; assert(NULL != psa && NULL == psa->tcfp); if (!psa->tmp_file_names_gend) dbc_gen_temp_file_names(psa); gtm_dist_m.addr = UNIX_ONLY("$")GTM_DIST; gtm_dist_m.len = SIZEOF(UNIX_ONLY("$")GTM_DIST) - 1; status = TRANS_LOG_NAME(>m_dist_m, >m_dist_path, gtm_dist_path_buff, SIZEOF(gtm_dist_path_buff), dont_sendmsg_on_log2long); #ifdef UNIX if (SS_LOG2LONG == status) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_LOGTOOLONG, 3, gtm_dist_m.len, gtm_dist_m.addr, SIZEOF(gtm_dist_path_buff) - 1); else #endif if (SS_NORMAL != status) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_GTMDISTUNDEF); assert(0 < gtm_dist_path.len); VMS_ONLY(dbc_remove_command_file(psa)); /* If we don't do this, the command files versions pile up fast */ psa->tcfp = Fopen((char_ptr_t)psa->tmpcmdfile, "w"); if (NULL == psa->tcfp) { save_errno = errno; errmsg = STRERROR(save_errno); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, psa->tmpcmdfile_len, psa->tmpcmdfile, ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg)); } UNIX_ONLY(dbc_write_command_file(psa, SHELL_START)); MEMCPY_LIT(psa->util_cmd_buff, SETDISTLOGENV); memcpy(psa->util_cmd_buff + SIZEOF(SETDISTLOGENV) - 1, gtm_dist_path.addr, gtm_dist_path.len); psa->util_cmd_buff[SIZEOF(SETDISTLOGENV) - 1 + gtm_dist_path.len] = 0; /* Null temrinator */ dbc_write_command_file(psa, (char_ptr_t)psa->util_cmd_buff); } /* Write a record to temporary command file */ void dbc_write_command_file(phase_static_area *psa, char_ptr_t cmd) { char_ptr_t errmsg; int rc, save_errno; assert(NULL != psa && NULL != psa->tcfp); assert(psa->tmp_file_names_gend); rc = FPRINTF(psa->tcfp, "%s\n", cmd); if (-1 == rc) { save_errno = errno; errmsg = STRERROR(save_errno); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fprintf()"), CALLFROM, /* BYPASSOK */ ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg)); } rc = CHMOD((char_ptr_t)psa->tmpcmdfile, S_IRUSR + S_IWUSR + S_IXUSR + S_IRGRP + S_IROTH); /* Change to 744 */ if (-1 == rc) { save_errno = errno; errmsg = STRERROR(save_errno); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(15) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("chmod()"), CALLFROM, ERR_TEXT, 2, psa->tmpcmdfile_len, psa->tmpcmdfile, ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg)); } } /* Close the temporary command file */ void dbc_close_command_file(phase_static_area *psa) { assert(NULL != psa && NULL != psa->tcfp); assert(psa->tmp_file_names_gend); fclose(psa->tcfp); psa->tcfp = NULL; } /* Execute the temporary command file */ void dbc_run_command_file(phase_static_area *psa, char_ptr_t cmdname, char_ptr_t cmdargs, boolean_t piped_result) { int rc, cmd_len; unsigned char cmdbuf1[MAX_FN_LEN + 256], cmdbuf2[MAX_FN_LEN + 1], *cp; assert(NULL != psa && NULL == psa->tcfp); assert(psa->tmp_file_names_gend); MEMCPY_LIT(cmdbuf1, RUN_CMD); cp = cmdbuf1 + SIZEOF(RUN_CMD) - 1; memcpy(cp, psa->tmpcmdfile, psa->tmpcmdfile_len); cp += psa->tmpcmdfile_len; cmd_len = (int)(cp - cmdbuf1); *cp = '\0'; rc = dbc_syscmd((char_ptr_t)cmdbuf1); if (0 != rc) { /* If piped_result, they can't see what went wrong (error messages likely in result file */ if (piped_result) { /* Output result file so they can see what happened -- this may or may not work but it is the best we can do at this point */ MEMCPY_LIT(cmdbuf2, DUMPRSLTFILE); cp = cmdbuf2 + SIZEOF(DUMPRSLTFILE) - 1; memcpy(cp, psa->tmprsltfile, psa->tmprsltfile_len); cp += psa->tmprsltfile_len; *cp = '\0'; dbc_syscmd((char_ptr_t)cmdbuf2); } rts_error_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_DBCCMDFAIL, 7, rc, cmd_len, cmdbuf1, RTS_ERROR_TEXT(cmdname), RTS_ERROR_TEXT(cmdargs), ERR_TEXT, 2, RTS_ERROR_LITERAL("Note that the "UNIX_ONLY("environment variable $")VMS_ONLY("logical ")GTM_DIST " must point to the current GT.M V4 installation")); } } /* Remove/dalete command file - normally only needed at cleanup since open with "W" will delete any existing file. */ void dbc_remove_command_file(phase_static_area *psa) { char_ptr_t errmsg; int rc, save_errno; assert(NULL != psa && NULL == psa->tcfp); /* Must be closed */ if (!psa->tmp_file_names_gend) dbc_gen_temp_file_names(psa); rc = remove((char_ptr_t)psa->tmpcmdfile); if (-1 == rc && ENOENT != errno) { save_errno = errno; errmsg = STRERROR(save_errno); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(15) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("remove()"), CALLFROM, ERR_TEXT, 2, psa->tmpcmdfile_len, psa->tmpcmdfile, ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg)); } } /* Open result file */ void dbc_open_result_file(phase_static_area *psa) { char_ptr_t errmsg; int rc, save_errno; assert(NULL != psa && NULL == psa->trfp); assert(psa->tmp_file_names_gend); psa->trfp = Fopen((char_ptr_t)psa->tmprsltfile, "r"); if (0 == psa->trfp) { save_errno = errno; errmsg = STRERROR(save_errno); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, psa->tmprsltfile_len, psa->tmprsltfile, ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg)); } } /* Read a record from temporary result file */ uchar_ptr_t dbc_read_result_file(phase_static_area *psa, int rderrmsg, uchar_ptr_t arg) { int save_errno; char_ptr_t errmsg; char_ptr_t fgs; char emsg[MAX_FN_LEN + 256]; assert(NULL != psa && NULL != psa->trfp); FGETS((char_ptr_t)psa->rslt_buff, MAX_ZWR_KEY_SZ, psa->trfp, fgs); if (NULL == fgs) { if (!feof(psa->trfp)) { /* Non-EOF message */ save_errno = errno; errmsg = STRERROR(save_errno); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fgets()"), CALLFROM, ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg)); } else { /* We have EOF */ if (0 != rderrmsg) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) rderrmsg, 2, RTS_ERROR_TEXT((char_ptr_t)arg)); else { strcpy(emsg, "Temporary results file ("); strcat(emsg, (char_ptr_t)psa->tmprsltfile); strcat(emsg, " had unexpected values"); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_PREMATEOF, 0, ERR_TEXT, 2, RTS_ERROR_TEXT(emsg)); } } exit(EXIT_FAILURE); /* We shouldn't come here but in case... */ } return (uchar_ptr_t)fgs; } /* Close the temporary command file */ void dbc_close_result_file(phase_static_area *psa) { assert(NULL != psa && NULL != psa->trfp); fclose(psa->trfp); psa->trfp = NULL; } /* Remove/dalete result file */ void dbc_remove_result_file(phase_static_area *psa) { int rc, save_errno; char_ptr_t errmsg; assert(NULL != psa && NULL == psa->trfp); /* Must be closed */ if (!psa->tmp_file_names_gend) dbc_gen_temp_file_names(psa); rc = remove((char_ptr_t)psa->tmprsltfile); if (-1 == rc && ENOENT != errno) { save_errno = errno; errmsg = STRERROR(save_errno); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(15) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("remove()"), CALLFROM, ERR_TEXT, 2, psa->tmprsltfile_len, psa->tmprsltfile, ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg)); } } /* Create the temporary file names we need. This is a hardcoded prefix following by the region name of the file we are processing. This should create a unique temporary command script and command result file for a given invocation and allows multiple copies of DBCERTIFY to run against databases in the same directory. */ void dbc_gen_temp_file_names(phase_static_area *psa) { unsigned char *cp, *regname_p; int len, dir_len; assert(NULL != psa && !psa->tmp_file_names_gend); assert(0 == psa->tmprsltfile[0]); assert(0 == psa->tmpcmdfile[0]); /* See if we have region name information yet. Where this region name information is kept depends on the phase we are in. Scan phase it is in psa->regname (is an argument to the phase). In certify phase the region name is in the scan phase outfile file header. */ if (psa->phase_one) /* Scan phase, region name in regname */ regname_p = psa->regname; else regname_p = (uchar_ptr_t)psa->ofhdr.regname; assert(0 != *regname_p); /* We should have a regname of substance */ /* Temp command file name: TMPFILEPFX_.TMPFILESFX. Note that tempfiledir has no default if not specified therefore defaults to the current directory. */ cp = psa->tmpcmdfile; if (0 != *psa->tmpfiledir) { /* A temporary file directory was specified .. use it */ len = STRLEN((char_ptr_t)psa->tmpfiledir); memcpy(cp, psa->tmpfiledir, len); cp += len; #ifdef VMS if (']' != *(cp - 1) && '>' != *(cp - 1) && ':' != *(cp - 1)) *cp++ = ':'; #else if ('/' != *(cp - 1)) *cp++ = '/'; #endif dir_len = (int)(cp - psa->tmpcmdfile); } else dir_len = 0; MEMCPY_LIT(cp, TMPFILEPFX); cp = psa->tmpcmdfile + SIZEOF(TMPFILEPFX) - 1; *cp++ = '_'; len = STRLEN((char_ptr_t)regname_p); memcpy(cp, regname_p, len); cp += len; MEMCPY_LIT(cp, TMPCMDFILSFX); cp += SIZEOF(TMPCMDFILSFX) - 1; psa->tmpcmdfile_len = (int)(cp - psa->tmpcmdfile); *cp = '\0'; /* Null terminate */ /* Now same thing for temporary results file */ cp = psa->tmprsltfile; if (0 != dir_len) { /* Dir will be same as for command file so use that.. */ memcpy(cp, psa->tmpcmdfile, dir_len); cp += dir_len; } MEMCPY_LIT(cp, TMPFILEPFX); cp = psa->tmprsltfile + SIZEOF(TMPFILEPFX) - 1; *cp++ = '_'; len = STRLEN((char_ptr_t)regname_p); memcpy(cp, regname_p, len); cp += len; MEMCPY_LIT(cp, TMPRSLTFILSFX); cp += SIZEOF(TMPRSLTFILSFX) - 1; psa->tmprsltfile_len = (int)(cp - psa->tmprsltfile); *cp = '\0'; /* Null terminate */ psa->tmp_file_names_gend = TRUE; } /* Execute the given system command. Note even in VMS we are getting a POSIX style return code, not the VMS style return code due to the _POSIX_EXIT macro defined at the top of this module. See the C library reference manual for details on VMS. */ int dbc_syscmd(char_ptr_t cmdparm) { int rc; #ifdef _BSD union wait wait_stat; #else int4 wait_stat; #endif #ifdef VMS /* Verify system() is supported */ /* BYPASSOK: system() used insode the comment, no SYSTEM() needed */ if (0 == SYSTEM(NULL)) GTMASSERT; #endif rc = SYSTEM(cmdparm); if (-1 == rc) rc = errno; else { #ifdef _BSD wait_stat.w_status = rc; #else wait_stat = rc; #endif rc = WEXITSTATUS(wait_stat); } return rc; } /* Find the region name associated with the given database. Parse the output from "DSE /REG" to determine. */ void dbc_find_database_filename(phase_static_area *psa, uchar_ptr_t regname, uchar_ptr_t dbfn) { int len; uchar_ptr_t rptr; dbc_open_command_file(psa); #ifdef VMS strcpy((char_ptr_t)psa->util_cmd_buff, RESULT_ASGN); strcat((char_ptr_t)psa->util_cmd_buff, (char_ptr_t)psa->tmprsltfile); dbc_write_command_file(psa, (char_ptr_t)psa->util_cmd_buff); dbc_write_command_file(psa, DSE_START); #else strcpy((char_ptr_t)psa->util_cmd_buff, DSE_START_PIPE_RSLT1); strcat((char_ptr_t)psa->util_cmd_buff, (char_ptr_t)psa->tmprsltfile); strcat((char_ptr_t)psa->util_cmd_buff, DSE_START_PIPE_RSLT2); dbc_write_command_file(psa, (char_ptr_t)psa->util_cmd_buff); #endif dbc_write_command_file(psa, DSE_FIND_REG_ALL); dbc_write_command_file(psa, DSE_QUIT); UNIX_ONLY(dbc_write_command_file(psa, "EOF")); dbc_close_command_file(psa); dbc_remove_result_file(psa); dbc_run_command_file(psa, "DSE", DSE_FIND_REG_ALL, TRUE); dbc_open_result_file(psa); /* There should be 7 lines of uninteresting stuff before we get to the file/region pairs but since other errors may pop up at the head of this list (notorious example -- waiting for ftok semaphore from DSE) we will just eat lines until we get to the first DSE prompt at which point our command should be outputing. If we run out of lines (hit EOF), the read routine will return an appropriate error. */ do { rptr = dbc_read_result_file(psa, 0, NULL); } while (0 != MEMCMP_LIT(rptr, DSE_REG_LIST_START)); /* And two more lines after that are also bogus */ dbc_read_result_file(psa, 0, NULL); dbc_read_result_file(psa, 0, NULL); /* Now we get to the triplets of Filename, Regionname, and a blank line for each region in GLD */ while(1) { rptr = dbc_read_result_file(psa, ERR_NOREGION, regname); /* Should have filename */ if (0 != MEMCMP_LIT(rptr, FILETAB)) GTMASSERT; len = STRLEN(((char_ptr_t)rptr + SIZEOF(FILETAB) - 1)) - 1; assert(MAX_FN_LEN >= len); assert(len); memcpy(dbfn, (rptr + SIZEOF(FILETAB) - 1), len); dbfn[len] = 0; rptr = dbc_read_result_file(psa, ERR_NOREGION, regname); if (0 != MEMCMP_LIT(rptr, REGIONTAB)) GTMASSERT; len = STRLEN((char_ptr_t)rptr + SIZEOF(REGIONTAB) - 1) - 1; assert(len); *(rptr + SIZEOF(REGIONTAB) - 1 + len) = 0; /* Get rid of trailing \n */ if (0 == strcmp(((char_ptr_t)rptr + SIZEOF(REGIONTAB) - 1), (char_ptr_t)regname)) break; /* Found match */ rptr = dbc_read_result_file(psa, ERR_NOREGION, regname); /* Ingored blank line */ len = STRLEN((char_ptr_t)rptr); if ('\n' == rptr[len - 1]) --len; /* Note last record of output file does not have '\n' so test before adjusting 'len' */ if ('\r' == rptr[len - 1]) --len; /* Same for carriage return (mostly for VMS) */ if (0 != len && ((SIZEOF("DSE> ") - 1) != len || 0 != memcmp(rptr, "DSE> ", len))) GTMASSERT; } dbc_close_result_file(psa); return; } /* Read a given database block into the next block_set (or return existing one) */ int dbc_read_dbblk(phase_static_area *psa, int blk_num, enum gdsblk_type blk_type) { uchar_ptr_t tucp, src_blk_p; int blk_index; block_info *blk_set_p, *blk_set_new_p; assert(0 <= blk_num); if (NULL == psa->blk_set) { /* Need a few of these.. */ psa->blk_set = malloc(SIZEOF(block_info) * MAX_BLOCK_INFO_DEPTH); memset(psa->blk_set, 0, SIZEOF(block_info) * MAX_BLOCK_INFO_DEPTH); assert(-1 == psa->block_depth); } DBC_DEBUG(("DBC_DEBUG: Requesting database block 0x%x (type = %d)\n", blk_num, blk_type)); /* Scan the blocks we have thus far to make sure this block is not amongst them. Block duplication is possible in two instances: (1) We have reached the target block or (2) this is a bitmap block we are reading in to modify. These conditions are also "asserted". */ assert(blk_num < psa->dbc_cs_data->trans_hist.total_blks); for (blk_index = 0, blk_set_p = &psa->blk_set[0]; blk_index <= psa->block_depth; ++blk_index, ++blk_set_p) { if (blk_set_p->blk_num == blk_num) { /* This block already exists in our cache */ assert(0xff == ((v15_blk_hdr_ptr_t)blk_set_p->old_buff)->levl || 0 == blk_index); if (gdsblk_gvtroot == blk_type) { assert(gdsblk_gvtindex == blk_set_p->blk_type); /* Override preexisting type to say this is the GVT root block which we did not know before when we read it in. */ blk_set_p->blk_type = gdsblk_gvtroot; } DBC_DEBUG(("DBC_DEBUG: Found block in active cache - blk_index %d\n", blk_index)); blk_set_p->found_in_cache = TRUE; return blk_index; } } ++psa->block_depth; /* Going to another level of block usage */ if (MAX_BLOCK_INFO_DEPTH <= psa->block_depth) GTMASSERT; blk_set_new_p = &psa->blk_set[psa->block_depth]; /* See if this block already occupies this or another slot in the "inactive cache" which is any block that was read into a slot >= block_depth but <= block_depth_hwm (our high water mark). */ for (blk_index = psa->block_depth, blk_set_p = &psa->blk_set[psa->block_depth]; blk_index <= psa->block_depth_hwm; blk_index++, blk_set_p++) { /* Note the blk_set_p->blk_num != 0 represents a minor inefficiency in that it forces us to always reload block 0 the first time it is used in a transaction but does not cause any correctness issues. After this initial load, it will be found on subsequent searches by the loop above. The check against 0 prevents us from picking up a block that was not in use before. An alternative method to this check would be to initialize the block numbers of the entire cache to some value (preferrably other than -1 as that value has another meaning [created block]). This is something that could be done in the future if this processing turns out to be burdensome which we fully do not expect to be the case with v5cbsu.m handling the bulk of the ocnversion workload. SE 5/2005. */ if (blk_num == blk_set_p->blk_num && 0 != blk_set_p->blk_num) { /* Block already exists in this slot so we can avoid I/O. If this is the slot we were going to put the new block in (blk_index == block_depth) then everything is in the right place and we only need minor resets. Else, copy information from found block to current block as necessary */ if (blk_index > psa->block_depth) { /* Block exists in an older slot. Copy info to new slot */ dbc_init_blk(psa, blk_set_new_p, blk_set_p->blk_num, gdsblk_read, blk_set_p->blk_len, blk_set_p->blk_levl); blk_set_new_p->blk_type = blk_set_p->blk_type; memcpy(blk_set_new_p->old_buff, ((gdsblk_read == blk_set_p->usage) ? blk_set_p->old_buff : blk_set_p->new_buff), psa->dbc_cs_data->blk_size); blk_set_p->blk_num = -1; /* Effectively invalidate this (now) older cache entry */ DBC_DEBUG(("DBC_DEBUG: Found block in inactive cache differemt slot (%d) for blk_index %d\n", blk_index, psa->block_depth)); } else { assert(blk_index == psa->block_depth); switch(blk_set_new_p->usage) { case gdsblk_create: case gdsblk_update: /* Both of these have the current value for the buffer in new_buff. Swap new_buff and old_buff to get things into proper order */ assert(blk_set_p->old_buff); assert(blk_set_p->new_buff); tucp = blk_set_p->old_buff; blk_set_p->old_buff = blk_set_p->new_buff; blk_set_p->new_buff = tucp; /* Fall into code for block that was only read (it is all setup already) */ case gdsblk_read: /* If block was not disturbed, the buffer pointers are already in the correct configuration */ dbc_init_blk(psa, blk_set_p, blk_set_p->blk_num, gdsblk_read, blk_set_p->blk_len, blk_set_p->blk_levl); DBC_DEBUG(("DBC_DEBUG: Found block in inactive cache same slot for blk_index" " %d\n", psa->block_depth)); break; default: GTMASSERT; } } VMS_ONLY(GET_ULONG(blk_set_new_p->tn, &((v15_blk_hdr_ptr_t)blk_set_new_p->old_buff)->tn)); UNIX_ONLY(blk_set_new_p->tn = ((v15_blk_hdr_ptr_t)blk_set_new_p->old_buff)->tn); blk_set_new_p->found_in_cache = TRUE; return psa->block_depth; } } /* Initialize block we are about to use. Some values not yet known until after read so this serves mainly to make sure all the structures (such as read buffer) are allocated. */ dbc_init_blk(psa, blk_set_new_p, blk_num, gdsblk_read, 0, 0); /* Now read the block */ DBC_DEBUG(("DBC_DEBUG: Reading in database block 0x%x into blk_index %d\n", blk_num, psa->block_depth)); psa->fc->op = FC_READ; psa->fc->op_buff = (sm_uc_ptr_t)blk_set_new_p->old_buff; psa->fc->op_pos = psa->dbc_cs_data->start_vbn + ((gtm_int64_t)(psa->dbc_cs_data->blk_size / DISK_BLOCK_SIZE) * blk_num); psa->fc->op_len = psa->dbc_cs_data->blk_size; /* In case length field was modified during a file-extension */ dbcertify_dbfilop(psa); /* Read data/index block (no return if error) */ /* Now that we know some value, call initialize again to set the values the way we want */ dbc_init_blk(psa, blk_set_new_p, blk_num, gdsblk_read, ((v15_blk_hdr_ptr_t)blk_set_new_p->old_buff)->bsiz, ((v15_blk_hdr_ptr_t)blk_set_new_p->old_buff)->levl); VMS_ONLY(GET_ULONG(blk_set_new_p->tn, &((v15_blk_hdr_ptr_t)blk_set_new_p->old_buff)->tn)); UNIX_ONLY(blk_set_new_p->tn = ((v15_blk_hdr_ptr_t)blk_set_new_p->old_buff)->tn); /* recalculate block type if necessary */ switch(blk_type) { case gdsblk_gvtroot: case gdsblk_gvtindex: case gdsblk_gvtleaf: case gdsblk_dtroot: case gdsblk_dtindex: case gdsblk_dtleaf: case gdsblk_bitmap: blk_set_new_p->blk_type = blk_type; break; case gdsblk_gvtgeneric: if (0 == ((v15_blk_hdr_ptr_t)blk_set_new_p->old_buff)->levl) blk_set_new_p->blk_type = gdsblk_gvtleaf; else blk_set_new_p->blk_type = gdsblk_gvtindex; break; case gdsblk_dtgeneric: if (0 == ((v15_blk_hdr_ptr_t)blk_set_new_p->old_buff)->levl) blk_set_new_p->blk_type = gdsblk_dtleaf; else blk_set_new_p->blk_type = gdsblk_dtindex; break; default: GTMASSERT; } return psa->block_depth; } /* Find the end of a key using the current value of the key as a base */ void dbc_find_key(phase_static_area *psa, dbc_gv_key *key, uchar_ptr_t rec_p, int blk_levl) { int cmpc, rec_len; int tmp_cmpc; unsigned short us_rec_len; uchar_ptr_t key_targ_p, key_src_p; cmpc = EVAL_CMPC((rec_hdr *)rec_p); GET_USHORT(us_rec_len, &((rec_hdr_ptr_t)rec_p)->rsiz); rec_len = us_rec_len; if (BSTAR_REC_SIZE == rec_len && 0 < blk_levl) { /* This is a star key record .. there is no key */ key->end = 0; DBC_DEBUG(("DBC_DEBUG: Found star key record in dbc_find_key\n")); return; } /* Loop till we find key termination */ key_targ_p = key->base + cmpc; key_src_p = rec_p + SIZEOF(rec_hdr); while (1) { for (; *key_src_p; ++key_targ_p, ++key_src_p) *key_targ_p = *key_src_p; if (0 == *(key_src_p + 1)) { /* Just found the end of the key */ *key_targ_p++ = 0; /* Create key ending null */ *key_targ_p = 0; /* Install 2nd 0x00 as part of key but not part of length */ key->end = (uint4)(key_targ_p - key->base); break; } /* Else, copy subscript separator char and keep scanning */ *key_targ_p++ = *key_src_p++; assert((key_src_p - rec_p) < rec_len); /* Sanity check */ } assert(cmpc <= key->end); /* Overrun sanity check */ return; } /* Find the gvt root block by looking up the GVN in the directory tree */ int dbc_find_dtblk(phase_static_area *psa, dbc_gv_key *key, int min_levl) { uchar_ptr_t rec_p; int blk_index; assert(MAX_MIDENT_LEN >= key->gvn_len); dbc_init_key(psa, &psa->gvn_key); memcpy(psa->gvn_key, key, SIZEOF(dbc_gv_key) + key->gvn_len); /* Make key with GVN only (including trailing null) */ psa->gvn_key->end = key->gvn_len; /* Look up GVN in directory tree */ blk_index = dbc_find_record(psa, psa->gvn_key, (psa->phase_one ? 0 : 1), min_levl, gdsblk_dtroot, FALSE); return blk_index; } /* Find the record in a given block rc = -1 : integrity error detected = -2 : record not found = else : the index of the block in the cache where record was found (curr_blk_key is set for matching record). Note since this routine is used in certify phase to lookup all the right hand siblings of a gvtroot block given a maximum key, this flag tells us that failure is ok .. we just wanted to populate the cache with siblings. */ int dbc_find_record(phase_static_area *psa, dbc_gv_key *key, int blk_index, int min_levl, enum gdsblk_type newblk_type, boolean_t fail_ok) { uchar_ptr_t rec_p, blk_p, blk_top, key1, key2; unsigned short us_rec_len; int blk_ptr, blk_levl, key_len, key_len1, key_len2, rec_len; int tmp_cmpc; enum gdsblk_type blk_type; block_info *blk_set_p; DBC_DEBUG(("DBC_DEBUG: dbc_find_record: Beginning scan of block index %d\n", blk_index)); /* If blk_index is 0, there is no starting block in the cache/set so we read block 1 (root) */ assert(0 <= min_levl); blk_type = newblk_type; if (gdsblk_dtroot == blk_type) { assert((psa->phase_one && 0 == blk_index) || (!psa->phase_one && 1 == blk_index)); assert((psa->phase_one && -1 == psa->block_depth) || (!psa->phase_one && 0 == psa->block_depth)); blk_index = dbc_read_dbblk(psa, 1, gdsblk_dtroot); blk_type = gdsblk_dtgeneric; /* Type of future blocks */ } else if (gdsblk_gvtroot == blk_type) blk_type = gdsblk_gvtgeneric; /* Type of future read blocks */ blk_set_p = &psa->blk_set[blk_index]; blk_levl = ((v15_blk_hdr_ptr_t)blk_set_p->old_buff)->levl; /* If we have reached the minimum level, we are done but ONLY if this is also our target block (blk_index == 0). If we are not at blk_index 0 then we need to find where our key fits into this block. This is typcially in the first search of the directory tree where min_levl is 0 but when we hit the dtleaf block we still want to search it to find the pointer to the gvt root block. */ if (min_levl == blk_levl && 0 == blk_index) { /* This is the level we were looking for and record is found */ DBC_DEBUG(("DBC_DEBUG: dbc_find_record: Reached minimum block level and found block we were looking for\n")); return blk_index; } /* Find first block that is greater than or equal to our gvn or if we find a star-key */ blk_p = blk_set_p->old_buff; rec_p = blk_p + SIZEOF(v15_blk_hdr); blk_top = blk_p + ((v15_blk_hdr_ptr_t)blk_set_p->old_buff)->bsiz; while (rec_p < blk_top) { blk_set_p->prev_match = blk_set_p->curr_match; blk_set_p->curr_match = 0; GET_USHORT(us_rec_len, &((rec_hdr *)rec_p)->rsiz); rec_len = us_rec_len; if (0 >= rec_len || rec_len > psa->dbc_cs_data->max_rec_size) /* Something messed up integrity wise - matters for phase-2 but not for phase-1 */ return -1; if (0 != blk_levl && BSTAR_REC_SIZE == rec_len) { /* We have a star record - This is the record we are looking for in this block */ blk_set_p->curr_blk_key->end = 0; /* Key length is zero for this type */ if (min_levl == blk_levl) { /* Block record and key information set up. We can return now */ DBC_DEBUG(("DBC_DEBUG: dbc_find_record: Reached minimum block level -- matching scan was a star" " key record\n")); return blk_index; } DBC_DEBUG(("DBC_DEBUG: dbc_find_record: Recursing down a level via star key record at offset 0x%lx\n", (rec_p - blk_p))); GET_ULONG(blk_ptr, rec_p + VMS_ONLY(3) UNIX_ONLY(4)); blk_index = dbc_read_dbblk(psa, blk_ptr, blk_type); /* Keep looking next level down */ return dbc_find_record(psa, key, blk_index, min_levl, blk_type, fail_ok); } /* Determine key for this record */ dbc_find_key(psa, blk_set_p->curr_blk_key, rec_p, blk_set_p->blk_levl); /* Perform key comparison keeping track of how many chars match (compression count) */ if (dbc_match_key(blk_set_p->curr_blk_key, blk_set_p->blk_levl, key, &blk_set_p->curr_match)) { /* Found our record - If the record is in an index block, recurse. Else return the record we found */ if (gdsblk_gvtleaf == blk_set_p->blk_type || min_levl == blk_levl) { /* This is a terminal block. It is the end of the road */ DBC_DEBUG(("DBC_DEBUG: dbc_find_record: Reached minimum block level (or leaf level) -- matching" " scan was a normal keyed record at offset 0x%lx\n", (rec_p - blk_p))); return blk_index; } /* We already know that the current block is not the one we are interested in and therefore this record is known to contain a pointer to another block. Read the block in and recurse to continue the search for the key. */ DBC_DEBUG(("DBC_DEBUG: dbc_find_record: Recursing down a level via keyed index record at offset 0x%lx\n", (rec_p - blk_p))); GET_ULONG(blk_ptr, (rec_p + SIZEOF(rec_hdr) + blk_set_p->curr_blk_key->end - EVAL_CMPC((rec_hdr *)rec_p) + 1)); blk_index = dbc_read_dbblk(psa, blk_ptr, blk_type); return dbc_find_record(psa, key, blk_index, min_levl, blk_type, fail_ok); } /* We want to be able to find the previous record */ blk_set_p->prev_rec = rec_p; memcpy(blk_set_p->prev_blk_key, blk_set_p->curr_blk_key, (SIZEOF(dbc_gv_key) + blk_set_p->curr_blk_key->end)); rec_p += rec_len; /* Point to next record in block */ blk_set_p->curr_rec = rec_p; } /* If we don't find the record (or one greater), the block with the key we are looking for is no longer existing in the GVT (assert that the search is for a level 0 GVT block). */ if (gdsblk_gvtleaf == psa->blk_set[0].blk_type) { /* Key not found */ DBC_DEBUG(("DBC_DEBUG: dbc_find_record: Searched for key was not found\n")); return -2; } /* Else we should have found the record or a star key. Globals are NOT removed once created so we should always be able to find an appropriate record if this is not a GVT leaf block. Exception to this is when we are just wanting to populate the right siblings of a gvtroot block in the cache. */ if (!fail_ok) { assert(FALSE); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DBCINTEGERR, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.dbfn), ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to find index record for an existing global")); } return -1; } /* Compare two keys. If key1 is logically greater than or equal to key2, return TRUE, else FALSE. Also, set output parameter matchc with the number of chars that matched */ boolean_t dbc_match_key(dbc_gv_key *key1, int blk_levl1, dbc_gv_key *key2, unsigned int *matchc) { uchar_ptr_t key_val1, key_val2; int key_len1, key_len2, key_len, lcl_matchc; lcl_matchc = 0; key_val1 = key1->base; key_val2 = key2->base; key_len1 = key1->end + 1; if (1 == key_len1 && 0 < blk_levl1) { /* This is a star key record. It is always greater than the second key but has no matching characters. */ *matchc = 0; return TRUE; } assert(1 < key_len1); /* Otherwise we expect to see a key here */ key_len2 = key2->end + 1; assert(1 < key_len2); /* Not expecting a star key record in second position */ key_len = MIN(key_len1, key_len2); for (; key_len; key_val1++, key_val2++, key_len--) { if (*key_val1 == *key_val2) ++lcl_matchc; else break; } *matchc = lcl_matchc; if ((0 == key_len && key_len1 >= key_len2) || (0 != key_len && *key_val1 > *key_val2)) return TRUE; return FALSE; } /* Initialize the given gv_key to a null status so dbc_find_key() start off with a new key */ void dbc_init_key(phase_static_area *psa, dbc_gv_key **key) { if (NULL == *key) { /* Need a key allocated for this block */ *key = malloc(SIZEOF(dbc_gv_key) + psa->dbc_cs_data->max_key_size); (*key)->top = (uint4)(SIZEOF(dbc_gv_key) + psa->dbc_cs_data->max_key_size); } (*key)->end = (*key)->gvn_len = 0; return; } /* Routine to initialize a blk_set block */ void dbc_init_blk(phase_static_area *psa, block_info *blk_set_p, int blk_num, enum gdsblk_usage blk_usage, int blk_len, int blk_levl) { blk_set_p->blk_num = blk_num; blk_set_p->usage = blk_usage; blk_set_p->ins_rec.blk_id = 0; blk_set_p->found_in_cache = FALSE; dbc_init_key(psa, &blk_set_p->curr_blk_key); dbc_init_key(psa, &blk_set_p->prev_blk_key); dbc_init_key(psa, &blk_set_p->ins_rec.ins_key); blk_set_p->blk_len = blk_len; blk_set_p->blk_levl = blk_levl; blk_set_p->curr_match = blk_set_p->prev_match = 0; if (NULL == blk_set_p->old_buff) blk_set_p->old_buff = malloc(psa->dbc_cs_data->blk_size); if (NULL == blk_set_p->new_buff) blk_set_p->new_buff = malloc(psa->dbc_cs_data->blk_size); blk_set_p->curr_rec = blk_set_p->prev_rec = blk_set_p->old_buff + SIZEOF(v15_blk_hdr); blk_set_p->upd_addr = NULL; blk_set_p->ins_blk_id_p = NULL; return; } /* Initialize database usage - open it and read in the file-header */ void dbc_init_db(phase_static_area *psa) { /* This routine does the database open and initialization for both scan (phase1) and certify phases however the requirements for these phases differ somewhat. For the scan phase we just want to open the database, read the file-header into dbc_cs_data and verify this is a database. For the certify phase, we also have to obtain standalone access, make sure the file hasn't moved around since the scan phase and add reserved_bytes and max_rec_size checks. But standalone access is somewhat tricky as part of the standalone verification process involves (for later V4 versions) knowing the key of the shared memory segment which is kept in the file-header meaning we have to read the file-header before we can lock it on UNIX. Because of this, on UNIX we will RE-READ the file-header after obtaining the lock to make sure there are no stale values. */ /* We must have RW access in scan phase in order to do the DSE buffer flush to assure we are looking at the correct database blocks and of course the certify phase needs R/W access to do its job. */ if (0 != ACCESS((char_ptr_t)psa->dbc_gv_cur_region->dyn.addr->fname, (R_OK | W_OK))) { if (EACCES == errno) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(psa->dbc_gv_cur_region)); else rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBOPNERR, 2, DB_LEN_STR(psa->dbc_gv_cur_region), errno); } /* Open the database which on VMS gives standalone access (for phase 2) */ psa->fc->op = FC_OPEN; dbcertify_dbfilop(psa); /* Knows this is a phase 2 open so gives standalone access on VMS */ psa->dbc_gv_cur_region->open = TRUE; if (!psa->phase_one) { /* Verify the fileid has not changed */ if (!is_gdid_gdid_identical(&psa->ofhdr.unique_id.uid, &FILE_INFO(psa->dbc_gv_cur_region)->UNIX_ONLY(fileid)VMS_ONLY(file_id))) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DBCNOTSAMEDB); } /* Read in database file header */ psa->fc->op = FC_READ; psa->fc->op_buff = (sm_uc_ptr_t)psa->dbc_cs_data; psa->fc->op_len = SIZEOF(*psa->dbc_cs_data); psa->fc->op_pos = 1; dbcertify_dbfilop(psa); /* Verify we (still) have a GT.M V4 database */ if (0 != memcmp(psa->dbc_cs_data->label, V15_GDS_LABEL, GDS_LABEL_SZ - 1)) { if (memcmp(psa->dbc_cs_data->label, V15_GDS_LABEL, GDS_LABEL_SZ - 3)) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBNOTGDS, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.dbfn)); else rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADDBVER, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.regname)); } if (!psa->phase_one) { #ifdef UNIX /* Obtain standalone access to database. In UNIX, this requires creation/access to the "ftok" database semaphore. This is the main semaphore in some V4 releases and the "startup/rundown" semaphore in other releases. But in all cases, its creation and locking will govern standalone access to the database in question. On VMS, we just don't open the file as shared and we are guarranteed standalone access to it. */ dbc_aquire_standalone_access(psa); dbcertify_dbfilop(psa); /* Re-read file header */ #endif /* Verify reserved_bytes and max_rec_len again and verify kill_in_prog is not set */ if (VMS_ONLY(9) UNIX_ONLY(8) > psa->dbc_cs_data->reserved_bytes) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBMINRESBYTES, 2, VMS_ONLY(9) UNIX_ONLY(8), psa->dbc_cs_data->reserved_bytes); if (SIZEOF(blk_hdr) > (psa->dbc_cs_data->blk_size - psa->dbc_cs_data->max_rec_size)) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBMAXREC2BIG, 3, psa->dbc_cs_data->max_rec_size, psa->dbc_cs_data->blk_size, (psa->dbc_cs_data->blk_size - SIZEOF(blk_hdr))); if (0 != psa->dbc_cs_data->kill_in_prog) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBCKILLIP, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.dbfn)); /* Turn off replication and/or journaling for our trip here */ if (jnl_open == psa->dbc_cs_data->jnl_state) { psa->dbc_cs_data->jnl_state = jnl_closed; psa->dbc_cs_data->repl_state = repl_closed; } } return; } /* Close the database and remove any semaphores we had protecting it */ void dbc_close_db(phase_static_area *psa) { if (psa->dbc_gv_cur_region->open) { /* If region is open.. close it and release the semaphores.. */ psa->fc->op = FC_CLOSE; dbcertify_dbfilop(psa); psa->dbc_gv_cur_region->open = FALSE; UNIX_ONLY(if (!psa->phase_one) dbc_release_standalone_access(psa)); } return; } #ifdef UNIX /* Aquire semaphores that on on all V4.x releases are the access control semaphores. In pre V4.2 releases they were based on an FTOK of the database name with an ID of '1'. In V4.2 and later, they are based on the FTOK of the database name with an ID of '43'. Since we do not know which flavor of database we are dealing with, we must create and acquire both flavors of semaphore and hold them for the duration of the phase 2 run. But just holding these semaphore is not sufficient to guarrantee standalone access. We also must attempt to attach to the shared memory for the segment. If it is found, standalone access is not achieved. Early V4 versions (prior to V4.2) created the shared memory with the same FTOK id as the semaphore. Later versions would have had the key of the created private section in the file-header. Use both approaches and fail our attempt if either succeeds. */ void dbc_aquire_standalone_access(phase_static_area *psa) { mu_all_version_get_standalone((char_ptr_t)psa->dbc_gv_cur_region->dyn.addr->fname, &psa->sem_inf[0]); } void dbc_release_standalone_access(phase_static_area *psa) { mu_all_version_release_standalone(&psa->sem_inf[0]); } #endif fis-gtm-V6.0-003/sr_port/dbcertify_scan_phase.c0000644000032200000250000010426412201176155020344 0ustar librarygtc/**************************************************************** * * * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /**************************************************************** DBCERTIFY_SCAN_PHASE - Phase 1 scan utility - Flush database buffers (call to DSE BUFFER_FLUSH) - Open database - Verify either report_only or max_lrecl and reserved_bytes within bounds. - If not report_only, open output file. - Locate too-full blocks and identify type. - Write descriptive records to output file if required - rewrite header of output file to include total information. - print statistics of run to console. Note: Most routines in this utility are self-contained meaning they do not reference GT.M library routines (with some notable exceptions). This is because phase-1 is going to run against live V4 databases and the V5 compilation will be using V5 database structures. ****************************************************************/ #include "mdef.h" #ifdef VMS #include #include #include #endif #include #include "gtm_stat.h" #include "gtm_ctype.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "gtm_unistd.h" #include "gtm_stdlib.h" #include "gtm_fcntl.h" #if defined(__MVS__) #include "gtm_zos_io.h" #endif #include "cli.h" #include "copy.h" #include "iosp.h" #include "gdsroot.h" #include "v15_gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "v15_gdsbt.h" #include "gdsfhead.h" #include "v15_gdsfhead.h" #include "filestruct.h" #include "v15_filestruct.h" #include "gdsblk.h" #include "gdsbml.h" #include "gdsblkops.h" #include "gtmmsg.h" #include "gtmio.h" #include "spec_type.h" #include "get_spec.h" #include "collseq.h" #include "format_targ_key.h" #include "patcode.h" #include "error.h" #include "mupip_exit.h" #include "gvcst_lbm_check.h" #include "dbcertify.h" GBLREF gv_key *gv_altkey; GBLREF gv_namehead *gv_target; GBLREF pattern *pattern_list; GBLREF pattern *curr_pattern; GBLREF pattern mumps_pattern; GBLREF uint4 *pattern_typemask; GBLREF phase_static_area *psa_gbl; error_def(ERR_FILENAMETOOLONG); error_def(ERR_DBNOTGDS); error_def(ERR_BADDBVER); error_def(ERR_DBMINRESBYTES); error_def(ERR_DBMAXREC2BIG); error_def(ERR_DEVOPENFAIL); error_def(ERR_DBCREC2BIG); error_def(ERR_SYSCALL); error_def(ERR_TEXT); error_def(ERR_DBCINTEGERR); error_def(ERR_COLLATIONUNDEF); error_def(ERR_COLLTYPVERSION); error_def(ERR_GVIS); error_def(ERR_MUPCLIERR); ZOS_ONLY(error_def(ERR_BADTAG);) void dbc_write_p1out(phase_static_area *psa, void *obuf, int olen); void dbc_requeue_block(phase_static_area *psa, block_id blk_num); void dbc_integ_error(phase_static_area *psa, block_id blk_num, char_ptr_t emsg); void dbc_process_block(phase_static_area *psa, int blk_num, gtm_off_t dbptr); uchar_ptr_t dbc_format_key(phase_static_area *psa, uchar_ptr_t rec_p); /* Phase 1 certification process scans the dstabase */ void dbcertify_scan_phase(void) { int max_max_rec_size; /* Maximum value for max record size for given block size */ int lm_offset; /* Local bit map offset */ int mm_offset; /* Master map offset */ int save_errno, blk_index; ssize_t rc; size_t len; uchar_ptr_t badfn; char_ptr_t errmsg; unsigned char dbfn[MAX_FN_LEN + 1]; unsigned short buff_len; gtm_off_t dbptr; boolean_t outfile_present; enum gdsblk_type blk_type; block_id bitmap_blk_num, last_bitmap_blk_num, blk_num; integ_error_blk_list *iebl; phase_static_area *psa; ZOS_ONLY(int realfiletag;) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; psa = psa_gbl; DBC_DEBUG(("DBC_DEBUG: Beginning scan phase\n")); psa->bsu_keys = TRUE; UNIX_ONLY(atexit(dbc_scan_phase_cleanup)); TREF(transform) = TRUE; psa->block_depth = psa->block_depth_hwm = -1; /* Initialize no cache */ initialize_pattern_table(); /* On VMS, file operations are in 512 byte chunks which seems to give VMS some fidgies when we rewrite the header later. Make sure the header is in one single 512 byte block. */ assert(DISK_BLOCK_SIZE == SIZEOF(p1hdr)); /* Check results of option parse */ psa->phase_one = TRUE; psa->report_only = (CLI_PRESENT == cli_present("REPORT_ONLY")); psa->detail = (CLI_PRESENT == cli_present("DETAIL")); psa->bsu_keys = !cli_negated("BSU_KEYS"); if (outfile_present = (CLI_PRESENT == cli_present("OUTFILE"))) { buff_len = SIZEOF(psa->outfn) - 1; if (FALSE == cli_get_str("OUTFILE", (char_ptr_t)psa->outfn, &buff_len)) mupip_exit(ERR_MUPCLIERR); psa->outfn[buff_len] = '\0'; /* Not null terminated if max string on UNIX, not at all on VMS */ } if (CLI_PRESENT == cli_present("TEMPFILE_DIR")) { /* Want to put temp files in this directory */ buff_len = SIZEOF(psa->tmpfiledir) - 1; if (FALSE == cli_get_str("TEMPFILE_DIR", (char_ptr_t)psa->tmpfiledir, &buff_len)) mupip_exit(ERR_MUPCLIERR); psa->tmpfiledir[buff_len] = '\0'; } psa->keep_temp_files = (CLI_PRESENT == cli_present("KEEP_TEMPS")); buff_len = SIZEOF(psa->regname) - 1; if (FALSE == cli_get_str("REGION", (char_ptr_t)psa->regname, &buff_len)) mupip_exit(ERR_MUPCLIERR); psa->regname[buff_len] = '\0'; /* First order of business is to flush the database in the cache so we start with as current a version as possible. */ dbc_open_command_file(psa); # ifdef VMS strcpy((char_ptr_t)psa->util_cmd_buff, RESULT_ASGN); strcat((char_ptr_t)psa->util_cmd_buff, (char_ptr_t)psa->tmprsltfile); dbc_write_command_file(psa, (char_ptr_t)psa->util_cmd_buff); dbc_write_command_file(psa, DSE_START); # else strcpy((char_ptr_t)psa->util_cmd_buff, DSE_START_PIPE_RSLT1); strcat((char_ptr_t)psa->util_cmd_buff, (char_ptr_t)psa->tmprsltfile); strcat((char_ptr_t)psa->util_cmd_buff, DSE_START_PIPE_RSLT2); dbc_write_command_file(psa, (char_ptr_t)psa->util_cmd_buff); # endif strcpy((char_ptr_t)psa->util_cmd_buff, DSE_FIND_REG_ALL); strcat((char_ptr_t)psa->util_cmd_buff, "="); strcat((char_ptr_t)psa->util_cmd_buff, (char_ptr_t)psa->regname); dbc_write_command_file(psa, (char_ptr_t)psa->util_cmd_buff); dbc_write_command_file(psa, DSE_BFLUSH); dbc_write_command_file(psa, DSE_QUIT); UNIX_ONLY(dbc_write_command_file(psa, "EOF")); dbc_close_command_file(psa); dbc_remove_result_file(psa); dbc_run_command_file(psa, "DSE", DSE_BFLUSH, TRUE); /* Also need to find out what the database name for this region is */ dbc_find_database_filename(psa, psa->regname, dbfn); /* See if a phase-1 output filename was specified. If not, create a default name */ if (!outfile_present) { /* No output file name specified -- supply a default */ len = strlen((char_ptr_t)dbfn); if (MAX_FN_LEN < (len + SIZEOF(DEFAULT_OUTFILE_SUFFIX) - 1)) { badfn = malloc(len + SIZEOF(DEFAULT_OUTFILE_SUFFIX)); memcpy(badfn, dbfn, len); badfn[len] = 0; strcat((char_ptr_t)badfn, DEFAULT_OUTFILE_SUFFIX); rts_error(VARLSTCNT(6) ERR_FILENAMETOOLONG, 0, ERR_TEXT, 2, RTS_ERROR_STRING((char_ptr_t)badfn)); } strcpy((char_ptr_t)psa->outfn, (char_ptr_t)dbfn); strcat((char_ptr_t)psa->outfn, DEFAULT_OUTFILE_SUFFIX); } /* Build data structures and open database */ MALLOC_INIT(psa->dbc_gv_cur_region, SIZEOF(gd_region)); MALLOC_INIT(psa->dbc_gv_cur_region->dyn.addr, SIZEOF(gd_segment)); psa->dbc_gv_cur_region->dyn.addr->acc_meth = dba_bg; len = strlen((char_ptr_t)dbfn); strcpy((char_ptr_t)psa->dbc_gv_cur_region->dyn.addr->fname, (char_ptr_t)dbfn); psa->dbc_gv_cur_region->dyn.addr->fname_len = (unsigned short)len; FILE_CNTL_INIT(psa->dbc_gv_cur_region->dyn.addr); psa->dbc_gv_cur_region->dyn.addr->file_cntl->file_type = dba_bg; psa->dbc_cs_data = malloc(SIZEOF(*psa->dbc_cs_data)); /* Initialize for db processing - open and read in file-header */ psa->fc = psa->dbc_gv_cur_region->dyn.addr->file_cntl; dbc_init_db(psa); /* If REPORT_ONLY was *NOT* specified, then we require two things: * 1) The reserved bytes value must be at least 8 (UNIX) or 9 (VMS). * 2) The maximum record size must be < blk_size - 16 to allow for new V5 block header. */ max_max_rec_size = psa->dbc_cs_data->blk_size - SIZEOF(blk_hdr); if (VMS_ONLY(9) UNIX_ONLY(8) > psa->dbc_cs_data->reserved_bytes) { gtm_putmsg(VARLSTCNT(4) ERR_DBMINRESBYTES, 2, VMS_ONLY(9) UNIX_ONLY(8), psa->dbc_cs_data->reserved_bytes); if (!psa->report_only) exit(SS_NORMAL - 1); /* Gives -1 on UNIX (failure) and 0 on VMS (failure) */ } if (psa->dbc_cs_data->max_rec_size > max_max_rec_size) { gtm_putmsg(VARLSTCNT(5) ERR_DBMAXREC2BIG, 3, psa->dbc_cs_data->max_rec_size, psa->dbc_cs_data->blk_size, max_max_rec_size); if (!psa->report_only) exit(SS_NORMAL - 1); } /* If not REPORT_ONLY, open the phase-1 output file and write header info. Note this will be * re-written at the completion of the process. */ if (!psa->report_only) { /* Recreate the file entirely if it exists */ psa->outfd = OPEN3((char_ptr_t)psa->outfn, O_WRONLY + O_CREAT + O_TRUNC, S_IRUSR + S_IWUSR RMS_OPEN_BIN); if (FD_INVALID == psa->outfd) { /* The following STRERROR() extraction necessary for VMS portability */ save_errno = errno; errmsg = STRERROR(save_errno); rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, RTS_ERROR_STRING((char_ptr_t)psa->outfn), ERR_TEXT, 2, RTS_ERROR_STRING(errmsg)); } # ifdef __MVS__ if (-1 == gtm_zos_set_tag(psa->outfd, TAG_BINARY, TAG_NOTTEXT, TAG_FORCE, &realfiletag)) TAG_POLICY_GTM_PUTMSG((char_ptr_t)psa->outfn, errno, realfiletag, TAG_BINARY); # endif memset((void *)&psa->ofhdr, 0, SIZEOF(p1hdr)); memcpy(psa->ofhdr.p1hdr_tag, P1HDR_TAG, SIZEOF(psa->ofhdr.p1hdr_tag)); dbc_write_p1out(psa, &psa->ofhdr, SIZEOF(p1hdr)); /* Initial hdr is all zeroes */ } /* Initialize */ psa->block_buff = malloc(psa->dbc_cs_data->blk_size); /* Current data/index block we are looking at */ psa->curr_lbmap_buff= malloc(psa->dbc_cs_data->blk_size); /* Current local bit map cache */ psa->local_bit_map_cnt = (psa->dbc_cs_data->trans_hist.total_blks + psa->dbc_cs_data->bplmap - 1) / psa->dbc_cs_data->bplmap; dbptr = (psa->dbc_cs_data->start_vbn - 1) * DISK_BLOCK_SIZE; blk_num = 0; /* Loop to process every local bit map in the database. Since the flag tells us only * (0) it is full or (1) it is not full, we have to completely process each local bit map. */ psa->fc->op_len = psa->dbc_cs_data->blk_size; for (mm_offset = 0; (mm_offset < psa->local_bit_map_cnt) && (blk_num < psa->dbc_cs_data->trans_hist.total_blks); ++mm_offset) { /* Once through for each master map bit in our database */ psa->fc->op_buff = psa->curr_lbmap_buff; psa->fc->op_pos = (dbptr / DISK_BLOCK_SIZE) + 1; dbcertify_dbfilop(psa); /* Read local bitmap block (no return if error) */ /* Verification we haven't gotten lost */ assert(0 == (blk_num % psa->dbc_cs_data->bplmap)); /* Loop through each local bit map processing (checking) allocated blocks */ for (lm_offset = 0; (lm_offset < (psa->dbc_cs_data->bplmap * BML_BITS_PER_BLK)) && (blk_num < psa->dbc_cs_data->trans_hist.total_blks); lm_offset += BML_BITS_PER_BLK, dbptr += psa->dbc_cs_data->blk_size, blk_num++) { if (gvcst_blk_is_allocated(psa->curr_lbmap_buff + SIZEOF(v15_blk_hdr), lm_offset)) /* This block is in use -- process it */ dbc_process_block(psa, blk_num, dbptr); else { DBC_DEBUG(("DBC_DEBUG: Block 0x%x is NOT allocated -- bypassing\n", blk_num)); psa->blks_bypassed++; } } if ((BLKS_PER_LMAP * BML_BITS_PER_BLK) > lm_offset) DBC_DEBUG(("DBC_DEBUG: Partial lmap processed - blk 0x%x - lm_offset 0x%x\n", \ (mm_offset * BLKS_PER_LMAP), lm_offset)); } /* If there were any blocks we had trouble processing the first time through, perform a second buffer flush and * retry them. If they are still broken, it is an error this time. Note all integ errors are fatal but record-too-long * errors only cause the run to turn into a "report_only" type run and thus do not create the output file but * scanning continues. */ if (NULL != psa->iebl) { DBC_DEBUG(("DBC_DEBUG: Entering block re-processing loop\n")); psa->final = TRUE; last_bitmap_blk_num = -1; for (iebl = psa->iebl; iebl; iebl = iebl->next) for (blk_index = 0; blk_index < iebl->blk_cnt; blk_index++) { /* For each previously broken block. First see if they are still allocated */ blk_num = iebl->blk_list[blk_index]; assert(blk_num); bitmap_blk_num = ROUND_DOWN2(blk_num, psa->dbc_cs_data->bplmap); /* Read bitmap in if it isn't already in our buffer */ if (bitmap_blk_num != last_bitmap_blk_num) { psa->fc->op_buff = psa->curr_lbmap_buff; dbptr = ((psa->dbc_cs_data->start_vbn - 1) * DISK_BLOCK_SIZE) + psa->dbc_cs_data->free_space + ((gtm_off_t)psa->dbc_cs_data->blk_size * bitmap_blk_num); psa->fc->op_pos = (dbptr / DISK_BLOCK_SIZE) + 1; dbcertify_dbfilop(psa); /* Read local bitmap block (no return if error) */ last_bitmap_blk_num = bitmap_blk_num; } lm_offset = (blk_num - bitmap_blk_num) * 2; dbptr = ((psa->dbc_cs_data->start_vbn - 1) * DISK_BLOCK_SIZE) + psa->dbc_cs_data->free_space + ((gtm_off_t)psa->dbc_cs_data->blk_size * blk_num); if (gvcst_blk_is_allocated(psa->curr_lbmap_buff + SIZEOF(v15_blk_hdr), lm_offset)) /* This block is in use -- process it */ dbc_process_block(psa, blk_num, dbptr); else { DBC_DEBUG(("DBC_DEBUG: Bypassing block 0x%x because no longer allocated\n", blk_num)); psa->blks_bypassed++; } } DBC_DEBUG(("DBC_DEBUG: Block reprocessing complete\n")); } /* Now, update the fields in the output file's fileheader if we are writing it */ if (!psa->report_only) { rc = lseek(psa->outfd, (ssize_t)0, SEEK_SET); if (-1 == rc) { save_errno = errno; errmsg = STRERROR(save_errno); rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("lseek()"), CALLFROM, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg)); } psa->ofhdr.tn = psa->dbc_cs_data->trans_hist.curr_tn; psa->ofhdr.blk_count = psa->blks_too_big; psa->ofhdr.tot_blocks = psa->blks_processed; psa->ofhdr.dt_leaf_cnt = psa->dtlvl0; psa->ofhdr.dt_index_cnt = psa->dtlvln0; psa->ofhdr.gvt_leaf_cnt = psa->gvtlvl0; psa->ofhdr.gvt_index_cnt = psa->gvtlvln0; psa->ofhdr.uid_len = SIZEOF(unique_file_id); /* Size used by v5cbsu since this field len varies by platform */ memcpy(&psa->ofhdr.unique_id, &FILE_INFO(psa->dbc_gv_cur_region)->UNIX_ONLY(fileid)VMS_ONLY(file_id), SIZEOF(unique_file_id)); assert(SIZEOF(psa->ofhdr.regname) > strlen((char_ptr_t)psa->regname)); strcpy((char_ptr_t)psa->ofhdr.regname, (char_ptr_t)psa->regname); assert(SIZEOF(psa->ofhdr.dbfn) > strlen((char_ptr_t)psa->dbc_gv_cur_region->dyn.addr->fname)); strcpy((char_ptr_t)psa->ofhdr.dbfn, (char_ptr_t)psa->dbc_gv_cur_region->dyn.addr->fname); dbc_write_p1out(psa, &psa->ofhdr, SIZEOF(p1hdr)); /* Rewrite populated output file header */ CLOSEFILE_RESET(psa->outfd, rc); /* Close output file; Resets "psa->outfd" to FD_INVALID */ if (-1 == rc) { save_errno = errno; errmsg = STRERROR(save_errno); rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("close()"), CALLFROM, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg)); } } psa->fc->op = FC_CLOSE; dbcertify_dbfilop(psa); /* Close database */ PRINTF("\n\n"); PRINTF("Total blocks in database ------- %12d [0x%08x]\n", psa->dbc_cs_data->trans_hist.total_blks, psa->dbc_cs_data->trans_hist.total_blks); PRINTF("Total local bitmap blocks ------- %12d [0x%08x]\n", psa->local_bit_map_cnt, psa->local_bit_map_cnt); PRINTF("Blocks bypassed ----------------- %12d [0x%08x]\n", psa->blks_bypassed, psa->blks_bypassed); PRINTF("Blocks processed ---------------- %12d [0x%08x]\n", psa->blks_processed, psa->blks_processed); PRINTF("Blocks needing to be split ------ %12d [0x%08x]\n", psa->blks_too_big, psa->blks_too_big); PRINTF("- DT leaf (data) blocks --------- %12d [0x%08x]\n", psa->dtlvl0, psa->dtlvl0); PRINTF("- DT index blocks --------------- %12d [0x%08x]\n", psa->dtlvln0, psa->dtlvln0); PRINTF("- GVT leaf (data) blocks -------- %12d [0x%08x]\n", psa->gvtlvl0, psa->gvtlvl0); PRINTF("- GVT index blocks -------------- %12d [0x%08x]\n", psa->gvtlvln0, psa->gvtlvln0); /* Release resources */ free(psa->dbc_cs_data); # ifdef VMS /* Some extra freeing of control blocks on VMS */ if (NULL != FILE_INFO(psa->dbc_gv_cur_region)->fab) free(FILE_INFO(psa->dbc_gv_cur_region)->fab); if (NULL != FILE_INFO(psa->dbc_gv_cur_region)->nam) { if (NULL != FILE_INFO(psa->dbc_gv_cur_region)->nam->nam$l_esa) free(FILE_INFO(psa->dbc_gv_cur_region)->nam->nam$l_esa); free(FILE_INFO(psa->dbc_gv_cur_region)->nam); } if (NULL != FILE_INFO(psa->dbc_gv_cur_region)->xabfhc) free(FILE_INFO(psa->dbc_gv_cur_region)->xabfhc); if (NULL != FILE_INFO(psa->dbc_gv_cur_region)->xabpro) free(FILE_INFO(psa->dbc_gv_cur_region)->xabpro); # endif free(psa->dbc_gv_cur_region->dyn.addr->file_cntl->file_info); free(psa->dbc_gv_cur_region->dyn.addr->file_cntl); free(psa->dbc_gv_cur_region->dyn.addr); free(psa->dbc_gv_cur_region); free(psa->curr_lbmap_buff); free(psa->block_buff); for (; psa->iebl; ) { iebl = psa->iebl->next; free(psa->iebl); psa->iebl = iebl; } free(psa); } /* Write the given output record but keep the global variable "chksum" updated with the tally. * Assumes that all writes are from aligned buffers (regardless of how they end up on disk). */ void dbc_write_p1out(phase_static_area *psa, void *obuf, int olen) { int save_errno; ssize_t rc; char_ptr_t errmsg; DBC_DEBUG(("DBC_DEBUG: Output %d bytes to dbcertscan output file\n", olen)); rc = write(psa->outfd, obuf, olen); if (-1 == rc) { save_errno = errno; errmsg = STRERROR(save_errno); rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("close()"), CALLFROM, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg)); } } /* Routine to process a database block */ void dbc_process_block(phase_static_area *psa, int blk_num, gtm_off_t dbptr) { int rec_len, rec1_cmpc, rec2_cmpc, key_len, blk_levl, rec1_len, rec2_len, rec2_rlen; int tmp_cmpc; int free_bytes, blk_len; int save_errno, mm_offset; ssize_t rc; size_t len, rec1_gvn_len; boolean_t have_dt_blk; unsigned short us_rec_len; char_ptr_t errmsg, key_pfx; uchar_ptr_t rec_ptr, rec1_ptr, rec2_ptr, key_ptr; enum gdsblk_type blk_type; DBC_DEBUG(("DBC_DEBUG: Block 0x%x is allocated -- processing\n", blk_num)); psa->fc->op_buff = psa->block_buff; psa->fc->op_pos = (dbptr / DISK_BLOCK_SIZE) + 1; dbcertify_dbfilop(psa); /* Read data/index block (no return if error) */ /* Check free space in block */ blk_len = ((v15_blk_hdr_ptr_t)psa->block_buff)->bsiz; free_bytes = psa->dbc_cs_data->blk_size - blk_len; if (UNIX_ONLY(8) VMS_ONLY(9) > free_bytes) { blk_levl = ((v15_blk_hdr_ptr_t)psa->block_buff)->levl; if (MAX_BT_DEPTH <= blk_levl) dbc_integ_error(psa, blk_num, "Bad block level"); /* Isolate first record for length check */ rec1_ptr = psa->block_buff + SIZEOF(v15_blk_hdr); rec1_cmpc = EVAL_CMPC((rec_hdr_ptr_t)rec1_ptr); if (0 != rec1_cmpc) dbc_integ_error(psa, blk_num, "Bad compression count"); GET_USHORT(us_rec_len, &((rec_hdr_ptr_t)rec1_ptr)->rsiz); rec1_len = us_rec_len; if ((rec1_len + SIZEOF(v15_blk_hdr)) < blk_len) { /* There is a 2nd record. It must also be checked as it is possible for a * too-long record to exist as the 2nd record if it is a near clone of the * first record (differing only in the last byte of the key) and the first * record has no value (null value). */ rec2_ptr = rec1_ptr + rec1_len; rec2_cmpc = EVAL_CMPC((rec_hdr_ptr_t)rec2_ptr); if (rec2_cmpc > rec1_len) dbc_integ_error(psa, blk_num, "Compression count too large"); GET_USHORT(us_rec_len, &((rec_hdr_ptr_t)rec2_ptr)->rsiz); rec2_len = us_rec_len; rec2_rlen = rec2_len + rec2_cmpc; } else { rec2_len = rec2_rlen = 0; /* There is no second record */ assert(0 == blk_levl); /* And thus this is supposed to be lvl0 data block */ } if (rec1_len > psa->dbc_cs_data->max_rec_size) { /* First record exceeds maximum size */ rec_len = rec1_len; rec_ptr = rec1_ptr; } else if (rec2_rlen > psa->dbc_cs_data->max_rec_size) { /* Second record exceeds maximum size */ rec_len = rec2_rlen; rec_ptr = rec2_ptr; } else /* All is well .. set flag record length is ok */ rec_len = 0; if (rec_len) { /* One of these records exceeds the max size - might be a transitory integ on * 1st pass or permanent on 2nd pass. */ assert(rec_ptr); if (psa->final) { /* Should be a data block with a too-long record in it */ assert(0 == ((v15_blk_hdr_ptr_t)psa->block_buff)->levl); psa->gvtlvl0++; key_ptr = dbc_format_key(psa, rec_ptr); /* Text representation of the key */ gtm_putmsg(VARLSTCNT(9) ERR_DBCREC2BIG, 7, RTS_ERROR_STRING((char_ptr_t)key_ptr), rec_len, blk_num, psa->dbc_cs_data->max_rec_size, psa->dbc_gv_cur_region->dyn.addr->fname_len, psa->dbc_gv_cur_region->dyn.addr->fname); if (!psa->report_only) { CLOSEFILE_RESET(psa->outfd, rc); /* Close output file; Resets "psa->outfd" to FD_INVALID */ if (-1 == rc) { save_errno = errno; errmsg = STRERROR(save_errno); rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("close()"), CALLFROM, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg)); } if (-1 == remove((char_ptr_t)psa->outfn)) { /* Delete bogus output file */ save_errno = errno; errmsg = STRERROR(save_errno); rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("remove()"), CALLFROM, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg)); } psa->report_only = TRUE; /* No more writing to output file */ } } else /* Not our final trip through, cause the block to be requeued for later processing */ dbc_requeue_block(psa, blk_num); return; } /* Determine type of block (DT lvl 0, DT lvl !0, GVT lvl 0, GVT lvl !0) * Rules for checking: * 1) If compression count of 2nd record is zero, it *must* be a directory tree block. This is a fast path * check to avoid doing the strlen in the second check. * 2) If compression count of second record is less than or equal to the length of the global variable name, * then this must be a directory tree block. The reason this check works is a GVT index or data block * would have same GVN in the 2nd record as the first so the compression count would be a minimum of * (length(GVN) + 1). The "+ 1" is for the terminating null of the GVN. * 3) If there is no second record, this must be a lvl0 data tree block as no other block could exceed * the maximum block size with a single record. */ have_dt_blk = FALSE; if (0 != rec2_len) { /* There is a second record .. */ if (0 == rec2_cmpc) have_dt_blk = TRUE; /* Only DT records have non-zero cmpc in 2nd record */ else { rec1_gvn_len = strlen((char_ptr_t)rec1_ptr + SIZEOF(rec_hdr)); if (rec2_cmpc <= rec1_gvn_len) have_dt_blk = TRUE; } if (have_dt_blk) { if (0 == blk_levl) { psa->dtlvl0++; blk_type = gdsblk_dtleaf; } else { psa->dtlvln0++; if (1 != blk_num) /* Quick root block check */ blk_type = gdsblk_dtindex; else blk_type = gdsblk_dtroot; } } else { if (0 == blk_levl) { psa->gvtlvl0++; blk_type = gdsblk_gvtleaf; } else { psa->gvtlvln0++; /* Note from the master map, we cannot tell if this is a gvtroot block or not so just mark it as an index block for now. It will be noted as a root block when read in by stage 2. */ blk_type = gdsblk_gvtindex; } } } else { /* There was no second record. This record must be a lvl 0 data block */ psa->gvtlvl0++; blk_type = gdsblk_gvtleaf; } if (psa->bsu_keys && gdsblk_gvtleaf == blk_type) { /* Get text representation of the key. Because we are not using the DT in the cache, there is * a possibility that we cannot find this global however that chance should be slight. Not finding * it only means that this record cannot be processed by v5cbsu.m and will instead have to be * processed by phase-2. This is an acceptable alternative. * * The key we format is the second record in the block if it is available. This is because of the * way an update in place takes place. If the block is too big, the block is split at the point * of the update. If the (somewhat long) keys of the first and second records differ by only 1 * byte and the first record has no value, we could get into a situation where the second record * is highly compressed and a split at that point will give back insufficient space for the * new block to meet the block size requirements. If instead we split the record after the 2nd * record in this situation, the resulting blocks will be sized sufficiently to meet the upgrade * requirements. */ if (rec2_len) { /* There is a 2nd record */ rec_ptr = rec2_ptr; key_pfx = "[2] "; } else { /* No 2nd record, format 1st record instead */ rec_ptr = rec1_ptr; key_pfx = "[1] "; } key_ptr = dbc_format_key(psa, (rec2_len ? rec2_ptr : rec1_ptr)); } else { key_ptr = (uchar_ptr_t)""; key_pfx = ""; } if (psa->detail) { if (0 == psa->blks_too_big) { /* Print header */ PRINTF("\nProblem blocks (max block size = %d):\n\n", psa->dbc_cs_data->blk_size); PRINTF(" Blknum Offset Blktype BlkLvl Blksize Free" " Key\n"); } # ifndef __osf__ GTM64_ONLY(PRINTF(" 0x%08x %16lx %s %5d %9d %6d %s%s\n", blk_num, dbptr, (have_dt_blk ? " DT " : " GVT "), ((v15_blk_hdr_ptr_t)psa->block_buff)->levl, ((v15_blk_hdr_ptr_t)psa->block_buff)->bsiz, free_bytes, key_pfx, key_ptr)); NON_GTM64_ONLY(PRINTF(" 0x%08x %16llx %s %5d %9d %6d %s%s\n", blk_num, dbptr, (have_dt_blk ? " DT " : " GVT "), ((v15_blk_hdr_ptr_t)psa->block_buff)->levl, ((v15_blk_hdr_ptr_t)psa->block_buff)->bsiz, free_bytes, key_pfx, key_ptr)); VMS_ONLY(PRINTF(" 0x%08x %16llx %s %5d %9d %6d %s%s\n", blk_num, dbptr, (have_dt_blk ? " DT " : " GVT "), ((v15_blk_hdr_ptr_t)psa->block_buff)->levl, ((v15_blk_hdr_ptr_t)psa->block_buff)->bsiz, free_bytes, key_pfx, key_ptr)); # else PRINTF(" 0x%08x %16lx %s %5d %9d %6d\n %s%s", blk_num, dbptr, (have_dt_blk ? " DT " : " GVT "), ((v15_blk_hdr_ptr_t)psa->block_buff)->levl, ((v15_blk_hdr_ptr_t)psa->block_buff)->bsiz, free_bytes, key_pfx, key_ptr); # endif } psa->blks_too_big++; /* Prepare the record to put to the output file */ if (!psa->report_only) { GET_LONG(psa->rhdr.tn, &((v15_blk_hdr_ptr_t)psa->block_buff)->tn); psa->rhdr.blk_num = blk_num; psa->rhdr.blk_type = blk_type; psa->rhdr.blk_levl = blk_levl; if (psa->bsu_keys && gdsblk_gvtleaf == blk_type) psa->rhdr.akey_len = key_len = STRLEN((char_ptr_t)key_ptr); else psa->rhdr.akey_len = 0; dbc_write_p1out(psa, &psa->rhdr, SIZEOF(p1rec)); if (psa->bsu_keys && gdsblk_gvtleaf == blk_type) dbc_write_p1out(psa, key_ptr, key_len); } } psa->blks_processed++; } /* Requeue a block for later processing after a flush to verify we have a problem or not */ void dbc_requeue_block(phase_static_area *psa, block_id blk_num) { integ_error_blk_list *iebl; if (NULL == psa->iebl || MAX_IEB_CNT <= (psa->iebl->blk_cnt + 1)) { /* Need a new/another block to hold error blocks */ DBC_DEBUG(("DBC_DEBUG: Allocating new iebl struct\n")); iebl = malloc(SIZEOF(integ_error_blk_list)); iebl->next = psa->iebl; iebl->blk_cnt = 0; psa->iebl = iebl; } DBC_DEBUG(("DBC_DEBUG: Requeuing block 0x%x for later processing\n", blk_num)) psa->iebl->blk_list[psa->iebl->blk_cnt++] = blk_num; } /* Routine to handle integrity errors. If first pass (not final), requeue the block. If on * final pass, give integrity rts_error. */ void dbc_integ_error(phase_static_area *psa, block_id blk_num, char_ptr_t emsg) { char_ptr_t errmsg; unsigned char intgerrmsg[256]; int save_errno; ssize_t rc; size_t len; if (!psa->final) dbc_requeue_block(psa, blk_num); else { /* Give integrity error message */ if (!psa->report_only) { CLOSEFILE_RESET(psa->outfd, rc); /* Close output file; Resets "psa->outfd" to FD_INVALID */ if (-1 == rc) { save_errno = errno; errmsg = STRERROR(save_errno); rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("close()"), CALLFROM, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg)); } if (-1 == remove((char_ptr_t)psa->outfn)) { /* Delete bogus output file */ save_errno = errno; errmsg = STRERROR(save_errno); rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("remove()"), CALLFROM, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg)); } psa->report_only = TRUE; /* No more writing to output file */ } intgerrmsg[0] = 0; strcpy((char_ptr_t)intgerrmsg, emsg); strcat((char_ptr_t)intgerrmsg, " in block 0x"); len = strlen((char_ptr_t)intgerrmsg); i2hex(blk_num, &intgerrmsg[len], 8); intgerrmsg[len + 8] = 0; rts_error(VARLSTCNT(8) ERR_DBCINTEGERR, 2, RTS_ERROR_STRING((char_ptr_t)psa->ofhdr.dbfn), ERR_TEXT, 2, RTS_ERROR_STRING((char_ptr_t)intgerrmsg)); } } /* Generate an ascii representation of the given key in the current block buffer. * This is accomplished (mainly) by: * 1) Locating the key within the record. * 2) Calling the dbc_find_dtblk() routine to locate the directory entry for us. * 3) Setting up gv_target and friends to point to the entry. * 4) Checking the located directory entry for collation information. * 5) Calling format_targ_key() to do the formatting into our buffer. * Note: usage of "first_rec_key" is somewhat overloaded in this routine. Under most * circumstances, it is most likely the second key that is being formatted but * this is a defined area that is available for use in this (scan phase) routine * so we use it. */ uchar_ptr_t dbc_format_key(phase_static_area *psa, uchar_ptr_t trec_p) { int dtblk_index, hdr_len, rec_value_len, rec_len, rec_cmpc; int tmp_cmpc; size_t len; uchar_ptr_t blk_p, rec_value_p, subrec_p, key_end_p, rec_p; block_info *blk_set_p; unsigned short us_rec_len; dbc_init_key(psa, &psa->first_rec_key); /* We have to parse the block down to the supplied key to make sure the compressed portions * of the key are available. */ rec_p = psa->block_buff + SIZEOF(v15_blk_hdr); while (rec_p < trec_p) { dbc_find_key(psa, psa->first_rec_key, rec_p, 0); GET_USHORT(us_rec_len, &((rec_hdr_ptr_t)rec_p)->rsiz); rec_p += us_rec_len; } assert(rec_p == trec_p); dbc_find_key(psa, psa->first_rec_key, trec_p, 0); psa->first_rec_key->gvn_len = USTRLEN((char_ptr_t)psa->first_rec_key->base); /* The GVN we need to lookup in the DT */ assert(0 < psa->first_rec_key->gvn_len); psa->block_depth = -1; /* Reset to beginning each pass */ dtblk_index = dbc_find_dtblk(psa, psa->first_rec_key, 0); if (0 > dtblk_index) { /* Couldn't find the GVN in the DT. Tiz possible but rare (concurrency issues) and of no major consequence. */ assert(FALSE); return NULL; } blk_set_p = &psa->blk_set[dtblk_index]; blk_p = blk_set_p->old_buff; assert(0 == ((v15_blk_hdr_ptr_t)blk_p)->levl); rec_cmpc = EVAL_CMPC((rec_hdr *)blk_set_p->curr_rec); rec_value_p = (blk_set_p->curr_rec + SIZEOF(rec_hdr) + blk_set_p->curr_blk_key->end + 1 - rec_cmpc); /* Verify that the dt record we found is the exact one we were looking for */ if ((psa->first_rec_key->gvn_len + 1) != blk_set_p->curr_blk_key->end) /* Some concurrency issues no doubt.. */ return NULL; if (0 != memcmp(psa->first_rec_key->base, blk_set_p->curr_blk_key->base, blk_set_p->curr_blk_key->end)) return NULL; /* Create gv_target if necessary */ if (NULL == gv_target) { gv_target = malloc(SIZEOF(gv_namehead) + psa->dbc_cs_data->max_key_size); gv_target->clue.prev = 0; gv_target->clue.top = psa->first_rec_key->top; } /* Copy our key to gv_target->clue since dbc_gv_key is somewhat different */ gv_target->clue.end = psa->first_rec_key->end; memcpy(gv_target->clue.base, psa->first_rec_key->base, psa->first_rec_key->end + 1); /* Figure out collation for this global */ GET_USHORT(us_rec_len, &((rec_hdr *)blk_set_p->curr_rec)->rsiz); rec_len = us_rec_len; rec_value_len = (int)(rec_len - (rec_value_p - blk_set_p->curr_rec)); if (SIZEOF(block_id) < rec_value_len) { /* This global potentially has collation data in its record (taken from gvcst_root_search()) */ subrec_p = get_spec(rec_value_p + SIZEOF(block_id), (int)(rec_value_len - SIZEOF(block_id)), COLL_SPEC); if (subrec_p) { gv_target->nct = *(subrec_p + COLL_NCT_OFFSET); gv_target->act = *(subrec_p + COLL_ACT_OFFSET); gv_target->ver = *(subrec_p + COLL_VER_OFFSET); } else { gv_target->nct = 0; gv_target->act = 0; gv_target->ver = 0; } } else { gv_target->nct = 0; gv_target->act = psa->dbc_cs_data->def_coll; gv_target->ver = psa->dbc_cs_data->def_coll_ver; } /* If there was any collation data involved, make sure the routines are available */ if (gv_target->act) { /* Need to setup gv_altkey in case of errors (contains gvn) */ if (NULL == gv_altkey) { gv_altkey = malloc(SIZEOF(gv_key) + psa->dbc_cs_data->max_key_size); gv_altkey->prev = 0; gv_altkey->top = psa->first_rec_key->top; } gv_altkey->end = psa->first_rec_key->gvn_len + 1; memcpy(gv_altkey->base, psa->first_rec_key->base, psa->first_rec_key->gvn_len + 1); act_in_gvt(); } assert(gv_target->act || NULL == gv_target->collseq); /* Format the resulting key into the result buffer which is sized appropriately for this task */ key_end_p = format_targ_key(psa->rslt_buff, SIZEOF(psa->rslt_buff), &gv_target->clue, TRUE); *key_end_p = 0; return psa->rslt_buff; } /* Simple cleanup routine for this scan phaase */ void dbc_scan_phase_cleanup(void) { /* Cleanup our temporary files */ if (psa_gbl->tmp_file_names_gend) { /* only close/delete if we know what they are */ if (psa_gbl->tcfp) dbc_close_command_file(psa_gbl); if (!psa_gbl->keep_temp_files) dbc_remove_command_file(psa_gbl); if (psa_gbl->trfp) dbc_close_result_file(psa_gbl); if (!psa_gbl->keep_temp_files) dbc_remove_result_file(psa_gbl); } } fis-gtm-V6.0-003/sr_port/dbfilop.h0000644000032200000250000000106112201176155015620 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef DBFILOP_INCLUDED #define DBFILOP_INCLUDED uint4 dbfilop(file_control *fc); #endif /* DBFILOP_INCLUDED */ fis-gtm-V6.0-003/sr_port/ddphdr.h0000644000032200000250000002140512201176155015452 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2003 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef DDPHDR_H_INCLUDED #define DDPHDR_H_INCLUDED typedef int4 condition_code; #define MAX_ETHER_DATA_SIZE 1500 #define ETHERNET_HEADER_SIZE 14 /* Is size of Destination address + source address + protocol # */ #define ETHERADDR_LENGTH 6 #define MIN_ETH_RECV_BUFCNT 1 /* from OpenVMS I/O User's Reference Manual, system default */ #define MAX_ETH_RECV_BUFCNT 255 /* from OpenVMS I/O User's Reference Manual */ #define ETH_RCV_BUFCNT 64 /* GT.CM DDP default */ #define DDP_ETH_PROTO_TYPE ((unsigned short)0x3980) /* will be seen as 8039 on the wire */ #define DDP_MIN_MSG_LEN 64 #define DDP_PROTO_VERSION 0x02 /* MSM, DSM-11 use version 2; DSM 6.0 & 6.1, DDP-DOS V1.00.8+ use version 4 */ #define DDP_MSG_TERMINATOR 0xff #define DDP_CIRCUIT_NAME_LEN 3 #define DDP_VOLUME_NAME_LEN 3 #define DDP_UCI_NAME_LEN 3 /* Request codes */ #define DDPTR_USEREXIT 0x00 /* [00] */ /* Individual user sends message to agent to clean up for exit. Per DSM doc, * this code is for an ERROR ON RRB (read request buffer) */ #define DDPTR_LOCK 0x02 /* [02] */ /* Not implemented */ #define DDPTR_UNLOCK 0x04 /* [04] */ /* Not implemented */ #define DDPTR_ZALLOC 0x06 /* [06] */ #define DDPTR_ZDEALLOC 0x08 /* [08] */ #define DDPTR_GET 0x0a /* [10] */ #define DDPTR_PUT 0x0c /* [12] */ #define DDPTR_KILL 0x0e /* [14] */ #define DDPTR_ORDER 0x10 /* [16] */ #define DDPTR_QUERY 0x12 /* [18] */ #define DDPTR_DEFINE 0x14 /* [20] */ #define DDPTR_PREVIOUS 0x16 /* [22] */ #define DDPTR_JOB 0x18 /* [24] */ /* Not implemented */ #define DDPTR_RESPONSE 0x1a /* [26] */ #define DDPTR_ERRESPONSE 0x1c /* [28] */ #define DDPTR_RDRQBUF 0x1e /* [30] */ /* READ REQUEST BUFFER, not implemented */ #define DDPTR_ANNOUNCE 0x20 /* [32] */ /* Response codes other than DDPTR_RESPONSE and DDPTR_ERRESPONSE */ #define DDPTRX_ANNOUNCE 0x80 /* [128] */ /* Announcement that we are connecting */ #define DDPTRX_NOCONNECT 0x81 /* [129] */ /* Named volume set not connected */ #define DDPTRX_CONGESTION 0x82 /* [130] */ /* Agent congestion */ #define DDPTRX_RUNDOWN 0x83 /* [131] */ /* Client wishes to disconnect */ #define DDPTRX_SHUTDOWN 0x84 /* [132] */ /* Shutdown the server */ #define DDPTRX_DUMP 0x85 /* [133] */ /* Start trace */ /* GT.M extended reference form is ^|"globaldirectory"|global, DSM is ^["UCI","VOL"]global */ #define GTM_EXTREF_PREFIX "^|\"" #define GTM_EXTREF_SUFFIX "\"|" #define DSM_EXTREF_PREFIX "^[\"" #define DSM_UCI_VOL_SEPARATOR "\",\"" #define DSM_EXTREF_SUFFIX "\"]" #define DSM_EXTREF_FORM_LEN (STR_LIT_LEN(DSM_EXTREF_PREFIX) + \ DDP_UCI_NAME_LEN + \ STR_LIT_LEN(DSM_UCI_VOL_SEPARATOR) + \ DDP_VOLUME_NAME_LEN + \ STR_LIT_LEN(DSM_EXTREF_SUFFIX)) #define DDP_VOLSET_CONF_LOGICAL_PREFIX "GTMDDP_VOLCONF_" #define DDP_GROUP_LOGICAL_PREFIX "GTMDDP_GROUPS_" #define DDP_ETHER_DEV_PREFIX "GTMDDP_CONTROLLER_" #define DDP_MAXRECSIZE_PREFIX "GTMDDP_MAXRECSIZE_" #define DDP_ETH_RCV_BUFCNT_PREFIX "GTMDDP_ETHRCVBUFCNT_" #define DDP_MAXREQCREDITS_PREFIX "GTMDDP_MAXREQCREDITS_" #define DDP_CLIENT_CKTNAM_LOGI "GTMDDP_CIRCUIT_NAME" #define DDP_MAX_VOLSETS 16 #define DDP_TEXT_ID_LENGTH 3 #define DDP_ANNOUNCE_CODE_LEN 2 /* "WI" or "II" */ #define MAXIMUM_PROCESSES 256 #define DDP_MAX_GROUP 16 #define DDP_DEFAULT_GROUP_MASK 0x0001 /* member of group 0 */ #define DDP_MIN_RECSIZE 1024 #define DDP_LEAST_MAXREQCREDITS 1 #define DDP_LARGEST_MAXREQCREDITS 0xFF /* some constants that were derived from DSM packets */ #define DDP_GROUP_MASK 0x0101 #define DDP_ADVERTISE_INTERVAL 0x00 #define DDP_MAX_REQUEST_CREDITS 0x04 #define DDP_CPU_TYPE 0x01 #define DDP_SOFTWARE_VERSION 0x00 #define DDP_CPU_LOAD_RATING 0x00 #define DDP_AUTOCONFIGURE_VERSION 0x02 #define DDP_ANNOUNCE_FILLER3_LITERAL 0x01ff00ff #define DDP_GLOBAL_TYPE 0x02 /* DDP node status bit masks */ #define DDP_NODE_STATUS_READ 0x01 /* bit is 1 if read locked, 0 if read enabled */ #define DDP_NODE_STATUS_WRITE 0x02 /* bit is 1 if write locked, 0 if write enabled */ #define DDP_NODE_STATUS_STATE 0x04 /* bit is 1 if unreachable, 0 if reachable */ #define DDP_NODE_STATUS_CHANGE 0x10 /* bit is 1 if state change occurred on circuit */ #define DDP_NODE_STATUS_DISABLED 0x20 /* bit is 1 if disabled, 0 if enabled */ #define DDP_NODE_STATUS_ALL_CLEAR 0x00 /* read enabled + write enabled + reachable + no state change + circuit enabled */ #define DDP_LOG_ERROR(err_len, err_string) \ { \ now_t now; /* for GET_CUR_TIME macro */ \ char time_str[CTIME_BEFORE_NL + 2]; /* for GET_CUR_TIME macro*/ \ char *time_ptr; /* for GET_CUR_TIME macro*/ \ bool save_dec_nofac; \ \ GET_CUR_TIME; \ save_dec_nofac = dec_nofac; /* save for later restore */ \ dec_nofac = TRUE; /* don't need error mnemonic prefix, just print the message contents */ \ dec_err(VARLSTCNT(6) ERR_DDPLOGERR, 4, CTIME_BEFORE_NL, time_ptr, (err_len), (err_string)); \ dec_nofac = save_dec_nofac; /* back to what it was */ \ } /* All structures that are DDP messages should be packed; do not let the compiler pad for structure member alignment */ #if defined(__alpha) # pragma member_alignment save # pragma nomember_alignment #endif typedef struct { unsigned short uci; unsigned short volset; } ddp_info; typedef struct { unsigned char trancode; unsigned char proto; unsigned short source_circuit_name; /* 5-bit format */ unsigned short source_job_number; unsigned short remote_circuit_name; /* 5-bit format */ unsigned short remote_job_number; /* 0000 if this is a request */ unsigned char message_number; unsigned char filler1; /* literal 00 */ unsigned short message_length; unsigned char hdrlen; unsigned char txt[1]; } ddp_hdr_t; #define DDP_MSG_HDRLEN 0x0f /* excluding txt field of ddp_hdr_t */ struct frame_hdr { unsigned short frame_length; unsigned char destination_address[ETHERADDR_LENGTH]; unsigned char source_address[ETHERADDR_LENGTH]; unsigned char protocol_type[2]; }; struct in_buffer_struct { struct frame_hdr fh; ddp_hdr_t dh; }; typedef struct { /* byte position in announce packet - 15 is the first position past the header, position starts from 0, header size is 15 bytes */ unsigned short filler0; /* position 15: literal 0x0000 */ unsigned char code[DDP_ANNOUNCE_CODE_LEN]; /* position 17: "WI", or "II" */ unsigned char ether_addr[ETHERADDR_LENGTH]; /* position 19: Ethernet physical address for this node */ unsigned short circuit_name; /* position 25: DDP Node (circuit) name */ unsigned short filler1; /* position 27: reserved for possible name extension */ unsigned short filler2; /* position 29: reserved for possible name extension */ unsigned short max_job_no; /* position 31: max job # */ unsigned short group_mask; /* position 33: DDP group number mask */ unsigned char advertise_interval; /* position 35: Advertise interval in seconds */ unsigned char max_request_credits; /* position 36: Maximum request credits */ unsigned char cpu_type; /* position 37: Remote CPU type */ unsigned char version; /* position 38: Version of software */ unsigned char cpu_load_rating; /* position 39: CPU load rating */ unsigned char proto_version; /* position 40: DDP protocol version in use */ unsigned char node_status; /* position 41: see comments re: DDP_NODE_STATUS_* */ unsigned char autoconfigure_version; /* position 42: DDP autoconfigure version */ unsigned short volset[DDP_MAX_VOLSETS]; /* position 43: 5 bit formal volset names */ /******************************************* begin unknown **************************************************/ unsigned char filler3[32 + 4 + 8]; /* position 75: at position 107 we write literal 0x01ff00ff */ /******************************************* end unknown **************************************************/ unsigned char terminator; /* position 119: DDP_MSG_TERMINATOR */ } ddp_announce_msg_t; #define DDP_ANNOUNCE_MSG_LEN 105 /* from ddp_announce_msg_t */ typedef struct { unsigned char naked_size; unsigned short uci; unsigned short vol; unsigned char global_type; unsigned char global_len; unsigned char global[1]; /* actually, global_len bytes of formatted global reference */ } ddp_global_request_t; /* immediately follows the message header (ddp_hdr) for global request. For SET, ASCII value follows */ #if defined(__alpha) # pragma member_alignment restore #endif #endif /* DDPHDR_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/deferred_events.c0000644000032200000250000004367212201176155017356 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #ifdef VMS # include "efn.h" # include #endif #include "xfer_enum.h" #include "tp_timeout.h" #include "deferred_events.h" #include "outofband.h" #include "interlock.h" #include "lockconst.h" #include "add_inter.h" #include "op.h" #include "iott_wrterr.h" #ifdef DEBUG_DEFERRED_EVENT # include "gtm_stdio.h" #endif #include "fix_xfer_entry.h" /* ============================================================================= * EXTERNAL VARIABLES * ============================================================================= */ /* The transfer table */ GBLREF xfer_entry_t xfer_table[]; /* M Profiling active */ GBLREF boolean_t is_tracing_on; /* Marks sensitive database operations */ GBLREF volatile int4 fast_lock_count; #if defined(VMS) GBLREF volatile short num_deferred; #else GBLREF volatile int4 num_deferred; #endif GBLREF volatile int4 ctrap_action_is, outofband; /* ============================================================================= * FILE-SCOPE VARIABLES * ============================================================================= */ /* ------------------------------------------------------------------ * Declared volatile because accesses occur both in main thread * and (possibly multiple) interrupts levels. * ------------------------------------------------------------------ */ /* Holds count of events logged of each type. * Cleared when table is reset. * Location zero (== no_event) is not used. */ /* INCR_CNT on VMS doesn't return the post-incremented value as is the * case in Unix. But we don't need an interlocked add in VMS since we * should be in an AST and AST's can't be nested (we assert to that effect * in xfer_set_handlers). The macro INCR_CNT_SP accomplishes this task for us. */ #if defined(UNIX) volatile int4 xfer_table_events[DEFERRED_EVENTS]; #define INCR_CNT_SP(X,Y) INCR_CNT(X,Y) #elif defined(VMS) volatile short xfer_table_events[DEFERRED_EVENTS]; #define INCR_CNT_SP(X,Y) (++*X) #else # error "Unsupported Platform" #endif GBLREF global_latch_t defer_latch; /* ------------------------------------------------------- * Act only on first recieved. * ------------------------------------------------------- */ GBLDEF volatile int4 first_event = no_event; error_def(ERR_DEFEREVENT); /* ============================================================================= * EXPORTED FUNCTIONS * ============================================================================= */ /* ------------------------------------------------------------------ * *** INTERRUPT HANDLER *** * Sets up transfer table changes needed for: * - Synchronous handling of asynchronous events. * - Single-stepping and breakpoints * Note: * - Call here from a routine specific to each event type. * - Pass in a single value to pass on to xfer_table set function * for that type. Calling routine should record any other event * info, if needed, in volatile global variables. * - If this is first event logged, will call back to the function * provided and pass along parameter. * Future: * - mdb_condition_handler does not call here -- should change it. * - Ditto for routines related to zbreak and zstep. * - Should put handler prototypes in a header file & include it here, * if can use with some way to ensure type checking. * - A higher-level interface (e.g. change sets) might be better. * ------------------------------------------------------------------ */ boolean_t xfer_set_handlers(int4 event_type, void (*set_fn)(int4 param), int4 param_val) { boolean_t is_first_event = FALSE; /* ------------------------------------------------------------ * Keep track of what event types have come in. * - Get and set value atomically in case of concurrent * events and/or resetting while setting. * ------------------------------------------------------------------ * Use interlocked operations to prevent races between set and reset, * and to avoid missing overlapping sets. * On HPUX-HPPA: * OK only if there's no a risk a conflicting operation is * in progress (can deadlock in micro-lock). * On all platforms: * Don't want I/O from a sensitive area. * Avoid both by testing fast_lock_count, and doing interlocks and * I/O only if it is non-zero. Can't be resetting then, so worst * risk is missing an event when there's already one happening. * ------------------------------------------------------------------ */ VMS_ONLY(assert(lib$ast_in_prog())); if (fast_lock_count == 0) { DBGDFRDEVNT((stderr, "xfer_set_handlers: Before interlocked operations: " "xfer_table_events[%d]=%d, first_event=%s, num_deferred=%d\n", event_type, xfer_table_events[event_type], (is_first_event ? "TRUE" : "FALSE"), num_deferred)); if (1 == INCR_CNT_SP(&xfer_table_events[event_type], &defer_latch)) /* Concurrent events can collide here, too */ is_first_event = (1 == INCR_CNT_SP(&num_deferred, &defer_latch)); DBGDFRDEVNT((stderr, "xfer_set_handlers: After interlocked operations: " "xfer_table_events[%d]=%d, first_event=%s, num_deferred=%d\n", event_type,xfer_table_events[event_type], (is_first_event ? "TRUE" : "FALSE"), num_deferred)); } else if (1 == ++xfer_table_events[event_type]) is_first_event = (1 == ++num_deferred); if (is_first_event) { first_event = event_type; # ifdef DEBUG_DEFERRED_EVENT if (0 != fast_lock_count) DBGDFRDEVNT((stderr, "xfer_set_handlers: Setting xfer_table for event type %d\n", event_type)); # endif /* ------------------------------------------------------- * If table changed, it was not synchronized. * (Assumes these entries are all that would be changed) * Note asserts bypassed for Itanium due to nature of the * fixed up addresses making direct comparisions non-trivial. * -------------------------------------------------------- */ # ifndef __ia64 assert((xfer_table[xf_linefetch] == op_linefetch) || (xfer_table[xf_linefetch] == op_zstepfetch) || (xfer_table[xf_linefetch] == op_zst_fet_over) || (xfer_table[xf_linefetch] == op_mproflinefetch)); assert((xfer_table[xf_linestart] == op_linestart) || (xfer_table[xf_linestart] == op_zstepstart) || (xfer_table[xf_linestart] == op_zst_st_over) || (xfer_table[xf_linestart] == op_mproflinestart)); assert((xfer_table[xf_zbfetch] == op_zbfetch) || (xfer_table[xf_zbfetch] == op_zstzb_fet_over) || (xfer_table[xf_zbfetch] == op_zstzbfetch)); assert((xfer_table[xf_zbstart] == op_zbstart) || (xfer_table[xf_zbstart] == op_zstzb_st_over) || (xfer_table[xf_zbstart] == op_zstzbstart)); assert((xfer_table[xf_forchk1] == op_forchk1) || (xfer_table[xf_forchk1] == op_mprofforchk1)); assert((xfer_table[xf_forloop] == op_forloop)); assert(xfer_table[xf_ret] == opp_ret || xfer_table[xf_ret] == opp_zst_over_ret || xfer_table[xf_ret] == opp_zstepret); assert(xfer_table[xf_retarg] == op_retarg || xfer_table[xf_retarg] == opp_zst_over_retarg || xfer_table[xf_retarg] == opp_zstepretarg); # endif /* !IA64 */ /* ----------------------------------------------- * Now call the specified set function to swap in * the desired handlers (and set flags or whatever). * ----------------------------------------------- */ DBGDFRDEVNT((stderr, "xfer_set_handlers: Driving event setup handler\n")); set_fn(param_val); } # ifdef DEBUG_DEFERRED_EVENT else if (0 != fast_lock_count) { DBGDFRDEVNT((stderr, "xfer_set_handlers: ---Multiple deferred events---\n" "Event type %d occurred while type %d was pending\n", event_type, first_event)); } else { DBGDFRDEVNT((stderr, "xfer_set_handlers: Event bypassed -- was not first event\n")); } # endif assert(no_event != first_event); return is_first_event; } /* ------------------------------------------------------------------ * Reset the transfer table only if current event type * - Needed for abort before action, e.g., a tp timeout * that happened just before commit was too late to be aborted and * so must be cleared. In a case like this, reset should happen * only if the event type attempting the clear is the type * that caused the change. * - Other resets should be unconditional, in case there are * unidentified control paths (e.g. exit paths) that cause * resets when they did not set. * ------------------------------------------------------------------ */ boolean_t xfer_reset_if_setter(int4 event_type) { if (event_type == first_event) { DBGDFRDEVNT((stderr, "xfer_reset_if_setter: event_type is first_event\n")); /* Still have to synchronize the same way... */ if (xfer_reset_handlers(event_type)) { /* Check for and activate any other pending events before returning success */ /* (Not implemented) */ return TRUE; } else { /* Would require interleaved resets to get here, e.g. due to rts_error from interrupt level */ assert(FALSE); return FALSE; } } DBGDFRDEVNT((stderr, "xfer_reset_if_setter: event_type is NOT first_event\n")); return FALSE; } /* ------------------------------------------------------------------ * Reset transfer table to normal settings. * * - Intent: Put back all state that was or could have been changed * due to prior deferral(s). * - Would be easier to implement this assumption if this routine * were changed to delegate responsibility as does the * corresponding set routine. * - Note that all events are reenabled before user's handler * would be executed (assuming one is appropriate for this event * and has been specified) * => It's possible to have handler-in-handler execution. * => If no handler executed, would lose other deferred events due * to reset of all pending. * - If M profiling is active, some entries should be set to the * op_mprof* routines. * - Return value indicates whether reset type matches set type. * If it does not, this indicates an "abnormal" path. * - Should still reset the table in this case. * - BUT: Consider also calling a reset routine for all setters * that have been logged, to allow them to reset themselves, * (for example, to reset TP timer & flags, or anything else * that could cause unintended effects if left set after * deferred events have been cleared). * - May need to update behavior to ensure it doesn't miss a * critical event between registration of first event * and clearing of all events. This seems problematic only if * the following are true: * - Two events are deferred at one time (call them A and B). * - An M exception handler (ZTRAP or device) is required to * execute due to B and perform action X. * - Either no handler executes due to A, or the handler that * does execute does not perform action X in response to B * (this includes the possibility of performing X but not * as needed by B, e.g. perhaps it should happen for both * A and B but only happens for A). * Seems like most or all of these can be addressed by carefully * specifying coding requirements on M handlers. * ------------------------------------------------------------------ */ boolean_t xfer_reset_handlers(int4 event_type) { int4 e_type; boolean_t reset_type_is_set_type; int4 status; int e, ei, e_tot = 0; /* ------------------------------------------------------------------ * Note: If reset routine can preempt path from handler to * set routine (e.g. clearing event before acting on it), * these assertions can fail. * Should not happen in current design. * ------------------------------------------------------------------ */ assert(0 < num_deferred); assert(0 < xfer_table_events[event_type]); if (is_tracing_on) { FIX_XFER_ENTRY(xf_linefetch, op_mproflinefetch); FIX_XFER_ENTRY(xf_linestart, op_mproflinestart); FIX_XFER_ENTRY(xf_forchk1, op_mprofforchk1); } else { FIX_XFER_ENTRY(xf_linefetch, op_linefetch); FIX_XFER_ENTRY(xf_linestart, op_linestart); FIX_XFER_ENTRY(xf_forchk1, op_forchk1); } FIX_XFER_ENTRY(xf_forloop, op_forloop); FIX_XFER_ENTRY(xf_zbfetch, op_zbfetch); FIX_XFER_ENTRY(xf_zbstart, op_zbstart); FIX_XFER_ENTRY(xf_ret, opp_ret); FIX_XFER_ENTRY(xf_retarg, op_retarg); DBGDFRDEVNT((stderr, "xfer_reset_handlers: Reset xfer_table for event type %d.\n", event_type)); reset_type_is_set_type = (event_type == first_event); # ifdef DEBUG if (!reset_type_is_set_type) rts_error(VARLSTCNT(4) ERR_DEFEREVENT, 2, event_type, first_event); # endif # ifdef DEBUG_DEFERRED_EVENT /* Note: concurrent modification of array elements means events that occur during this section will * cause inconsistent totals. */ for (ei = no_event; ei < DEFERRED_EVENTS; ei++) e_tot += xfer_table_events[ei]; if (1 < e_tot) { DBGDFRDEVNT((stderr, "xfer_reset_handlers: Event Log:\n")); for (ei=no_event; ei e_type; e_type++) { xfer_table_events[e_type] = 1; } /* ------------------------------------------------------------------------- * Reset external event modules that need it. * (Should do this in a more modular fashion.) * None * ------------------------------------------------------------------------- */ /* -------------------------------------------- * Reset private variables. * -------------------------------------------- */ first_event = no_event; num_deferred = 0; ctrap_action_is = 0; outofband = 0; # ifdef VMS status = sys$clref(efn_outofband); assert(SS$_WASSET == status); assertpro((SS$_WASSET == status) || (SS$_WASCLR == status)); # endif /* ****************************************************************** * There is a race here: * If a new event interrupts after previous line and before * corresponding assignment in next loop, it will be missed. * For most events, we're going to an M handler anyway, so it won't * matter (assuming the handler would handle all pending events). * But if not going to an M handler (e.g. if resetting zbreak/zstep), * could miss another event. * * Better (to avoid missing any events): * aswp xfer_table_events elements (as described above), and * check here if still zero. If not, must have missed that event * since aswp, possibly before num_deferred was reset => never set * xfer_table => should do that now. * If more than one is nonzero, choose first arbitrarily * unless first_event is now set -- unless it is, we've lost track of * which event was first. * ****************************************************************** */ /* Clear to allow new events to be reset only after we're all done. */ for (e_type = 1; DEFERRED_EVENTS > e_type; e_type++) xfer_table_events[e_type] = FALSE; return reset_type_is_set_type; } /* ------------------------------------------------------------------ * Perform action corresponding to the first async event that * was logged. * ------------------------------------------------------------------ */ void async_action(bool lnfetch_or_start) { /* Double-check that we should be here: */ assert(0 < num_deferred); switch(first_event) { case (outofband_event): /* This function can be invoked only by a op_*intrrpt* transfer table function. Those transfer table * functions should be active only for a short duration between the occurrence of an outofband event * and the handling of it at a logical boundary (next M-line). We dont expect to be running with * those transfer table functions for more than one M-line. If "outofband" is set to 0, the call to * "outofband_action" below will do nothing and we will end up running with the op_*intrrpt* transfer * table functions indefinitely. In this case M-FOR loops are known to return incorrect results which * might lead to application integrity issues. It is therefore considered safer to GTMASSERT as we * will at least have the core for analysis. */ assertpro(0 != outofband); outofband_action(lnfetch_or_start); break; case (tt_write_error_event): # ifdef UNIX xfer_reset_if_setter(tt_write_error_event); iott_wrterr(); # endif /* VMS tt error processing is done in op_*intrrpt */ break; case (network_error_event): /* ------------------------------------------------------- * Network error not implemented here yet. Need to move * from mdb_condition_handler after review. * ------------------------------------------------------- */ case (zstp_or_zbrk_event): /* ------------------------------------------------------- * ZStep/Zbreak events not implemented here yet. Need to * move here after review. * ------------------------------------------------------- */ default: assertpro(FALSE); /* see above assertpro() for comment as to why this is needed */ } } /* ------------------------------------------------------------------ * Indicate whether an xfer_table change is pending. * Only works for changes made using routines in this module * (need to rework others, too). * * Might not be needed. * ------------------------------------------------------------------ */ boolean_t xfer_table_changed(void) { return (0 != num_deferred); } fis-gtm-V6.0-003/sr_port/deferred_events.h0000644000032200000250000000736012201176155017355 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* Uncomment below to enable tracing of deferred events */ /* #define DEBUG_DEFERRED_EVENT */ #ifdef DEBUG_DEFERRED_EVENT # define DBGDFRDEVNT(x) DBGFPF(x) #else # define DBGDFRDEVNT(x) #endif /* -------------------------------------------- * Async. events that can be deferred * -------------------------------------------- */ enum deferred_event { no_event = 0, outofband_event, network_error_event, zstp_or_zbrk_event, tt_write_error_event, DEFERRED_EVENTS }; /* ============================================================================= * EXPORTED VARIABLES * ============================================================================= */ /* ------------------------------------------------------- * - Used by the substitute xfer_table functions. * - Keeping_count => should change name to num_logged. * - Should be made static and wrapped with a function for weaker * intermodule coupling; however, it's accessed from assembly * language => not worth the trouble to add a layer. * ------------------------------------------------------- */ #if defined(UNIX) GBLREF volatile int4 num_deferred; #elif defined(VMS) GBLREF volatile short num_deferred; #else # error "Unsupported Platform" #endif /* ------------------------------------------------------------------ * Sets up transfer table changes needed for: * - Synchronous handling of asynchronous events. * - Single-stepping and breakpoints * Return value indicates success (e.g. if first to attempt). * * Notes: * - mdb_condition_handler is different. * Should change it to use this function (CAREFULLY!). * - So are routines related to zbreak and zstep. * ==> Need to update them too (also carefully -- needs * a thorough redesign or rethinking). * ------------------------------------------------------------------ */ boolean_t xfer_set_handlers(int4, void (*callback)(int4), int4 param); /* ------------------------------------------------------------------ * Reset transfer table to normal settings. * * Puts back everything that could/would have been changed, assuming * that no xfer_table changes have been added since it was written. * * Return value indicates success/failure. Succeeds only if event * type of reset is the same as event type of set. * ------------------------------------------------------------------ */ boolean_t xfer_reset_handlers(int4 event_type); /* ------------------------------------------------------------------ * This version resets the handlers only if they were set by the * same event type. * ------------------------------------------------------------------ */ boolean_t xfer_reset_if_setter(int4 event_type); /* ------------------------------------------------------- * Prototypes for transfer table callback functions. * Only called by routine that manages xfer_table. * * Should use these (with enums?) to ensure type checking * is done. * ------------------------------------------------------- */ void ctrap_set(int4); void ctrlc_set(int4); void ctrly_set(int4); void tt_write_error_set(int4); /* ------------------------------------------------------------------ * Perform action corresponding to the first async event that * was logged. * ------------------------------------------------------------------ */ void async_action(bool); boolean_t xfer_table_changed(void); fis-gtm-V6.0-003/sr_port/desired_db_format_set.c0000644000032200000250000001466312201176155020517 0ustar librarygtc/**************************************************************** * * * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_time.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gdscc.h" #include "gdskill.h" #include "jnl.h" #include "iosp.h" /* for SS_NORMAL */ #include "util.h" /* Prototypes */ #include "gtmmsg.h" /* for gtm_putmsg prototype */ #include "desired_db_format_set.h" #include "send_msg.h" /* for send_msg */ #include "wcs_phase2_commit_wait.h" #define WCS_PHASE2_COMMIT_WAIT_LIT "wcb_phase2_commit_wait" LITREF char *gtm_dbversion_table[]; GBLREF inctn_opcode_t inctn_opcode; GBLREF jnl_gbls_t jgbl; GBLREF uint4 process_id; GBLREF inctn_detail_t inctn_detail; /* holds detail to fill in to inctn jnl record */ error_def(ERR_COMMITWAITSTUCK); error_def(ERR_CRYPTNOV4); error_def(ERR_DBDSRDFMTCHNG); error_def(ERR_MMNODYNDWNGRD); error_def(ERR_MUDWNGRDTN); error_def(ERR_MUNOACTION); error_def(ERR_SNAPSHOTNOV4); error_def(ERR_WCBLOCKED); /* input parameter "command_name" is a string that is either "MUPIP REORG UPGRADE/DOWNGRADE" or "MUPIP SET VERSION" */ int4 desired_db_format_set(gd_region *reg, enum db_ver new_db_format, char *command_name) { boolean_t was_crit; char *db_fmt_str; char *wcblocked_ptr; int4 status; uint4 jnl_status; inctn_opcode_t save_inctn_opcode; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; trans_num curr_tn; jnl_private_control *jpc; jnl_buffer_ptr_t jbp; assert(reg->open); csa = &FILE_INFO(reg)->s_addrs; csd = csa->hdr; GTMCRYPT_ONLY( /* We don't allow databases to be encrypted if the version is V4 */ if (csd->is_encrypted && (GDSV4 == new_db_format)) { gtm_putmsg(VARLSTCNT(4) ERR_CRYPTNOV4, 2, DB_LEN_STR(reg)); return ERR_CRYPTNOV4; } ) GTM_SNAPSHOT_ONLY( /* We don't allow databases to be downgraded when snapshots are in progress */ if (SNAPSHOTS_IN_PROG(csa->nl) && (GDSV4 == new_db_format)) { gtm_putmsg(VARLSTCNT(5) ERR_SNAPSHOTNOV4, 3, csa->nl->num_snapshots_in_effect, DB_LEN_STR(reg)); return ERR_SNAPSHOTNOV4; } ) was_crit = csa->now_crit; if (FALSE == was_crit) grab_crit(reg); /* if MM and desired_db_format is not V5, gvcst_init would have issued MMNODYNDWNGRD error. assert that. */ assert(dba_bg == csd->acc_meth || (dba_mm == csd->acc_meth) && (GDSV6 == csd->desired_db_format)); if (csd->desired_db_format == new_db_format) { /* no change in db_format. fix max_tn_warn if necessary and return right away. */ status = ERR_MUNOACTION; assert(csd->trans_hist.curr_tn <= csd->max_tn); if ((GDSV4 == new_db_format) && (MAX_TN_V4 < csd->max_tn)) { /* reset max_tn to MAX_TN_V4 only if V4 format and the new value will still be greater than curr_tn */ if (MAX_TN_V4 >= csd->trans_hist.curr_tn) { csd->max_tn = MAX_TN_V4; /* since max_tn changed above, max_tn_warn might also need to correspondingly change */ SET_TN_WARN(csd, csd->max_tn_warn); } else GTMASSERT; /* out-of-design state where curr_tn > MAX_TN_V4 in GDSV4 */ } if (FALSE == was_crit) rel_crit(reg); return status; } if (dba_mm == csd->acc_meth) { status = ERR_MMNODYNDWNGRD; gtm_putmsg(VARLSTCNT(4) status, 2, REG_LEN_STR(reg)); if (FALSE == was_crit) rel_crit(reg); return status; } /* check if curr_tn is too high to downgrade */ curr_tn = csd->trans_hist.curr_tn; if ((GDSV4 == new_db_format) && (MAX_TN_V4 <= curr_tn)) { status = ERR_MUDWNGRDTN; gtm_putmsg(VARLSTCNT(5) status, 3, &curr_tn, DB_LEN_STR(reg)); if (FALSE == was_crit) rel_crit(reg); return status; } /* Wait for concurrent phase2 commits to complete before switching the desired db format */ if (csa->nl->wcs_phase2_commit_pidcnt && !wcs_phase2_commit_wait(csa, NULL)) { /* Set wc_blocked so next process to get crit will trigger cache-recovery */ SET_TRACEABLE_VAR(csa->nl->wc_blocked, TRUE); wcblocked_ptr = WCS_PHASE2_COMMIT_WAIT_LIT; send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_STR(wcblocked_ptr), process_id, &csd->trans_hist.curr_tn, DB_LEN_STR(reg)); status = ERR_COMMITWAITSTUCK; gtm_putmsg(VARLSTCNT(7) status, 5, process_id, 1, csa->nl->wcs_phase2_commit_pidcnt, DB_LEN_STR(reg)); if (FALSE == was_crit) rel_crit(reg); return status; } if (JNL_ENABLED(csd)) { SET_GBL_JREC_TIME; /* needed for jnl_ensure_open, jnl_put_jrt_pini and jnl_write_aimg_rec */ jpc = csa->jnl; jbp = jpc->jnl_buff; /* Before writing to jnlfile, adjust jgbl.gbl_jrec_time if needed to maintain time order of jnl records. * This needs to be done BEFORE the jnl_ensure_open as that could write journal records * (if it decides to switch to a new journal file) */ ADJUST_GBL_JREC_TIME(jgbl, jbp); jnl_status = jnl_ensure_open(); if (0 == jnl_status) { save_inctn_opcode = inctn_opcode; inctn_opcode = inctn_db_format_change; inctn_detail.blks2upgrd_struct.blks_to_upgrd_delta = csd->blks_to_upgrd; if (0 == jpc->pini_addr) jnl_put_jrt_pini(csa); jnl_write_inctn_rec(csa); inctn_opcode = save_inctn_opcode; } else gtm_putmsg(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg)); } csd->desired_db_format = new_db_format; csd->fully_upgraded = FALSE; csd->desired_db_format_tn = curr_tn; switch(new_db_format) { case GDSV4: csd->max_tn = MAX_TN_V4; break; case GDSV6: csd->max_tn = MAX_TN_V6; break; default: GTMASSERT; } SET_TN_WARN(csd, csd->max_tn_warn); /* if max_tn changed above, max_tn_warn also needs a corresponding change */ assert(curr_tn < csd->max_tn); /* ensure CHECK_TN macro below will not issue TNTOOLARGE rts_error */ CHECK_TN(csa, csd, curr_tn); /* can issue rts_error TNTOOLARGE */ /* increment csd->trans_hist.curr_tn */ assert(csd->trans_hist.early_tn == csd->trans_hist.curr_tn); csd->trans_hist.early_tn = csd->trans_hist.curr_tn + 1; INCREMENT_CURR_TN(csd); if (FALSE == was_crit) rel_crit(reg); status = SS_NORMAL; send_msg(VARLSTCNT(11) ERR_DBDSRDFMTCHNG, 9, DB_LEN_STR(reg), LEN_AND_STR(gtm_dbversion_table[new_db_format]), LEN_AND_STR(command_name), process_id, process_id, &curr_tn); return status; } fis-gtm-V6.0-003/sr_port/desired_db_format_set.h0000644000032200000250000000120212201176155020505 0ustar librarygtc/**************************************************************** * * * Copyright 2005 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef DESIRED_DB_FORMAT_SET_DEFINED /* prototypes */ int4 desired_db_format_set(gd_region *reg, enum db_ver new_db_format, char *command_name); #define DESIRED_DB_FORMAT_SET_DEFINED #endif fis-gtm-V6.0-003/sr_port/deviceparameters.c0000644000032200000250000003374612201176155017536 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "nametabtyp.h" #include "io_params.h" #include "zshow_params.h" #include "advancewindow.h" #include "namelook.h" #include "cvtparm.h" #include "deviceparameters.h" error_def(ERR_DEVPARINAP); error_def(ERR_DEVPARUNK); error_def(ERR_DEVPARVALREQ); error_def(ERR_RPARENMISSING); LITREF unsigned char io_params_size[]; LITREF dev_ctl_struct dev_param_control[]; LITDEF nametabent dev_param_names[] = { {2,"AF*"} ,{2,"AL*"} ,{4,"ALLO"} ,{2,"AP*"} ,{2,"AT*"} ,{4,"BIGR*"} ,{2,"BL*"} ,{4,"BLOC"} ,{4,"BU*"} ,{2,"CA"}, {4,"CANT*"} ,{4,"CANO*"} ,{2,"CE*"} ,{3,"CHA*"} ,{3,"CHS*"} ,{3,"CLE*"} ,{3,"CLI"} ,{4,"COMM*"}, {7,"COMMAND"} ,{4,"CONN*"} ,{4,"CONT*"} ,{4,"CONV*"} ,{3,"COP*"} ,{2,"CP*"} ,{2,"CT*"} ,{4,"CTRA"} ,{4,"DELE*"} ,{4,"DELE"} ,{4,"DELI*"} ,{4,"DEST*" } ,{7,"DESTROY"} ,{3,"DET*"} ,{3,"DOU*"} ,{3,"DOW*"} ,{2,"EB*"} ,{4,"EBCD"} ,{2,"EC*"} ,{2,"ED*"} ,{4,"EDIT"} ,{4,"EMPT*"} ,{7,"EMPTERM"} ,{6,"ERASEL*"} ,{6,"ERASET*"} ,{2,"ES*"} ,{3,"EXC*"} ,{4,"EXCE"} ,{3,"EXT*"} ,{4,"EXTE"} ,{4,"EXTG*"} ,{1,"F"} ,{3,"FIE*"} ,{5,"FIELD"} ,{3,"FIF*"} ,{4,"FIFO"} ,{3,"FIL*"} ,{3,"FIR*"} ,{3,"FIX*"} ,{5,"FIXED"} ,{3,"FLA*"} ,{3,"FLU*"} ,{2,"FO"} ,{3,"FOR*"} ,{3,"FOL*"} ,{6,"FOLLOW"} ,{1,"G"} ,{2,"GR*"} ,{2,"HE*"} ,{3,"HOL*"} ,{3,"HOS*"} ,{4,"HOST"} ,{6,"ICHSET"} ,{4,"INDE*"} ,{11,"INDEPENDENT"} ,{2,"IN*"} ,{4,"INSE"} ,{3,"IOE*"} ,{3,"LAB*"} ,{3,"LAS*"} ,{2,"LE*"} ,{4,"LENG"} ,{2,"LI*"} ,{4,"LOGF*"} ,{4,"LOGQ*"} ,{3,"LOW*"} ,{1,"M"} ,{8,"MOREREAD*"} ,{3,"MOU*"} ,{2,"NA*"} ,{3,"NEW*"} ,{3,"NEX*"} ,{6,"NOBIGR*"} ,{4,"NOBU*"} ,{4,"NOCA*"} ,{4,"NOCE*"} ,{6,"NOCENE"} ,{6,"NOCONV*"} ,{6,"NODELI*"} ,{6,"NODEST*"} ,{9,"NODESTROY"} ,{5,"NODOU*"} ,{4,"NOEB*"} ,{4,"NOEC*"} ,{6,"NOECHO"} ,{4,"NOED*"} ,{6,"NOEDIT"} ,{6,"NOEMPT*"} ,{9,"NOEMPTERM"} ,{4,"NOES*"} ,{6,"NOESCA"} ,{5,"NOEXT*"} ,{5,"NOFIL*"} ,{5,"NOFIX*"} ,{5,"NOFLA*"} ,{5,"NOFOL*"} ,{8,"NOFOLLOW"} ,{4,"NOHE*"} ,{5,"NOHOL*"} ,{5,"NOHOS*"} ,{6,"NOHOST"} ,{4,"NOIN*"} ,{6,"NOINSE"} ,{5,"NOLAB*"} ,{5,"NOLOW*"} ,{6,"NONOTI*"} ,{5,"NOPAG*"} ,{6,"NOPASS*"} ,{6,"NOPAST*"} ,{6,"NOPRIN*"} ,{4,"NORC*"} ,{6,"NOREAD"} ,{7,"NOREADO*"} ,{7,"NOREADS*"} ,{5,"NORES*"} ,{5,"NORET*"} ,{4,"NOSE*"} ,{4,"NOST*"} ,{4,"NOTE"} ,{5,"NOTER*"} ,{4,"NOTI*"} ,{5,"NOTRA*"} ,{5,"NOTRU*"} ,{4,"NOTT*"} ,{6,"NOTTSY"} ,{4,"NOTY*"} ,{6,"NOTYPE"} ,{4,"NOUR*"} ,{4,"NOWA*"} ,{4,"NOWC*"} ,{4,"NOWR"} ,{5,"NOWRA*"} ,{6,"NOWRAP"} ,{7,"NOWRITE*"} ,{2,"NU*"} ,{1,"O"} ,{6,"OCHSET"} ,{2,"OP*"} ,{2,"OV*"} ,{2,"OW*"} ,{2,"P1"} ,{2,"P2"} ,{2,"P3"} ,{2,"P4"} ,{2,"P5"} ,{2,"P6"} ,{2,"P7"} ,{2,"P8"} ,{3,"PAD"} ,{3,"PAG*"} ,{4,"PARS*"} ,{5,"PARSE"} ,{4,"PASS*"} ,{4,"PAST*"} ,{4,"PRIO*"} ,{4,"PRIN*"} ,{3,"PRM*"} ,{6,"PRMMBX"} ,{3,"PRO*"} ,{3,"QUE*"} ,{2,"RC*"} ,{4,"RCHK"} ,{4,"READ"} ,{5,"READO*"} ,{5,"READS*"} ,{3,"REC*"} ,{3,"REM*"} ,{3,"REN*"} ,{3,"RES*"} ,{3,"RET*"} ,{3,"REW*"} ,{3,"RFA"} ,{3,"RFM"} ,{1,"S"} ,{3,"SEQ*"} ,{3,"SET*"} ,{2,"SH"} ,{3,"SHA*"} ,{4,"SHAR"} ,{4,"SHEL*"} ,{5,"SHELL"} ,{2,"SK*"} ,{2,"SO*"} ,{3,"SPA*"} ,{3,"SPO*"} ,{2,"ST"} ,{3,"STR*"} ,{4,"STDE*"} ,{6,"STDERR"} ,{2,"SU*"} ,{2,"SY*"} ,{2,"TE*"} ,{4,"TERM"} ,{2,"TM*"} ,{3,"TRA*"} ,{3,"TRU*"} ,{2,"TT*"} ,{4,"TTSY"} ,{2,"TY*"} ,{4,"TYPE"} ,{2,"UI*"} ,{3,"UIC"} ,{2,"UN*"} ,{2,"UP*"} ,{2,"UR*"} ,{2,"US*"} ,{2,"VA*"} ,{1,"W"} ,{2,"WA*"} ,{4,"WAIT"} ,{2,"WC*"} ,{4,"WCHK"} ,{2,"WI*"} ,{5,"WIDTH"} ,{2,"WO*"} ,{2,"WR"} ,{3,"WRA*"} ,{5,"WRITE"} ,{7,"WRITELB"} ,{7,"WRITEOF"} ,{7,"WRITEON*"} ,{7,"WRITETM"} ,{1,"X"} ,{1,"Y"} ,{2,"ZB*"} ,{2,"ZD*"} ,{3,"ZEX*"} ,{4,"ZFIL*"} ,{3,"ZFF"} ,{2,"ZI*"} ,{4,"ZLEN*"} ,{4,"ZLIS*"} ,{8,"ZNODELAY"} /* ZNO* have to be spelled out fully */ ,{9,"ZNOFILTER"} ,{5,"ZNOFF"} ,{7,"ZNOWRAP"} ,{4,"ZWID*"} ,{4,"ZWRA*"} }; /* Offset of letter in dev_param_names */ /* Following array has reached the maximum value limit(255) for its entry. Hence adddition of the next deviceparameter needs * to change this array to short or int. This will lead to change the interface to namelook() and the type of the first argument * passed to it. Once that is implemented, remove this comment. */ LITDEF unsigned char dev_param_index[27] = { /* A B C D E F G H I J K L M N */ 0, 5, 9, 26, 34, 49, 64, 66, 70, 76, 76, 76, 84, 87, /* O P Q R S T U V W X Y Z end */ 153, 158, 177, 178, 191, 209, 218, 224, 225, 240, 241, 242, 255 }; /* Offset of string within letter in dev_param_names */ /* maintained in conjunction with zshow_params.h = offset in letter, letter */ LITDEF zshow_index zshow_param_index[] = { /* ALLO BLOC COMMAND CONV CTRA DELE DEST EBCD EDIT EMPTERM EXCE EXTE FIELD */ {2,0}, {2,1}, {9,2}, {12,2}, {16,2}, {1,3}, {3,3}, {1,4}, {4,4}, {6,4}, {11,4}, {13,4}, {2,5}, /* FIL FIXED FOLLOW */ {5,5}, {8,5}, {14,5}, /* HOST ICHSET INDEPENDENT INSE LAB */ {3,7}, {0,8}, {2,8}, {4,8}, {1,11}, /* LENG NOCENE NODEST NOECHO NOEDIT NOEMPTERM NOESCA NOFOLLOW NOHOST NOINSE */ {3,11}, {7,13}, {10,13}, {15,13}, {17,13}, {19,13}, {21,13}, {27,13}, {31,13}, {33,13}, /* NOPAST NOREADS NOTTSY NOTYPE NOWRAP OCHSET PAD PARSE PAST PRMMBX RCHK */ {39,13}, {44,13}, {55,13}, {57,13}, {63,13}, {1,14}, {8,15}, {11,15}, {13,15}, {17,15}, {1,17}, /* READ READS REC SHAR SHELL STDERR TERM TTSY TYPE UIC WAIT WCHK */ {2,17}, {4,17}, {5,17}, {5,18}, {7,18}, {15,18}, {1,19}, {6,19}, {8,19}, {1,20}, {2,22}, {4,22}, /* WIDTH WRITE */ {6,22}, {10,22} }; int deviceparameters(oprtype *c, char who_calls) { oprtype x; oprtype cat_list[n_iops]; int cat_cnt; mval tmpmval; triple *ref, *parm; int n; int status; char parstr[MAXDEVPARLEN]; char *parptr; boolean_t is_parm_list; boolean_t parse_warn; static readonly unsigned char dev_param_data[] = { iop_after ,iop_allocation ,iop_allocation ,iop_append ,iop_attach ,iop_bigrecord ,iop_blocksize ,iop_blocksize ,iop_burst ,iop_canctlo, iop_canctlo ,iop_canonical ,iop_cenable ,iop_characteristic ,iop_chset ,iop_clearscreen ,iop_cli ,iop_command ,iop_command ,iop_connect ,iop_contiguous ,iop_convert ,iop_copies ,iop_cpulimit ,iop_ctrap ,iop_ctrap ,iop_delete ,iop_delete ,iop_delimiter ,iop_destroy ,iop_destroy ,iop_detach ,iop_doublespace ,iop_downscroll ,iop_ebcdic ,iop_ebcdic ,iop_echo ,iop_editing ,iop_editing ,iop_empterm ,iop_empterm ,iop_eraseline ,iop_erasetape ,iop_escape ,iop_exception ,iop_exception ,iop_extension ,iop_extension ,iop_extgap ,iop_field ,iop_field ,iop_field ,iop_fifo, iop_fifo ,iop_filter ,iop_firstpage ,iop_fixed ,iop_fixed ,iop_flag ,iop_flush ,iop_form ,iop_form ,iop_follow ,iop_follow ,iop_g_protection, iop_g_protection ,iop_header ,iop_hold ,iop_hostsync, iop_hostsync ,iop_ipchset ,iop_independent ,iop_independent ,iop_insert ,iop_insert ,iop_ioerror ,iop_label ,iop_lastpage ,iop_length ,iop_length ,iop_listen ,iop_logfile ,iop_logqueue ,iop_lowercase ,iop_m ,iop_morereadtime ,iop_mount ,iop_name ,iop_newversion ,iop_next ,iop_nobigrecord ,iop_noburst ,iop_nocanonical ,iop_nocenable ,iop_nocenable ,iop_noconvert ,iop_nodelimiter ,iop_nodestroy ,iop_nodestroy ,iop_nodoublespace ,iop_noebcdic ,iop_noecho ,iop_noecho ,iop_noediting ,iop_noediting ,iop_noempterm ,iop_noempterm ,iop_noescape ,iop_noescape ,iop_inhextgap ,iop_nofilter ,iop_nofixed ,iop_noflag ,iop_nofollow ,iop_nofollow ,iop_noheader ,iop_nohold ,iop_nohostsync ,iop_nohostsync ,iop_noinsert ,iop_noinsert ,iop_nolabel ,iop_nolowercase ,iop_nonotify ,iop_page ,iop_nopassall ,iop_nopasthru ,iop_noprint ,iop_nordcheckdata ,iop_noreadonly ,iop_noreadonly ,iop_noreadsync ,iop_norestart ,iop_inhretry ,iop_nosequential ,iop_nostream ,iop_note ,iop_noterminator ,iop_notify ,iop_notrailer ,iop_notruncate ,iop_nottsync ,iop_nottsync ,iop_notypeahead ,iop_notypeahead ,iop_nourgent ,iop_nowait ,iop_nowtcheckdata ,iop_nowrap ,iop_nowrap ,iop_nowrap ,iop_nowriteonly ,iop_nl ,iop_o_protection ,iop_opchset ,iop_operator ,iop_noinsert ,iop_o_protection ,iop_p1 ,iop_p2 ,iop_p3 ,iop_p4 ,iop_p5 ,iop_p6 ,iop_p7 ,iop_p8 ,iop_pad ,iop_page ,iop_parse ,iop_parse ,iop_passall ,iop_pasthru ,iop_priority ,iop_print ,iop_prmmbx ,iop_prmmbx ,iop_o_protection ,iop_queue ,iop_rdcheckdata ,iop_rdcheckdata ,iop_readonly ,iop_readonly ,iop_readsync ,iop_recordsize ,iop_remote ,iop_rename ,iop_restart ,iop_retry ,iop_rewind ,iop_rfa ,iop_rfm ,iop_s_protection ,iop_sequential ,iop_setup ,iop_shared ,iop_shared, iop_shared ,iop_shell ,iop_shell ,iop_skipfile ,iop_socket ,iop_space ,iop_spool ,iop_stream, iop_stream ,iop_stderr, iop_stderr ,iop_submit ,iop_s_protection ,iop_terminator, iop_terminator ,iop_tmpmbx ,iop_trailer ,iop_truncate ,iop_ttsync ,iop_ttsync ,iop_typeahead ,iop_typeahead ,iop_uic ,iop_uic ,iop_unload ,iop_upscroll ,iop_urgent ,iop_user ,iop_nofixed ,iop_w_protection ,iop_wait ,iop_wait ,iop_wtcheckdata ,iop_wtcheckdata ,iop_width ,iop_width ,iop_w_protection ,iop_wrap ,iop_wrap ,iop_writeonly ,iop_writelb ,iop_writeof ,iop_writeonly ,iop_writetm ,iop_x ,iop_y ,iop_zbfsize ,iop_zdelay ,iop_exception /* for ZEXCEPTION; ZEXC* is a synonym for EXC* */ ,iop_filter /* for ZFILTER; ZFIL* is a synonym for FIL* */ ,iop_zff ,iop_zibfsize ,iop_length /* for ZLENGTH; ZLEN* is a synonym for LE* and LENG */ ,iop_zlisten ,iop_znodelay ,iop_nofilter /* for ZNOFILTER; ZNOFILTER is a synonym for NOFIL* */ ,iop_znoff ,iop_nowrap /* for ZNOWRAP; ZNOWRAP is a synonym for NOWR, NOWRA*, NOWRAP */ ,iop_width /* for ZWIDTH; ZWID* is a synonym for WI*, WIDTH */ ,iop_wrap /* for ZWRAP; ZWRA* is a synonym for WR, and WRA* */ } ; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; /* The value of dev_param_index[26] should be 256 but is 255 since that is all that can fit in a unsigned char. That is why * following asserts has (dev_param_index[26] + 1). Once the type of dev_param_index is changed, the "+ 1" in following * assert should be removed. */ assert((SIZEOF(dev_param_names) / SIZEOF(nametabent) == dev_param_index[26] + 1)); assert((SIZEOF(dev_param_data) / SIZEOF(unsigned char)) == dev_param_index[26] + 1); assert(dev_param_index[26] == 255); assert(SIZEOF(dev_param_index[26] == SIZEOF(char))); is_parm_list = (TK_LPAREN == TREF(window_token)); if (is_parm_list) advancewindow(); cat_cnt = 0; parptr = parstr; parse_warn = FALSE; for (;;) { if ((TK_IDENT != TREF(window_token)) || (0 > (n = namelook(dev_param_index, dev_param_names, (TREF(window_ident)).addr, (TREF(window_ident)).len)))) { /* NOTE assignment above */ STX_ERROR_WARN(ERR_DEVPARUNK); /* sets "parse_warn" to TRUE */ break; } n = dev_param_data[n]; if (!(dev_param_control[n].valid_with & who_calls)) { STX_ERROR_WARN(ERR_DEVPARINAP); /* sets "parse_warn" to TRUE */ break; } advancewindow(); *parptr++ = n; if (io_params_size[n]) { if (TK_EQUAL != TREF(window_token)) { STX_ERROR_WARN(ERR_DEVPARVALREQ); /* sets "parse_warn" to TRUE */ break; } advancewindow(); if (EXPR_FAIL == expr(&x, MUMPS_EXPR)) return FALSE; assert(TRIP_REF == x.oprclass); if (OC_LIT == x.oprval.tref->opcode) { /* check to see if this string could overflow (5 is a int4 word plus a parameter code for safety) Must check before cvtparm, due to the fact that tmpmval could otherwise be garbage collected by a later putstr */ if (parptr - parstr + x.oprval.tref->operand[0].oprval.mlit->v.str.len + 5 > SIZEOF(parstr)) { cat_list[cat_cnt++] = put_str(parstr, INTCAST(parptr - parstr)); parptr = parstr; } assert(MLIT_REF == x.oprval.tref->operand[0].oprclass); status = cvtparm(n, &x.oprval.tref->operand[0].oprval.mlit->v, &tmpmval); if (status) { stx_error(status); return FALSE; } memcpy(parptr, tmpmval.str.addr, tmpmval.str.len); parptr += tmpmval.str.len; } else { if (parptr > parstr) { cat_list[cat_cnt++] = put_str(parstr, INTCAST(parptr - parstr)); parptr = parstr; } ref = newtriple(OC_CVTPARM); ref->operand[0] = put_ilit(n); ref->operand[1] = x; cat_list[cat_cnt++] = put_tref(ref); } } if (!is_parm_list) break; if (TK_COLON == TREF(window_token)) { advancewindow(); continue; } else if (TK_RPAREN == TREF(window_token)) { advancewindow(); break; } stx_error(ERR_RPARENMISSING); return FALSE; } if (parse_warn) { /* Parse the remaining arguments until the corresponding RIGHT-PAREN or SPACE or EOL is reached */ if (!parse_until_rparen_or_space()) return FALSE; if (TK_RPAREN == TREF(window_token)) advancewindow(); } *parptr++ = iop_eol; cat_list[cat_cnt++] = put_str(parstr,INTCAST(parptr - parstr)); if (cat_cnt <= 1) *c = cat_list[0]; else { ref = newtriple(OC_CAT); ref->operand[0] = put_ilit(cat_cnt + 1); *c = put_tref(ref); for (n = 0 ; n < cat_cnt ; n++) { parm = newtriple(OC_PARAMETER); ref->operand[1] = put_tref(parm); ref = parm; ref->operand[0] = cat_list[n]; } } return TRUE; } fis-gtm-V6.0-003/sr_port/deviceparameters.h0000644000032200000250000000116512201176155017531 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef DEVICEPARAMETERS_INCLUDED #define DEVICEPARAMETERS_INCLUDED int deviceparameters(oprtype *c, char who_calls); /***type int added***/ #endif /* DEVICEPARAMETERS_INCLUDED */ fis-gtm-V6.0-003/sr_port/dfa_calc.c0000644000032200000250000004144012201176155015715 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "copy.h" #include "patcode.h" #include "compiler.h" #include "gtm_string.h" /* the following macro checks that a 1 dimensional array reference is valid i.e. array[index] is within defined limits */ #define check_1dim_array_bound(array, index) assert((index) < (SIZEOF(array) / SIZEOF(array[0]))) /* the following macro checks that a 2 dimensional array reference is valid i.e. array[row][col] is within defined limits */ #define check_2dim_array_bound(array, row, col) \ { \ assert((row) < (SIZEOF(array) / SIZEOF(array[0]))); \ assert((col) < (SIZEOF(array[0]) / SIZEOF(array[0][0]))); \ } /* Note: in various places, dfa_calc() makes a reference to the array 'typemask'. dfa_calc() is executed at compile-time. * The content of the array typemask is static, but, at run-time, the pointer that is used to access the typemask array * (pattern_typemask) may change whenever a program executes the command View "PATCODE":tablename. * As a result, the pattern masks that the GT.M compiler uses may differ from the ones that are in operation at run-time. */ LITREF uint4 typemask[PATENTS]; static uint4 classmask[CHAR_CLASSES] = { PATM_N, PATM_P, PATM_L, PATM_U, PATM_C, PATM_B, PATM_D, PATM_F, PATM_G, PATM_H, PATM_I, PATM_J, PATM_K, PATM_M, PATM_O, PATM_Q, PATM_R, PATM_S, PATM_T, PATM_V, PATM_W, PATM_X, PATM_UTF8_ALPHABET, PATM_UTF8_NONBASIC }; /* This procedure is part of the MUMPS compiler. The function of this procedure is to build the data structures that * will be used to drive the DFA engine that can evaluate certain pattern matches. Note that this routine operates * at compile-time, and that all data structures built in this procedure are compiled at the end into a terse string * of values that will be passed to do_pattern (through patstr). do_pattern(), which operates at run-time will * interpret this string of values and do the actual DFA work (DFA = Discrete Finite Automaton). */ int dfa_calc(struct leaf *leaves, int leaf_num, struct e_table *expand, uint4 **fstchar_ptr, uint4 **outchar_ptr) { uint4 *locoutchar; uint4 pattern_mask; unsigned char *textstring; int offset[2 * (MAX_SYM + 1)]; int pos_offset[CHAR_CLASSES]; int fst[2][2], lst[2][2]; int4 charcls, maskcls, numexpand, count, clsnum, maxcls, clsposlis; int4 state_num, node_num, sym_num, expseq, seq; struct node nodes; /* EdM: comment for reviewers: * 'states' is currently defined as a boolean_t. * In the original version it was a bool (== char). * Since comparisons on this array are done using * memcmp, and the only values assigned to elements * in this array are TRUE and FALSE (1 and 0), * we might consider declaring states as a 'char' * array after all... */ boolean_t states[2 * MAX_SYM][CHAR_CLASSES]; boolean_t fpos[2 * MAX_SYM][CHAR_CLASSES]; int d_trans[2 * MAX_SYM][CHAR_CLASSES]; int pos_lis[2 * MAX_SYM][CHAR_CLASSES]; struct c_trns_tb c_trans; /* Note: in various places, this procedure makes a reference to the array 'typemask'. * This procedure is executed at compile-time. The contents of the array typemask is static, but, at * run-time, the pointer that is used to access the array pattern_typemask may change whenever a program * executes the command View "PATCODE":tablename. As a result, the pattern masks that the GT.M compiler * uses may differ from the ones that are in operation at run-time. */ locoutchar = *outchar_ptr; if (leaf_num > 1) { pattern_mask = PATM_DFA; state_num = 1; check_1dim_array_bound(leaves->nullable, leaf_num); leaves->nullable[leaf_num] = FALSE; leaves->letter[leaf_num][0] = DFABIT; leaves->letter[leaf_num][1] = -1; pos_offset[0] = 0; for (seq = 1; seq < CHAR_CLASSES; seq++) pos_offset[seq] = pos_offset[seq - 1] + expand->num_e[seq - 1]; memset(&nodes, 0, SIZEOF(nodes)); memset(&fpos[0][0], 0, SIZEOF(fpos)); memset(&states[0][0], 0, SIZEOF(states)); memset(&d_trans[0][0], 128, SIZEOF(d_trans)); memset(&pos_lis[0][0], 128, SIZEOF(pos_lis)); memset(&c_trans.c[0], 0, SIZEOF(c_trans.c)); memset(offset, 0, SIZEOF(offset)); memset(fst, 0, SIZEOF(fst)); memset(lst, 0, SIZEOF(lst)); charcls = 0; clsnum = 0; maxcls = 0; nodes.nullable[0] = leaves->nullable[0] & leaves->nullable[1]; states[state_num][charcls] = TRUE; for (maskcls = 0; leaves->letter[0][maskcls] >= 0; maskcls++) { check_1dim_array_bound(leaves->letter[0], maskcls); if (!(leaves->letter[0][maskcls] & DFABIT)) { check_2dim_array_bound(fpos, charcls, charcls + 1); fpos[charcls][charcls + 1] = TRUE; lst[FST][FST] = charcls; lst[FST][LST] = charcls; assert(leaves->letter[0][maskcls] >= 0 && leaves->letter[0][maskcls] < SIZEOF(typemask)); seq = patmaskseq(typemask[leaves->letter[0][maskcls]]); if (seq < 0) seq = 0; for (numexpand = 1; expand->meta_c[seq][numexpand] != leaves->letter[0][maskcls]; numexpand++) ; check_1dim_array_bound(pos_lis, (pos_offset[seq] + numexpand)); for (count = 0; pos_lis[pos_offset[seq] + numexpand][count] >= 0; count++) ; check_2dim_array_bound(pos_lis, (pos_offset[seq] + numexpand), count); pos_lis[pos_offset[seq] + numexpand][count] = charcls; charcls++; } else { seq = patmaskseq(leaves->letter[0][maskcls]); if (seq < 0) { seq = 0; expseq = 0; } else expseq = expand->num_e[seq]; for (numexpand = 0; numexpand < expseq; numexpand++) { states[state_num][charcls] = TRUE; fst[FST][LST] = charcls; lst[FST][LST] = charcls; for (count = 0; pos_lis[pos_offset[seq] + numexpand][count] >= 0; count++) ; check_2dim_array_bound(pos_lis, (pos_offset[seq] + numexpand), count); pos_lis[pos_offset[seq] + numexpand][count] = charcls; charcls++; } } } fst[LST][FST] = charcls; fst[LST][LST] = charcls; lst[LST][FST] = charcls; if(!leaves->nullable[1]) { nodes.last[0][charcls] = TRUE; maxcls = charcls; } for (maskcls = 0; leaves->letter[1][maskcls] >= 0; maskcls++) { check_1dim_array_bound(leaves->letter[1], maskcls); if (!(leaves->letter[1][maskcls] & DFABIT)) { check_2dim_array_bound(fpos, charcls, charcls + 1); fpos[charcls][charcls + 1] = TRUE; lst[LST][FST] = charcls; lst[LST][LST] = charcls; assert(leaves->letter[1][maskcls] >= 0 && leaves->letter[1][maskcls] < SIZEOF(typemask)); seq = patmaskseq(typemask[leaves->letter[1][maskcls]]); if (seq < 0) seq = 0; for (numexpand = 1; expand->meta_c[seq][numexpand] != leaves->letter[1][maskcls]; numexpand++) ; check_1dim_array_bound(pos_lis, (pos_offset[seq] + numexpand)); for (count = 0; pos_lis[pos_offset[seq] + numexpand][count] >= 0; count++) ; check_2dim_array_bound(pos_lis, (pos_offset[seq] + numexpand), count); pos_lis[pos_offset[seq] + numexpand][count] = charcls; charcls++; } else { seq = patmaskseq(leaves->letter[1][maskcls]); if (seq < 0) { seq = 0; expseq = 0; } else expseq = expand->num_e[seq]; for (numexpand = 0; numexpand < expseq; numexpand++) { nodes.last[0][charcls] = TRUE; fst[LST][LST] = charcls; lst[LST][LST] = charcls; check_1dim_array_bound(pos_lis, (pos_offset[seq] + numexpand)); for (count = 0; pos_lis[pos_offset[seq] + numexpand][count] >= 0; count++) ; check_2dim_array_bound(pos_lis, (pos_offset[seq] + numexpand), count); pos_lis[pos_offset[seq] + numexpand][count] = charcls; charcls++; } } } if (leaves->nullable[0]) { assert((2 * MAX_SYM) > lst[FST][LST]); assert(CHAR_CLASSES > fst[LST][LST]); for (numexpand = lst[FST][FST]; numexpand <= lst[FST][LST]; numexpand++) { for (count = fst[FST][FST]; count <= fst[FST][LST]; count++) { check_2dim_array_bound(fpos, numexpand, count); fpos[numexpand][count] = TRUE; } } for (numexpand = fst[LST][FST]; numexpand <= fst[LST][LST]; numexpand++) states[state_num][numexpand] = TRUE; } if (leaves->nullable[1]) { nodes.last[0][charcls - 1] = TRUE; for (numexpand = lst[LST][FST]; numexpand <= lst[LST][LST]; numexpand++) { for (count = fst[LST][FST]; count <= fst[LST][LST]; count++) { check_2dim_array_bound(fpos, numexpand, count); fpos[numexpand][count] = TRUE; } } for (numexpand = lst[FST][FST]; numexpand <= lst[FST][LST]; numexpand++) nodes.last[0][numexpand] = TRUE; maxcls = charcls; } for (numexpand = lst[FST][FST]; numexpand <= lst[FST][LST]; numexpand++) { for (count = fst[LST][FST]; count <= fst[LST][LST]; count++) { check_2dim_array_bound(fpos, numexpand, count); fpos[numexpand][count] = TRUE; } } if (!leaves->nullable[1]) clsnum = lst[LST][FST]; for (node_num = 1; node_num < leaf_num; node_num++) { nodes.nullable[node_num] = nodes.nullable[node_num - 1] & leaves->nullable[node_num + 1]; if (leaves->nullable[node_num + 1]) { for (maskcls = 0; maskcls < charcls; maskcls++) { check_2dim_array_bound(nodes.last, node_num, maskcls); nodes.last[node_num][maskcls] = nodes.last[node_num - 1][maskcls]; } } else { nodes.last[node_num][charcls] = TRUE; maxcls = charcls; } fst[LST][FST] = charcls; fst[LST][LST] = charcls; lst[LST][FST] = charcls; for (maskcls = 0; leaves->letter[node_num + 1][maskcls] >= 0; maskcls++) { check_1dim_array_bound(leaves->letter[node_num + 1], maskcls); if (!(leaves->letter[node_num + 1][maskcls] & DFABIT)) { check_2dim_array_bound(fpos, charcls, charcls + 1); fpos[charcls][charcls + 1] = TRUE; lst[LST][FST] = charcls; lst[LST][LST] = charcls; assert(leaves->letter[node_num + 1][maskcls] >= 0 && leaves->letter[node_num + 1][maskcls] < SIZEOF(typemask)); seq = patmaskseq(typemask[leaves->letter[node_num + 1][maskcls]]); if (seq < 0) seq = 0; for (numexpand = 1; expand->meta_c[seq][numexpand] != leaves->letter[node_num + 1][maskcls]; numexpand++) ; check_1dim_array_bound(pos_lis, (pos_offset[seq] + numexpand)); for (count = 0; pos_lis[pos_offset[seq] + numexpand][count] >= 0; count++) ; check_2dim_array_bound(pos_lis, (pos_offset[seq] + numexpand), count); pos_lis[pos_offset[seq] + numexpand][count] = charcls; charcls++; } else { seq = patmaskseq(leaves->letter[node_num + 1][maskcls]); if (seq < 0) { seq = 0; expseq = 0; } else expseq = expand->num_e[seq]; for (numexpand = 0; numexpand < expseq; numexpand++) { nodes.last[node_num][charcls] = TRUE; if (nodes.nullable[node_num - 1]) states[state_num][charcls] = TRUE; fst[LST][LST] = charcls; lst[LST][LST] = charcls; for (count = 0; pos_lis[pos_offset[seq] + numexpand][count] >= 0; count++) ; check_2dim_array_bound(pos_lis, (pos_offset[seq] + numexpand), count); pos_lis[pos_offset[seq] + numexpand][count] = charcls; charcls++; } } } if (nodes.nullable[node_num - 1]) { for (numexpand = fst[LST][FST]; numexpand <= fst[LST][LST]; numexpand++) { check_1dim_array_bound(states[state_num], numexpand); states[state_num][numexpand] = TRUE; } } if (leaves->nullable[node_num + 1]) { nodes.last[node_num][charcls - 1] = TRUE; for (numexpand = lst[LST][FST]; numexpand <= lst[LST][LST]; numexpand++) { for (count = fst[LST][FST]; count <= fst[LST][LST]; count++) { check_2dim_array_bound(fpos, numexpand, count); fpos[numexpand][count] = TRUE; } } maxcls = charcls; } for (numexpand = clsnum; numexpand < maxcls; numexpand++) for (count = fst[LST][FST]; count <= fst[LST][LST]; count++) if (nodes.last[node_num - 1][numexpand]) fpos[numexpand][count] = TRUE; if (!leaves->nullable[node_num + 1]) clsnum = lst[LST][FST]; } sym_num = charcls; state_num++; check_1dim_array_bound(offset, state_num + 1); for (seq = 1; seq < state_num; seq++) { charcls = 0; offset[seq + 1]++; offset[seq + 1] += offset[seq]; for (maskcls = 0; maskcls < CHAR_CLASSES; maskcls++) { if (expand->num_e[maskcls] > 0) { for (numexpand = 0; numexpand < expand->num_e[maskcls]; numexpand++) { for (maxcls = 0; pos_lis[charcls + numexpand][maxcls] >= 0; maxcls++) { clsposlis = pos_lis[charcls + numexpand][maxcls]; if (states[seq][clsposlis]) { for (clsnum = 0; clsnum <= sym_num; clsnum++) { check_1dim_array_bound(states[state_num], clsnum); states[state_num][clsnum] |= fpos[clsposlis][clsnum]; } } } check_1dim_array_bound(states, state_num); for (count = 0; memcmp(states[count], states[state_num], (sym_num + 1) * SIZEOF(boolean_t)) && (count < state_num); count++) ; if (count > 0) { if (0 == numexpand) { d_trans[seq][charcls] = count; for (clsnum = 0; (clsnum < c_trans.c[seq]) && (c_trans.trns[seq][clsnum] != count); clsnum++) ; check_1dim_array_bound(c_trans.p_msk[seq], clsnum); if (clsnum == c_trans.c[seq]) { c_trans.p_msk[seq][clsnum] = classmask[maskcls]; check_1dim_array_bound(c_trans.trns[seq], clsnum); c_trans.trns[seq][clsnum] = count; offset[seq + 1] += 2; c_trans.c[seq]++; } else c_trans.p_msk[seq][clsnum] |= classmask[maskcls]; } else if (d_trans[seq][charcls] != count) { d_trans[seq][charcls + numexpand] = count; offset[seq + 1] += 3; } if (count == state_num) state_num++; else memset(states[state_num], 0, (sym_num + 1) * SIZEOF(states[0][0])); } } charcls += expand->num_e[maskcls]; } } } *outchar_ptr += offset[state_num] + 2; if ((*outchar_ptr - *fstchar_ptr > MAX_DFA_SPACE) || ((offset[state_num] + 1) > (MAX_PATTERN_LENGTH / 2))) return -1; *locoutchar++ = PATM_DFA; *locoutchar++ = offset[state_num]; for (seq = 1; seq < state_num; seq++) { charcls = 0; for (numexpand = 0; numexpand < CHAR_CLASSES; numexpand++) { if (expand->num_e[numexpand] > 1) { for (count = 1; count < expand->num_e[numexpand]; count++) { check_2dim_array_bound(d_trans, seq, charcls + count); if (d_trans[seq][charcls + count] >= 0) { *locoutchar++ = PATM_STRLIT; *locoutchar++ = expand->meta_c[numexpand][count]; *locoutchar++ = offset[d_trans[seq][charcls + count]]; } } } charcls += expand->num_e[numexpand]; } for (numexpand = 0; numexpand < c_trans.c[seq]; numexpand++) { check_2dim_array_bound(c_trans.p_msk, seq, numexpand); *locoutchar++ = c_trans.p_msk[seq][numexpand]; check_2dim_array_bound(c_trans.trns, seq, numexpand); check_1dim_array_bound(offset, c_trans.trns[seq][numexpand]); *locoutchar++ = offset[c_trans.trns[seq][numexpand]]; } *locoutchar++ = (states[seq][sym_num]) ? PATM_ACS : PATM_DFA; } assert(MAX_DFA_SPACE >= (locoutchar - *fstchar_ptr)); return 1; } else { pattern_mask = 0; *outchar_ptr += 1; maskcls = 1; if (!(leaves->letter[0][0] & DFABIT)) { pattern_mask = PATM_STRLIT; for (maskcls = 0; leaves->letter[0][maskcls] >= 0; maskcls++) ; check_1dim_array_bound(leaves->letter[0], maskcls); *outchar_ptr += PAT_STRLIT_PADDING + ((maskcls + SIZEOF(uint4) - 1) / SIZEOF(uint4)); } else { for (numexpand = 0; leaves->letter[0][numexpand] >= 0; numexpand++) pattern_mask |= leaves->letter[0][numexpand]; check_1dim_array_bound(leaves->letter[0], numexpand); } if (*outchar_ptr - *fstchar_ptr > MAX_PATTERN_LENGTH) return -1; *locoutchar++ = pattern_mask; if (PATM_STRLIT & pattern_mask) { *locoutchar++ = maskcls; /* bytelen */ *locoutchar++ = maskcls; /* charlen */ *locoutchar++ = 0; /* both NONASCII and BADCHAR flags are absent since this is indeed a valid ASCII string or else we would not have come to dfa_calc (and hence there are no bad chars) */ assert(3 == PAT_STRLIT_PADDING); textstring = (unsigned char *)locoutchar; /* change pointer type */ for (numexpand = 0; numexpand < maskcls; numexpand++) *textstring++ = leaves->letter[0][numexpand]; } return maskcls; } } fis-gtm-V6.0-003/sr_port/dh.mpt0000644000032200000250000000176112201176155015154 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1987, 2003 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %DH ;GT.M %DH utility - decimal to hexadecimal conversion program ;invoke with %DH in decimal and %DL digits to return %DH in hexadecimal ;invoke at INT to execute interactively ;invoke at FUNC as an extrinsic function ;if you make heavy use of this routine, consider $ZCALL ; s %DH=$$FUNC(%DH,$G(%DL)) q INT n %DL r !,"Decimal: ",%DH r !,"Digits: ",%DL s %DH=$$FUNC(%DH,%DL) q FUNC(d,l) s:'$l($g(l)) l=8 q:d=0 $e("00000000",1,l) n h s h="" s:d<0 d=$$FUNC^%EXP(16,l)+d f q:'d s h=$e("0123456789ABCDEF",d#16+1)_h,d=d\16 q $e("00000000",1,l-$l(h))_h fis-gtm-V6.0-003/sr_port/dm_read.h0000644000032200000250000000104712201176155015600 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef DM_READ_INCLUDED #define DM_READ_INCLUDED void dm_read(mval *v); #endif /* DM_READ_INCLUDED */ fis-gtm-V6.0-003/sr_port/dm_setup.c0000644000032200000250000000155612201176176016030 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "stack_frame.h" #include "dm_setup.h" #include "io.h" GBLREF io_desc *gtm_err_dev; GBLREF stack_frame *frame_pointer; void dm_setup(void) { #ifdef UNIX /* zero the error device just to be safe */ assert(NULL == gtm_err_dev); gtm_err_dev = NULL; #endif new_stack_frame(frame_pointer->rvector, GTM_CONTEXT(call_dm), CODE_ADDRESS(call_dm)); frame_pointer->type = SFT_DM; } fis-gtm-V6.0-003/sr_port/dm_setup.h0000644000032200000250000000105312201176155016022 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2003 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __DM_SETUP_H_ #define __DM_SETUP_H_ #define GTM_DMOD "GTM$DMOD" void dm_setup(void); #endif fis-gtm-V6.0-003/sr_port/do.mpt0000644000032200000250000000172112201176155015157 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1987,2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %DO ;GT.M %DO utility - decimal to octal conversion program ;invoke with %DO in decimal and %DL digits to return %DO in octal ;invoke at INT to execute interactively ;invoke at FUNC as an extrinsic function ;if you make heavy use of this routine, consider $ZCALL ; s %DO=$$FUNC(%DO,$g(%DL)) q INT n %DL r !,"Decimal: ",%DO r !,"Digits: ",%DL s %DO=$$FUNC(%DO,%DL) q FUNC(d,l) s:'$l($g(l)) l=12 q:d=0 $e("000000000000",1,l) n o s o="" s:d<0 d=$$FUNC^%EXP(8,l)+d f q:'d s o=d#8_o,d=d\8 q $e("000000000000",1,l-$l(o))_o fis-gtm-V6.0-003/sr_port/do_indir_do.c0000644000032200000250000001041412201176176016452 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "toktyp.h" #include #include "stack_frame.h" #include "indir_enum.h" #include "cmd_qlf.h" #include "gtm_caseconv.h" #include "op.h" #include "do_indir_do.h" #include "valid_mname.h" GBLREF stack_frame *frame_pointer; GBLREF command_qualifier cmd_qlf; GBLREF boolean_t is_tracing_on; int do_indir_do(mval *v, unsigned char argcode) { mval label; lnr_tabent USHBIN_ONLY(*)*addr; mident_fixed ident; rhdtyp *current_rhead; if (valid_labname(&v->str)) { memcpy(ident.c, v->str.addr, v->str.len); if (!(cmd_qlf.qlf & CQ_LOWER_LABELS)) lower_to_upper((uchar_ptr_t)ident.c, (uchar_ptr_t)ident.c, v->str.len); label.mvtype = MV_STR; label.str.len = v->str.len; label.str.addr = &ident.c[0]; addr = op_labaddr(frame_pointer->rvector, &label, 0); current_rhead = CURRENT_RHEAD_ADR(frame_pointer->rvector); if (argcode == indir_do) { /* If we aren't in an indirect, exfun_frame() is the best way to copy the stack frame as it does not * require re-allocation of the various tables (temps, linkage, literals, etc). But if we are in an * indirect, the various stackframe fields cannot be copied as the indirect has different values so * re-create the frame from the values in the routine header via new_stack_frame(). */ if (!(frame_pointer->flags & SFF_INDCE)) { if (!is_tracing_on) exfun_frame(); else exfun_frame_sp(); } else { if (!is_tracing_on) { new_stack_frame(CURRENT_RHEAD_ADR(frame_pointer->rvector), # ifdef HAS_LITERAL_SECT (unsigned char *)LINKAGE_ADR(current_rhead), # else PTEXT_ADR(current_rhead), # endif USHBIN_ONLY(LINE_NUMBER_ADDR(current_rhead, *addr)) /* On non-shared binary calculate the transfer address to be passed to * new_stack_frame as follows: * 1) get the number stored at addr; this is the offset to the line number * entry * 2) add the said offset to the address of the routine header; this is the * address of line number entry * 3) dereference the said address to get the line number of the actual * program * 4) add the said line number to the address of the routine header */ NON_USHBIN_ONLY((unsigned char *)((char *)current_rhead + *(int4 *)((char *)current_rhead + *addr)))); } else { new_stack_frame_sp(CURRENT_RHEAD_ADR(frame_pointer->rvector), # ifdef HAS_LITERAL_SECT (unsigned char *)LINKAGE_ADR(current_rhead), # else PTEXT_ADR(current_rhead), # endif USHBIN_ONLY(LINE_NUMBER_ADDR(current_rhead, *addr)) /* On non-shared binary calculate the transfer address to be passed to * new_stack_frame as follows: * 1) get the number stored at addr; this is the offset to the line * number entry * 2) add the said offset to the address of the routine header; this is * the address of line number entry * 3) dereference the said address to get the line number of the actual * program * 4) add the said line number to the address of the routine header */ NON_USHBIN_ONLY((unsigned char *)((char *)current_rhead + *(int4 *)((char *)current_rhead + *addr)))); } return TRUE; } } /* On non-shared binary calculate the mpc pointer similarly to the descriptions above. */ frame_pointer->mpc = USHBIN_ONLY(LINE_NUMBER_ADDR(current_rhead, *addr)) NON_USHBIN_ONLY((unsigned char *)((char *)current_rhead + *(int4 *)((char *)current_rhead + *addr))); # ifdef HAS_LITERAL_SECT frame_pointer->ctxt = (unsigned char *)LINKAGE_ADR(current_rhead); # else frame_pointer->ctxt = PTEXT_ADR(current_rhead); # endif return TRUE; } else return FALSE; } fis-gtm-V6.0-003/sr_port/do_indir_do.h0000644000032200000250000000114512201176155016455 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef DO_INDIR_DO_INCLUDED #define DO_INDIR_DO_INCLUDED int do_indir_do(mval *v, unsigned char argcode); /***type int added***/ #endif /* DO_INDIR_DO_INCLUDED */ fis-gtm-V6.0-003/sr_port/do_patalt.c0000644000032200000250000003346212201176155016155 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" /* for memset */ #include "copy.h" #include "patcode.h" #ifdef UNICODE_SUPPORTED #include "gtm_utf8.h" #endif /* see corresponding GBLDEFs in gbldefs.c for comments on the caching mechanism */ GBLREF int4 curalt_depth; /* depth of alternation nesting */ GBLREF int4 do_patalt_calls[PTE_MAX_CURALT_DEPTH]; /* number of calls to do_patalt() */ GBLREF int4 do_patalt_hits[PTE_MAX_CURALT_DEPTH]; /* number of pte_csh hits in do_patalt() */ GBLREF int4 do_patalt_maxed_out[PTE_MAX_CURALT_DEPTH]; /* no. of pte_csh misses after maxing on allocation size */ GBLREF pte_csh *pte_csh_array[PTE_MAX_CURALT_DEPTH]; /* pte_csh array (per curalt_depth) */ GBLREF int4 pte_csh_cur_size[PTE_MAX_CURALT_DEPTH]; /* current pte_csh size (per curalt_depth) */ GBLREF int4 pte_csh_alloc_size[PTE_MAX_CURALT_DEPTH]; /* current allocated pte_csh size (per curalt_depth) */ GBLREF int4 pte_csh_entries_per_len[PTE_MAX_CURALT_DEPTH]; /* current number of entries per len */ GBLREF int4 pte_csh_tail_count[PTE_MAX_CURALT_DEPTH]; /* count of non 1-1 corresponding pte_csh_array members */ GBLREF pte_csh *cur_pte_csh_array; /* copy of pte_csh_array corresponding to curalt_depth */ GBLREF int4 cur_pte_csh_size; /* copy of pte_csh_cur_size corresponding to curalt_depth */ GBLREF int4 cur_pte_csh_entries_per_len; /* copy of pte_csh_entries_per_len corresponding to curalt_depth */ GBLREF int4 cur_pte_csh_tail_count; /* copy of pte_csh_tail_count corresponding to curalt_depth */ GBLREF boolean_t gtm_utf8_mode; /* Example compiled pattern for an alternation pattern * Pattern = P0_P1 * ---------------- * P0 = 1.3(.N,2"-",.2A) * P1 = 1" " * * Compiled Pattern * ----------------- * 0x00000000 <-- fixed (1 if fixed length, 0 if not fixed length) * 0x00000027 <-- length of pattern stream (inclusive of itself) * * 0x02000000 P0 <-- pattern_mask[0] => alternation * 0x00000001 P0 <-- alt_rep_min[0] * 0x00000003 P0 <-- alt_rep_max[0] * 0x00000009 P0 <-- length of alternation pattern's choice[0] pattern (exclusive of itself) * 0x00000000 P0 <-- fixed * 0x00000002 P0 <-- length of pattern stream (inclusive of itself) * 0x40000001 P0 <-- pattern_mask[0] => DFABIT | PATM_N * 0x00000001 P0 <-- count * 0x00000000 P0 <-- tot_min * 0x00007fff P0 <-- tot_max * 0x00000000 P0 <-- min[0] * 0x00007fff P0 <-- max[0] * 0x00000001 P0 <-- size[0] * 0x0000000a P0 <-- length of alternation pattern's choice[1] pattern (exclusive of itself) * 0x00000001 P0 <-- fixed * 0x00000004 P0 <-- length of pattern stream (inclusive of itself) * 0x00000082 P0 <-- pattern_mask[0] = PATM_STR | PATM_P * 0x00000001 P0 <-- length of PATM_STR (exclusive of itself) * 0x0000002d P0 <-- PATM_STR[0] = '-' * 0x00000001 P0 <-- count * 0x00000002 P0 <-- tot_min * 0x00000002 P0 <-- tot_max * 0x00000002 P0 <-- min[0] // Note for fixed length, max[] array is absent // * 0x00000001 P0 <-- size[0] * 0x00000000 P0 <-- End of alternation pattern's choices ('\0') * * 0x00000082 P1 <-- pattern_mask[1] => PATM_STR | PATM_P (' ') * 0x00000001 P1 <-- length of PATM_STR (exclusive of itself) * 0x00000020 P1 <-- PATM_STR[0] = ' ' * * 0x00000002 <-- count * 0x00000001 <-- total_min * 0x00007fff <-- total_max * 0x00000000 <-- min[0] <-- Begin of min[2] array * 0x00000001 <-- min[1] * 0x00007fff <-- max[0] <-- Begin of max[2] array * 0x00000001 <-- max[1] * 0x00000001 <-- size[0] <-- Begin of size[2] array * 0x00000001 <-- size[1] */ /* returns index in cur_pte_csh_array that holds the desired tuple.. * return PTE_NOT_FOUND otherwise. */ static int pte_csh_present(char *patptr, char *strptr, int4 charlen, int repcnt) { int4 index; pte_csh *tmp_pte, *pte_top; assert(PTE_MAX_CURALT_DEPTH > curalt_depth); index = ((PTE_STRLEN_CUTOFF > charlen) ? charlen : PTE_STRLEN_CUTOFF) * cur_pte_csh_entries_per_len; assert(cur_pte_csh_size > index); tmp_pte = cur_pte_csh_array + index; pte_top = tmp_pte + ((PTE_STRLEN_CUTOFF > charlen) ? cur_pte_csh_entries_per_len : cur_pte_csh_tail_count); assert(pte_top <= (cur_pte_csh_array + cur_pte_csh_size)); for (; tmp_pte < pte_top; tmp_pte++) { if ((tmp_pte->strptr != strptr) || (tmp_pte->patptr != patptr) || (tmp_pte->charlen != charlen) || (tmp_pte->repcnt != repcnt)) { if (NULL != tmp_pte->strptr) continue; else break; /* the first NULL value means all further entries for this "charlen" are NULL */ } tmp_pte->count++; return (int)tmp_pte->match; } return (int)PTE_NOT_FOUND; } static void pte_csh_insert(char *patptr, char *strptr, int4 charlen, int repcnt, boolean_t match) { int4 index; pte_csh *tmp_pte, *pte_top, *min_pte, *free_pte; assert(PTE_MAX_CURALT_DEPTH > curalt_depth); assert(PTE_NOT_FOUND == pte_csh_present(patptr, strptr, charlen, repcnt)); index = ((PTE_STRLEN_CUTOFF > charlen) ? charlen : PTE_STRLEN_CUTOFF) * cur_pte_csh_entries_per_len; assert(cur_pte_csh_size > index); tmp_pte = cur_pte_csh_array + index; pte_top = tmp_pte + ((PTE_STRLEN_CUTOFF > charlen) ? cur_pte_csh_entries_per_len : cur_pte_csh_tail_count); assert(pte_top <= (cur_pte_csh_array + cur_pte_csh_size)); min_pte = tmp_pte; free_pte = NULL; for (; tmp_pte < pte_top; tmp_pte++) { if (NULL == tmp_pte->patptr) { min_pte = free_pte = tmp_pte; break; } else if (min_pte->count > tmp_pte->count) min_pte = tmp_pte; } if (NULL == free_pte) { for (tmp_pte = cur_pte_csh_array + index; tmp_pte < pte_top; tmp_pte++) tmp_pte->count = 1; /* reset count whenever new entry is made thereby causing history refresh. * i.e. permitting formerly busy but currently inactive patterns to be reused */ } min_pte->count = 0; /* give little priority to the rest by setting count to 1 less than the others */ min_pte->patptr = patptr; min_pte->strptr = strptr; min_pte->charlen = charlen; min_pte->repcnt = repcnt; min_pte->match = match; } int do_patalt(uint4 *firstalt, unsigned char *strptr, unsigned char *strtop, int4 repmin, int4 repmax, int totchar, int repcnt, int4 min_incr, int4 max_incr) { boolean_t fixed; int4 alt_tot_min, alt_tot_max, new_pte_csh_size, tmp_do_patalt_calls; uint4 *cur_alt, tempuint; uint4 *patptr; int match, alt_size, charlen, bytelen, pat_found; mval alt_pat, alt_str; pte_csh *tmp_pte; unsigned char *strtmp, *strnext; if (PTE_MAX_CURALT_DEPTH > curalt_depth) { /* try to find it in the current pattern evaluation cache (cur_pte_csh_array) itself */ tmp_do_patalt_calls = ++do_patalt_calls[curalt_depth]; pat_found = pte_csh_present((char *)firstalt, (char *)strptr, totchar, repcnt); if (PTE_NOT_FOUND != pat_found) { do_patalt_hits[curalt_depth]++; return pat_found; } else if ((tmp_do_patalt_calls > cur_pte_csh_size) && ((tmp_do_patalt_calls - do_patalt_hits[curalt_depth]) > (tmp_do_patalt_calls / PTE_CSH_MISS_FACTOR))) { /* lots of cache miss happening. try to increase pt_csh_array size */ do_patalt_hits[curalt_depth] = do_patalt_calls[curalt_depth] = 1; new_pte_csh_size = cur_pte_csh_size; if (cur_pte_csh_size < pte_csh_alloc_size[curalt_depth]) { new_pte_csh_size = (cur_pte_csh_size << 1); assert(cur_pte_csh_size <= pte_csh_alloc_size[curalt_depth]); } else if (PTE_MAX_ENTRIES > pte_csh_alloc_size[curalt_depth]) { new_pte_csh_size = (cur_pte_csh_size << 1); tmp_pte = malloc(SIZEOF(pte_csh) * new_pte_csh_size); free(cur_pte_csh_array); pte_csh_alloc_size[curalt_depth] = new_pte_csh_size; pte_csh_array[curalt_depth] = tmp_pte; cur_pte_csh_array = pte_csh_array[curalt_depth]; } else do_patalt_maxed_out[curalt_depth]++; if (new_pte_csh_size != cur_pte_csh_size) { memset(pte_csh_array[curalt_depth], 0, SIZEOF(pte_csh) * new_pte_csh_size); pte_csh_cur_size[curalt_depth] *= 2; pte_csh_entries_per_len[curalt_depth] *= 2; pte_csh_tail_count[curalt_depth] *= 2; UPDATE_CUR_PTE_CSH_MINUS_ARRAY(cur_pte_csh_size, cur_pte_csh_entries_per_len, cur_pte_csh_tail_count); } } } alt_pat.mvtype = MV_STR; alt_str.mvtype = MV_STR; alt_str.str.addr = (char *)strptr; patptr = firstalt; GET_LONG(alt_size, patptr); patptr++; for (match = FALSE; !match && alt_size; patptr++) { cur_alt = patptr; cur_alt++; GET_ULONG(tempuint, cur_alt); cur_alt++; cur_alt += tempuint; GET_LONG(alt_tot_min, cur_alt); cur_alt++; if (alt_tot_min <= totchar) { GET_LONG(tempuint, cur_alt); GET_LONG(fixed, patptr); /* Note that some patterns whose minimum and maximum length are the same need not have * "fixed" field 1. This is because alternations which have choices that all evaluate * to the same length (e.g. 5(2l,2e,"ab")) are currently not recognizable by do_patfixed * and hence go through do_pattern. */ assert(!fixed || (alt_tot_min == tempuint)); alt_tot_max = (tempuint < totchar) ? tempuint : totchar; alt_pat.str.addr = (char *)patptr; alt_pat.str.len = alt_size * SIZEOF(uint4); /* Note that the below zero min length avoiding code is actually an optimization. * This is because if we start from length 0, we will end up matching the input string and in case * the alternation pattern's max count is huge (e.g. PAT_MAX) we will end up recursing * in do_patalt() as many times each time matching a length of 0, without realizing we are * not progressing anywhere in the match by matching a huge number of empty strings. * This will effectively cause a combinatorial explosion to occur in case there are at least 2 choices * in the alternation pattern (which usually will be the case) since the choices that need to be * examined are 2 ** PAT_MAX. * Instead, if we start from length 1, every level of recursion we decrease the size of the problem * by matching a non-zero length of the input string and hence we can't progress much in the * recursion levels before starting to backtrack, thereby avoiding the explosion. * Note that we do have to consider zero length in case we haven't yet exhausted our minimum count of * the alternation pattern and we have a null input string remaining to be matched. * Hence the if check below. */ if (totchar && (0 == alt_tot_min)) alt_tot_min = 1; /* avoid zero min length when non-zero string still needs to be matched */ if (!gtm_utf8_mode) { /* each character is 1 byte so charlen and bytelen is same */ charlen = alt_tot_min; bytelen = alt_tot_min; } UNICODE_ONLY( else { /* skip alt_tot_min characters */ strtmp = strptr; for (charlen = 0; charlen < alt_tot_min; charlen++) { assert(strtmp < strtop); strtmp = UTF8_MBNEXT(strtmp, strtop); } bytelen = (int)(strtmp - strptr); } ) UNICODE_ONLY( if (gtm_utf8_mode) alt_str.mvtype |= MV_UTF_LEN; /* avoid recomputing "char_len" in do_pattern/do_patfixed */ ) for ( ; !match && (charlen <= alt_tot_max); charlen++) { alt_str.str.len = bytelen; UNICODE_ONLY( if (gtm_utf8_mode) { assert(utf8_len(&alt_str.str) == charlen); alt_str.str.char_len = charlen; /* set "char_len" */ } ) match = charlen ? (fixed ? do_patfixed(&alt_str, &alt_pat) : do_pattern(&alt_str, &alt_pat)) : TRUE; /* max_incr and min_incr aid us in an earlier backtracking optimization. * for example, let us consider "abcdefghijklmnopqrstuvwxyz"?.13(1l,1e,1n,1u,1p,2l) * say the first do_patalt() call matches a substring (the beginning of the input string) "a" * with the first alternation choice 1l * say the recursive second do_patalt() call then matches a substring of the now beginning * input string "b" with the first alternation choice 1l again * the recursively called third do_patalt() now can rest assured that the remaining string * can't be matched by the alternation. This is because it has only 11 chances left * (note the maximum is .13) and each time the maximum length it can match is 2 (the * maximum length of all the alternation choices which is 2l) which leaves it with a * maximum of 22 characters while there are still 24 characters left in the input-string. * this optimization can cause a backtracking to occur at the 3rd level of call to do_patalt() * instead of going through the call trace 13 times and then determining at the leaf level. * since at each level, the choices examined are 6, we are saving nearly (6 to the power of 11) * choice examinations (11 for the levels that we avoid with the optimization) */ if (match && ((charlen < totchar) || (repcnt < repmin))) match &= ((repcnt < repmax) && ((totchar - charlen) <= (repmax - repcnt) * max_incr) && ((totchar - charlen) >= (repmin - repcnt) * min_incr)) ? do_patalt(firstalt, &strptr[bytelen], strtop, repmin, repmax, totchar - charlen, repcnt + 1, min_incr, max_incr) : FALSE; if (!match) { /* update "bytelen" to correspond to "charlen + 1" */ if (!gtm_utf8_mode) bytelen++; UNICODE_ONLY( else { assert((strtmp < strtop) || (charlen == alt_tot_max)); if (strtmp < strtop) { strnext = UTF8_MBNEXT(strtmp, strtop); assert(strnext > strtmp); bytelen += (int)(strnext - strtmp); strtmp = strnext; } } ) } } } patptr += alt_size; GET_LONG(alt_size, patptr); } if (PTE_MAX_CURALT_DEPTH > curalt_depth) pte_csh_insert((char *)firstalt, (char *)strptr, totchar, repcnt, match); return match; } fis-gtm-V6.0-003/sr_port/do_patfixed.c0000644000032200000250000001321412201176155016465 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "patcode.h" #include "copy.h" #ifdef UNICODE_SUPPORTED #include "gtm_icu_api.h" /* needed by *TYPEMASK* macros defined in gtm_utf8.h */ #include "gtm_utf8.h" #endif GBLDEF char codelist[] = PATM_CODELIST; GBLREF uint4 pat_allmaskbits; GBLREF uint4 *pattern_typemask; GBLREF boolean_t gtm_utf8_mode; /* This procedure executes at "run-time". After a pattern in a MUMPS program has been compiled (by patstr and its * helper-procedures), this procedure is called to evaluate "fixed-length" patterns. * i.e. for each pattern atom, the lower-bound is equal to the upper-bound such as 3N2A5N. * For patterns with a variable length, procedure do_pattern() is called to do the evaluation. */ int do_patfixed(mval *str, mval *pat) { int4 count, tempint; int4 *min, *reptr, *rtop; int4 repeat; int bit; int letter; int repcnt; int bytelen, charlen, pbytelen, strbytelen; unsigned char *strptr, *strtop, *strnext, *pstr, *ptop, *pnext; uint4 code, tempuint, patstream_len; uint4 *patptr; uint4 mbit; char buf[CHAR_CLASSES]; boolean_t flags, pvalid, strvalid; UNICODE_ONLY( wint_t utf8_codepoint; ) error_def(ERR_PATNOTFOUND); /* set up information */ MV_FORCE_STR(str); patptr = (uint4 *)pat->str.addr; DEBUG_ONLY( GET_ULONG(tempuint, patptr); assert(tempuint); /* ensure first uint4 is non-zero indicating fixed length pattern string */ ) patptr++; GET_ULONG(tempuint, patptr); DEBUG_ONLY(patstream_len = tempuint); patptr += tempuint; GET_LONG(count, patptr); assert(MAX_PATTERN_ATOMS > count); patptr++; GET_ULONG(tempuint, patptr); patptr++; if (!gtm_utf8_mode) charlen = str->str.len; UNICODE_ONLY( else { MV_FORCE_LEN(str); /* to set str.char_len if not already done; also issues BADCHAR error if appropriate */ charlen = str->str.char_len; } ) if (tempuint != charlen) return FALSE; patptr++; min = (int4 *)patptr; rtop = min + count; /* Note: the compiler generates: rtop = min + SIZEOF(int4) * count */ /* attempt a match */ strptr = (unsigned char *)str->str.addr; strtop = &strptr[str->str.len]; patptr = (uint4 *)pat->str.addr; patptr += 2; for (reptr = min; reptr < rtop ; reptr++) { GET_LONG(repeat, reptr); GET_ULONG(code, patptr); assert(code); patptr++; if (!(code & PATM_STRLIT)) { /* meta character pat atom */ if (!(code & pat_allmaskbits)) { /* current table has no characters with this pattern code */ bytelen = 0; for (bit = 0; bit < PAT_MAX_BITS; bit++) { mbit = (1 << bit); if ((mbit & code & PATM_LONGFLAGS) && !(mbit & pat_allmaskbits)) buf[bytelen++] = codelist[patmaskseq(mbit)]; } rts_error(VARLSTCNT(4) ERR_PATNOTFOUND, 2, bytelen, buf); } if (!gtm_utf8_mode) { for (repcnt = 0; repcnt < repeat; repcnt++) { if (!(code & pattern_typemask[*strptr++])) return FALSE; } } UNICODE_ONLY( else { for (repcnt = 0; repcnt < repeat; repcnt++) { assert(strptr < strtop); /* PATTERN_TYPEMASK macro relies on this */ if (!(code & PATTERN_TYPEMASK(strptr, strtop, strnext, utf8_codepoint))) return FALSE; strptr = strnext; } } ) } else { /* STRLIT pat atom */ assert(3 == PAT_STRLIT_PADDING); GET_LONG(bytelen, patptr); /* get bytelen */ patptr++; GET_LONG(charlen, patptr); /* get charlen */ patptr++; GET_ULONG(flags, patptr); /* get falgs */ patptr++; assert(!(flags & PATM_STRLIT_BADCHAR)); /* ensure pattern atom length is within limits of the complete pattern stream */ assert((0 <= bytelen) && ((patptr + DIVIDE_ROUND_UP(bytelen, SIZEOF(*patptr))) <= ((uint4 *)(pat->str.addr) + patstream_len + 2))); pstr = (unsigned char *)patptr; if (1 == bytelen) { if (!gtm_utf8_mode) { for (repcnt = 0; repcnt < repeat; repcnt++) if (*pstr != *strptr++) return FALSE; patptr++; } UNICODE_ONLY( else { for (repcnt = 0; repcnt < repeat; repcnt++) { if ((1 != (UTF8_VALID(strptr, strtop, bytelen), bytelen)) || (*pstr != *strptr++)) return FALSE; } patptr++; } ) } else if (bytelen > 0) { if (!gtm_utf8_mode) { for (repcnt = 0; repcnt < repeat; repcnt++) for (letter = 0, pstr = (unsigned char *)patptr; letter < bytelen; letter++) if (*pstr++ != *strptr++) return FALSE; patptr += DIVIDE_ROUND_UP(bytelen, SIZEOF(*patptr)); } UNICODE_ONLY( else { pstr = (unsigned char *)patptr; ptop = pstr + bytelen; for (repcnt = 0; repcnt < repeat; repcnt++) { pstr = (unsigned char *)patptr; for ( ; pstr < ptop; ) { pvalid = UTF8_VALID(pstr, ptop, pbytelen); /* sets pbytelen */ assert(pvalid); strvalid = UTF8_VALID(strptr, strtop, strbytelen); /* sets strbytelen */ if (pbytelen != strbytelen) return FALSE; else { DEBUG_ONLY(strnext = strptr + pbytelen); pnext = pstr + pbytelen; do { if (*pstr++ != *strptr++) return FALSE; } while (pstr < pnext); assert(strptr == strnext); } } } patptr += DIVIDE_ROUND_UP(bytelen, SIZEOF(*patptr)); } ) } } } return TRUE; } fis-gtm-V6.0-003/sr_port/do_patsplit.c0000644000032200000250000002777612201176155016543 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "patcode.h" #include "copy.h" #include "min_max.h" #include "gtm_string.h" #ifdef UNICODE_SUPPORTED #include "gtm_utf8.h" #endif GBLREF boolean_t gtm_utf8_mode; /* This routine tries to split the pattern-string P into substrings LFR where F is a fixed length pattern-atom of P * and L and R are the pattern substrings in P on the left and right side of F. * For pattern-strings that have more than one fixed-length pattern-atom, the one closest to the median is selected. * Once F is determined, do_patfixed() is invoked to determine all possible matches of F with the input string. * do_patsplit() has additional optimizations to try match the fixed length pattern in a restricted subset of the * input string taking into account the min and max of the left and the right pattern. * For each such match, an attempt is made to match L and R with the left and right side of the input string. * This is done using do_patfixed() or do_pattern() appropriately. * If any such attempt succeeds, we return TRUE. * If no attempt succeeds, we return FALSE. * If the pattern-string P doesn't contain any fixed-length pattern-atom, we return DO_PATSPLIT_FAIL */ int do_patsplit(mval *str, mval *pat) { int4 count, total_min, total_max; int4 min[MAX_PATTERN_ATOMS], max[MAX_PATTERN_ATOMS], size[MAX_PATTERN_ATOMS]; int4 bytelen, charlen, charstoskip, fixedcharlen, leftcharlen, rightcharlen, deltalen, numchars; int4 strbytelen, strcharlen; int4 alt_rep_min, alt_rep_max; int4 alt; uint4 tempuint; uint4 code, flags; uint4 *patptr, *patptr_start, *patptr_end, *fixed_patptr, *right_patptr, *tmp_patptr; ptstr left_ptstr, right_ptstr, fixed_ptstr; mval left_pat, right_pat, fixed_pat, left_str, right_str, fixed_str; int4 index, fixed_index; /* index of our current fixed-length pattern-atom */ boolean_t right; /* 0 indicates we are processing left side, 1 indicates right side */ boolean_t fixed[2]; /* fixed[0] is for the left, fixed[1] is for the right */ int4 tot_min[2], tot_max[2], cnt[2]; /* index 0 is for left, index 1 is for right */ int4 offset; unsigned char *strptr, *strtop, *rightptr, *rightnext, *fixedptr, *fixednext, *maxfixedptr; boolean_t match; /* match status of input pattern with input string */ gtm_uint64_t bound; MV_FORCE_STR(str); patptr = (uint4 *)pat->str.addr; DEBUG_ONLY( GET_ULONG(tempuint, patptr); assert(!tempuint); ) patptr++; patptr_start = patptr + 1; GET_ULONG(tempuint, patptr); patptr += tempuint; patptr_end = patptr; GET_LONG(count, patptr); patptr++; GET_LONG(total_min, patptr); patptr++; GET_LONG(total_max, patptr); patptr++; UNICODE_ONLY( if (gtm_utf8_mode) { MV_FORCE_LEN(str); /* to set str.char_len if not already done */ assert(str->str.char_len >= total_min && str->str.char_len <= total_max); } ) assert(count <= MAX_PATTERN_ATOMS); memcpy(&min[0], patptr, SIZEOF(*patptr) * count); patptr += count; memcpy(&max[0], patptr, SIZEOF(*patptr) * count); patptr += count; memcpy(&size[0], patptr, SIZEOF(*patptr) * count); patptr = patptr_start; right = FALSE; /* start with left side */ fixed[right] = TRUE; tot_min[right] = tot_max[right] = 0; fixed_patptr = right_patptr = NULL; fixed_index = -1; for (index = 0; index < count; index++) { GET_ULONG(code, patptr); tmp_patptr = patptr; patptr++; if (code & PATM_ALT) { /* skip to the next pattern-atom */ GET_LONG(alt_rep_min, patptr); patptr++; GET_LONG(alt_rep_max, patptr); patptr++; GET_LONG(alt, patptr); patptr++; while(alt) { patptr += alt; GET_LONG(alt, patptr); patptr++; } fixed[right] = FALSE; /* patptr now points to the next patcode after the alternation */ } else if (code == PATM_DFA) { /* Discrete Finite Automaton pat atom */ assert(min[index] != max[index]); /* DFA should never be fixed length */ GET_LONG(bytelen, patptr); patptr++; patptr += bytelen; fixed[right] = FALSE; } else { if (code & PATM_STRLIT) { /* STRLIT pat atom */ assert(3 == PAT_STRLIT_PADDING); GET_LONG(bytelen, patptr); patptr++; GET_LONG(charlen, patptr); patptr++; GET_ULONG(flags, patptr); patptr++; patptr += DIVIDE_ROUND_UP(bytelen, SIZEOF(*patptr)); } if ((min[index] == max[index]) && (bound = (gtm_uint64_t)min[index] * size[index])) { /* fixed_length */ if (ABS(index - (count / 2)) < ABS(fixed_index - (count / 2))) { /* non-zero fixed length pattern with a fixed_index closer to the median of the array */ if (right) { /* update left's tot_min and tot_max to reflect the new fixed_index */ tot_min[0] += tot_min[right] + BOUND_MULTIPLY(min[fixed_index], size[fixed_index], bound); if (tot_min[0] > PAT_MAX_REPEAT) tot_min[0] = PAT_MAX_REPEAT; tot_max[0] += tot_max[right] + BOUND_MULTIPLY(max[fixed_index], size[fixed_index], bound); if (tot_max[0] > PAT_MAX_REPEAT) tot_max[0] = PAT_MAX_REPEAT; fixed[0] &= fixed[right]; } fixed_index = index; right = TRUE; fixed[right] = TRUE; tot_min[right] = tot_max[right] = 0; fixed_patptr = tmp_patptr; right_patptr = patptr; continue; } } else fixed[right] = FALSE; } tot_min[right] += BOUND_MULTIPLY(min[index], size[index], bound); if (tot_min[right] > PAT_MAX_REPEAT) tot_min[right] = PAT_MAX_REPEAT; tot_max[right] += BOUND_MULTIPLY(max[index], size[index], bound); if (tot_max[right] > PAT_MAX_REPEAT) tot_max[right] = PAT_MAX_REPEAT; } assert(index == count); if (-1 == fixed_index) return DO_PATSPLIT_FAIL; assert(fixed_index < count); assert((total_min == (tot_min[0] + tot_min[1] + BOUND_MULTIPLY(min[fixed_index], size[fixed_index], bound))) || (PAT_MAX_REPEAT == total_min)); assert((total_max == (tot_max[0] + tot_max[1] + BOUND_MULTIPLY(max[fixed_index], size[fixed_index], bound))) || (PAT_MAX_REPEAT == total_max)); cnt[0] = fixed_index; if (cnt[0]) { /* left section has at least one pattern atom. create its compilation string */ patptr = left_ptstr.buff; *patptr++ = fixed[0]; *patptr++ = (uint4)(fixed_patptr - patptr_start + 1); memcpy(patptr, patptr_start, (char *)fixed_patptr - (char *)patptr_start); patptr += fixed_patptr - patptr_start; *patptr++ = cnt[0]; *patptr++ = tot_min[0]; *patptr++ = tot_max[0]; for (index = 0; index < cnt[0]; index++) *patptr++ = min[index]; if (!fixed[0]) { for (index = 0; index < cnt[0]; index++) *patptr++ = max[index]; } for (index = 0; index < cnt[0]; index++) *patptr++ = size[index]; left_pat.mvtype = MV_STR; left_pat.str.len = INTCAST((char *)patptr - (char *)&left_ptstr.buff[0]); left_pat.str.addr = (char *)&left_ptstr.buff[0]; } /* create fixed length pattern atom's compilation string */ patptr = fixed_ptstr.buff; *patptr++ = TRUE; /* fixed length pattern */ *patptr++ = (uint4)(right_patptr - fixed_patptr + 1); memcpy(patptr, fixed_patptr, (char *)right_patptr - (char *)fixed_patptr); patptr += right_patptr - fixed_patptr; *patptr++ = 1; /* count */ fixedcharlen = min[fixed_index] * size[fixed_index]; /* tot_min and tot_max */ *patptr++ = fixedcharlen; *patptr++ = fixedcharlen; *patptr++ = min[fixed_index]; /* min[0] */ *patptr++ = size[fixed_index]; /* size[0] */ fixed_pat.mvtype = MV_STR; fixed_pat.str.len = INTCAST((char *)patptr - (char *)&fixed_ptstr.buff[0]); fixed_pat.str.addr = (char *)&fixed_ptstr.buff[0]; cnt[1] = count - fixed_index - 1; if (cnt[1]) { /* right section has at least one pattern atom. create its compilation string */ patptr = right_ptstr.buff; *patptr++ = fixed[1]; *patptr++ = (uint4)(patptr_end - right_patptr + 1); memcpy(patptr, right_patptr, (char *)patptr_end - (char *)right_patptr); patptr += patptr_end - right_patptr; *patptr++ = cnt[1]; *patptr++ = tot_min[1]; *patptr++ = tot_max[1]; for (index = fixed_index + 1; index < count; index++) *patptr++ = min[index]; if (!fixed[1]) { for (index = fixed_index + 1; index < count; index++) *patptr++ = max[index]; } for (index = fixed_index + 1; index < count; index++) *patptr++ = size[index]; right_pat.mvtype = MV_STR; right_pat.str.len = INTCAST((char *)patptr - (char *)&right_ptstr.buff[0]); right_pat.str.addr = (char *)&right_ptstr.buff[0]; } strbytelen = str->str.len; strptr = (unsigned char *)str->str.addr; strtop = strptr + strbytelen; if (!gtm_utf8_mode) strcharlen = str->str.len; UNICODE_ONLY( else strcharlen = str->str.char_len; ) /* Determine "maxfixedptr" */ if (strcharlen > (tot_min[1] + tot_max[0] + fixedcharlen)) charstoskip = tot_max[0]; else charstoskip = strcharlen - tot_min[1] - fixedcharlen; if (!gtm_utf8_mode) strptr += charstoskip; UNICODE_ONLY( else { for ( ; 0 < charstoskip; charstoskip--) { assert(strptr < strtop); /* below macro relies on this */ strptr = UTF8_MBNEXT(strptr, strtop); } } ) maxfixedptr = strptr; /* Determine "fixedptr" */ strptr = (unsigned char *)str->str.addr; if (strcharlen > (tot_min[0] + tot_max[1] + fixedcharlen)) charstoskip = strcharlen - tot_max[1] - fixedcharlen; else charstoskip = tot_min[0]; leftcharlen = charstoskip; if (!gtm_utf8_mode) strptr += charstoskip; UNICODE_ONLY( else { for ( ; 0 < charstoskip; charstoskip--) { assert(strptr < strtop); /* below macro relies on this */ strptr = UTF8_MBNEXT(strptr, strtop); } } ) fixedptr = strptr; /* Set "left_str" */ left_str.mvtype = MV_STR; left_str.str.addr = str->str.addr; /* Set "right_str" */ right_str.mvtype = MV_STR; /* Set "fixed_str" */ fixed_str.mvtype = MV_STR; if (!gtm_utf8_mode) { fixed_str.str.len = fixedcharlen; rightptr = fixedptr + fixedcharlen; } UNICODE_ONLY( else { left_str.mvtype |= MV_UTF_LEN; /* avoid recomputing "char_len" in do_patfixed below */ right_str.mvtype |= MV_UTF_LEN; /* avoid recomputing "char_len" in do_patfixed below */ fixed_str.mvtype |= MV_UTF_LEN; /* avoid recomputing "char_len" in do_patfixed below */ fixed_str.str.char_len = fixedcharlen; /* skip fixedcharlen characters */ assert(fixedptr == strptr); for (numchars = 0; numchars < fixedcharlen; numchars++) { assert(strptr < strtop); strptr = UTF8_MBNEXT(strptr, strtop); } rightptr = strptr; } ) deltalen = 0; /* Try to match the fixed pattern string and for each match, try matching the left and right input strings */ for (match = FALSE; !match && (fixedptr <= maxfixedptr); fixedptr = fixednext, rightptr = rightnext, leftcharlen++) { fixed_str.str.addr = (char *)fixedptr; fixed_str.str.len = INTCAST(rightptr - fixedptr); if (!gtm_utf8_mode) { fixednext = fixedptr + 1; rightnext = rightptr + 1; } UNICODE_ONLY( else { assert(fixedptr < strtop); fixednext = UTF8_MBNEXT(fixedptr, strtop); assert((rightptr < strtop) || (fixedptr == maxfixedptr) && (fixednext > maxfixedptr)); if (rightptr < strtop) rightnext = UTF8_MBNEXT(rightptr, strtop); } ) if (!do_patfixed(&fixed_str, &fixed_pat)) continue; assert(cnt[0] || cnt[1]); /* fixed_pat takes only one pattern atom and non-zero rest are in cnt[0] and cnt[1] */ if (cnt[0]) { left_str.str.len = INTCAST(fixedptr - (unsigned char *)left_str.str.addr); UNICODE_ONLY(left_str.str.char_len = leftcharlen;) match = fixed[0] ? do_patfixed(&left_str, &left_pat) : do_pattern(&left_str, &left_pat); if (!match) continue; } if (cnt[1]) { right_str.str.addr = (char *)rightptr; UNICODE_ONLY(right_str.str.char_len = strcharlen - leftcharlen - fixedcharlen;) right_str.str.len = INTCAST(strtop - rightptr); match = (fixed[1] ? do_patfixed(&right_str, &right_pat) : do_pattern(&right_str, &right_pat)); } } return match; } fis-gtm-V6.0-003/sr_port/do_pattern.c0000644000032200000250000003272712201176155016350 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "patcode.h" #include "copy.h" #include "min_max.h" #ifdef UNICODE_SUPPORTED #include "gtm_icu_api.h" /* needed by *TYPEMASK* macros defined in gtm_utf8.h */ #include "gtm_utf8.h" #endif GBLREF uint4 pat_allmaskbits; GBLREF uint4 *pattern_typemask; GBLREF char codelist[]; GBLREF int4 curalt_depth; /* depth of alternation nesting */ GBLREF int4 do_patalt_calls[PTE_MAX_CURALT_DEPTH]; /* number of calls to do_patalt() */ GBLREF int4 do_patalt_hits[PTE_MAX_CURALT_DEPTH]; /* number of pte_csh hits in do_patalt() */ GBLREF pte_csh *pte_csh_array[PTE_MAX_CURALT_DEPTH]; /* pte_csh array (per curalt_depth) */ GBLREF int4 pte_csh_cur_size[PTE_MAX_CURALT_DEPTH]; /* current pte_csh size (per curalt_depth) */ GBLREF int4 pte_csh_alloc_size[PTE_MAX_CURALT_DEPTH]; /* current allocated pte_csh size (per curalt_depth) */ GBLREF int4 pte_csh_entries_per_len[PTE_MAX_CURALT_DEPTH]; /* current number of entries per len */ GBLREF int4 pte_csh_tail_count[PTE_MAX_CURALT_DEPTH]; /* count of non 1-1 corresponding pte_csh_array members */ GBLREF pte_csh *cur_pte_csh_array; /* copy of pte_csh_array corresponding to curalt_depth */ GBLREF int4 cur_pte_csh_size; /* copy of pte_csh_cur_size corresponding to curalt_depth */ GBLREF int4 cur_pte_csh_entries_per_len; /* copy of pte_csh_entries_per_len corresponding to curalt_depth */ GBLREF int4 cur_pte_csh_tail_count; /* copy of pte_csh_tail_count corresponding to curalt_depth */ GBLREF boolean_t gtm_utf8_mode; /* This procedure executes at "run-time". After a pattern in a MUMPS program has been compiled (by patstr and * its helper-procedures), this procedure can be called to evaluate "variable-length" patterns. * Variable-length patterns are of the kind 3.5N2.A.5N i.e. for at least one pattern atom, * the lower-bound is different from the upper-bound. * For patterns with a fixed length, procedure do_patfixed() will be called to do the evaluation. * Variable length input patterns will be scanned at runtime to see if they have at least one fixed length pattern atom. * If yes, routine do_patsplit() will be invoked to determine the fixed length sub pattern atom that is closest to the * median of the pattern atoms. The input pattern would then be split into three, left, fixed and right. * The fixed pattern can be matched by a linear scan in the input string. Once that is done, the left and right * pattern atom positions are pivoted relative to the input string and do_pattern() is invoked on each of them recursively. * If no fixed length pattern atoms can be found, then do_pattern() calculates all possible permutations (it has certain * optimizations to prune the combinatorial search tree) and tries to see for each permutation if a match occurs. */ int do_pattern(mval *str, mval *pat) { int4 count, total_min, total_max; int4 alt_rep_min, alt_rep_max, min_incr, max_incr; int4 bytelen, charlen, length, pbytelen, strbytelen; boolean_t success, attempt, pvalid, strvalid; int atom, unit, idx, index, hasfixed; uint4 z_diff, *rpt, *rtop, rept; uint4 repeat[MAX_PATTERN_ATOMS]; uint4 *patidx[MAX_PATTERN_ATOMS]; unsigned char *stridx[MAX_PATTERN_ATOMS]; unsigned char *strptr, *strtop, *strnext, *pstr, *ptop, *pnext; uint4 code, tempuint; uint4 *dfa_ptr, dfa_val; uint4 *patptr; uint4 mbit, flags; int4 *min, *max, *size; int4 mintmp, maxtmp, sizetmp; int alt, bit; char buf[CHAR_CLASSES]; boolean_t pte_csh_init; boolean_t match; UNICODE_ONLY( wint_t utf8_codepoint; ) error_def(ERR_PATNOTFOUND); /* set up information */ MV_FORCE_STR(str); patptr = (uint4 *) pat->str.addr; GET_ULONG(tempuint, patptr); if (tempuint) { /* tempuint non-zero implies fixed length pattern string. this in turn implies we are not called from op_pattern.s * but instead called from op_fnzsearch(), gvzwr_fini(), gvzwr_var(), lvzwr_fini(), lvzwr_var() etc. * in this case, call do_patfixed() as the code below and code in do_patsplit() assumes we are dealing with a * variable length pattern string. changing all the callers to call do_patfixed() directly instead of this extra * redirection was considered, but not felt worth it since the call to do_pattern() is not easily macroizable * due to the expression-like usage in those places. */ return do_patfixed(str, pat); } patptr++; patidx[0] = patptr + 1; stridx[0] = (unsigned char *)str->str.addr; strtop = stridx[0] + str->str.len; GET_ULONG(tempuint, patptr); patptr += tempuint; GET_LONG(count, patptr); patptr++; GET_LONG(total_min, patptr); patptr++; GET_LONG(total_max, patptr); patptr++; /* "length" actually denotes character length; Get it from the appropriate field in the mstr */ if (!gtm_utf8_mode) length = str->str.len; UNICODE_ONLY( else { MV_FORCE_LEN(str); /* to set str.char_len if not already done; also issues BADCHAR error if appropriate */ length = str->str.char_len; } ) if (length < total_min || length > total_max) return FALSE; min = (int4 *)patptr; patptr += count; max = (int4 *)patptr; patptr += count; if (MIN_SPLIT_N_MATCH_COUNT <= count) { hasfixed = FALSE; for (index = 0; index < count; index++) { GET_LONG(maxtmp, max + index); GET_LONG(mintmp, min + index); if (maxtmp == mintmp) { hasfixed = TRUE; break; } } if (hasfixed && (DO_PATSPLIT_FAIL != (match = do_patsplit(str, pat)))) return match; } size = (int4 *)patptr; memcpy(repeat, min, count * SIZEOF(*min)); rtop = &repeat[0] + count; count--; attempt = FALSE; idx = 0; pte_csh_init = FALSE; /* proceed to check string */ for (;;) { if (total_min == length) { /* attempt a match */ attempt = TRUE; strptr = stridx[idx]; patptr = patidx[idx]; rpt = &repeat[idx]; for (; rpt < rtop; rpt++) { GET_ULONG(code, patptr); patptr++; rept = *rpt; if (code & PATM_ALT) { /* pattern alternation */ GET_LONG(alt_rep_min, patptr); patptr++; GET_LONG(alt_rep_max, patptr); patptr++; GET_LONG(maxtmp, max + idx); GET_LONG(mintmp, min + idx); assert(alt_rep_min || !mintmp); assert(alt_rep_max || !maxtmp); min_incr = mintmp ? mintmp / alt_rep_min : 0; max_incr = maxtmp ? maxtmp / alt_rep_max : 0; if (rept) { if (FALSE == pte_csh_init) { PTE_CSH_INCR_CURALT_DEPTH(curalt_depth); pte_csh_init = TRUE; } if (do_patalt(patptr, strptr, strtop, alt_rep_min, alt_rep_max, rept, 1, min_incr, max_incr)) { if (!gtm_utf8_mode) strptr += rept; UNICODE_ONLY( else { for (unit = 0; unit < rept; unit++) { assert(strptr < strtop); /* below macro relies on this */ strptr = UTF8_MBNEXT(strptr, strtop); } } ) } else goto CALC; } /* make sure that patptr points to the next patcode after the alternation */ GET_LONG(alt, patptr); patptr++; while(alt) { patptr += alt; GET_LONG(alt, patptr); patptr++; } } else if (!(code & PATM_STRLIT)) { /* meta character pat atom */ if (!(code & pat_allmaskbits)) { /* current table has no characters with this pattern code */ bytelen = 0; for (bit = 0; bit < PAT_MAX_BITS; bit++) { mbit = (1 << bit); if ((mbit & code & PATM_LONGFLAGS) && !(mbit & pat_allmaskbits)) buf[bytelen++] = codelist[patmaskseq(mbit)]; } rts_error(VARLSTCNT(4) ERR_PATNOTFOUND, 2, bytelen, buf); } if (!gtm_utf8_mode) { for (unit = 0; unit < rept; unit++) { if (!(code & pattern_typemask[*strptr++])) goto CALC; } } UNICODE_ONLY( else { for (unit = 0; unit < rept; unit++) { assert(strptr < strtop); /* PATTERN_TYPEMASK macro relies on this */ if (!(code & PATTERN_TYPEMASK(strptr, strtop, strnext, utf8_codepoint))) goto CALC; strptr = strnext; } } ) } else if (code == PATM_DFA) { /* Discrete Finite Automaton pat atom */ GET_LONG(bytelen, patptr); patptr++; dfa_ptr = patptr; for (unit = 0; unit < rept; ) { GET_ULONG(dfa_val, dfa_ptr); if (!(dfa_val & PATM_STRLIT)) { if (!gtm_utf8_mode) { success = (dfa_val & pattern_typemask[*strptr]); strnext = strptr + 1; } UNICODE_ONLY( else { success = (dfa_val & PATTERN_TYPEMASK(strptr, strtop, strnext, utf8_codepoint)); } ) } else { dfa_ptr++; GET_ULONG(dfa_val, dfa_ptr); /* Only ASCII characters are currently allowed for DFA STRLITs. * Assert that below. */ assert(IS_ASCII(dfa_val)); if (!gtm_utf8_mode) { success = (dfa_val == *strptr); strnext = strptr + 1; } UNICODE_ONLY( else { UTF8_VALID(strptr, strtop, strbytelen); success = ((1 == strbytelen) && (dfa_val == *strptr)); strnext = strptr + strbytelen; } ) } dfa_ptr++; if (success) { GET_ULONG(dfa_val, dfa_ptr); dfa_ptr = patptr + dfa_val; strptr = strnext; unit++; GET_ULONG(dfa_val, dfa_ptr); if (dfa_val == PATM_ACS) break; } else { dfa_ptr++; GET_ULONG(dfa_val, dfa_ptr); if ((dfa_val & PATM_DFA) == PATM_DFA) break; } } if (unit < rept) goto CALC; else { GET_ULONG(dfa_val, dfa_ptr); while (dfa_val < PATM_DFA) { if (dfa_val & PATM_STRLIT) dfa_ptr += 3; else dfa_ptr += 2; GET_ULONG(dfa_val, dfa_ptr); } if (dfa_val != PATM_ACS) goto CALC; } patptr += bytelen; } else { /* STRLIT pat atom */ assert(3 == PAT_STRLIT_PADDING); GET_LONG(bytelen, patptr); /* get bytelen */ patptr++; GET_LONG(charlen, patptr); /* get charlen */ patptr++; GET_ULONG(flags, patptr); /* get flags */ patptr++; if (bytelen == 1) { if (!gtm_utf8_mode) { for (unit = 0; unit < rept; unit++) { if (*(unsigned char *)patptr != *strptr++) goto CALC; } } UNICODE_ONLY( else { for (unit = 0; unit < rept; unit++) { if ((1 != (UTF8_VALID(strptr, strtop, strbytelen), strbytelen)) || (*(unsigned char *)patptr != *strptr++)) goto CALC; } } ) patptr++; } else if (bytelen > 0) { if (!gtm_utf8_mode) { ptop = (unsigned char *)patptr + bytelen; for (unit = 0; unit < rept; unit++) { pstr = (unsigned char *)patptr; while (pstr < ptop) { if (*pstr++ != *strptr++) goto CALC; } } } UNICODE_ONLY( else { pstr = (unsigned char *)patptr; ptop = pstr + bytelen; for (unit = 0; unit < rept; unit++) { pstr = (unsigned char *)patptr; for ( ; pstr < ptop; ) { pvalid = UTF8_VALID(pstr, ptop, pbytelen); /* sets pbytelen */ assert(pvalid); strvalid = UTF8_VALID(strptr, strtop, strbytelen); /* sets strbytelen */ if (pbytelen != strbytelen) goto CALC; DEBUG_ONLY(strnext = strptr + pbytelen); pnext = pstr + pbytelen; do { if (*pstr++ != *strptr++) goto CALC; } while (pstr < pnext); assert(strptr == strnext); } } } ) patptr += DIVIDE_ROUND_UP(bytelen, SIZEOF(*patptr)); } } idx++; stridx[idx] = strptr; patidx[idx] = patptr; } if (pte_csh_init) { /* surrounded by braces since the following is a multi-line macro */ PTE_CSH_DECR_CURALT_DEPTH(curalt_depth); } return TRUE; } else { /* calculate permutations */ attempt = FALSE; GET_LONG(maxtmp, max + count); GET_LONG(mintmp, min + count); GET_LONG(sizetmp, size + count); if (repeat[count] < maxtmp) { atom = unit = length - total_min; z_diff = maxtmp - mintmp; if (sizetmp > 1) { unit /= sizetmp; atom = unit * sizetmp; z_diff *= sizetmp; } if (atom > 0) { total_min += MIN(atom, z_diff); repeat[count] = MIN(repeat[count] + unit, maxtmp); if (total_min == length) continue; } } } CALC: unit = count; GET_LONG(sizetmp, size + unit); for ( ; ; ) { GET_LONG(mintmp, min + unit); total_min -= (repeat[unit] - mintmp) * sizetmp; repeat[unit] = mintmp; unit--; if (unit < 0) { if (pte_csh_init) { /* surrounded by braces since the following is a multi-line macro */ PTE_CSH_DECR_CURALT_DEPTH(curalt_depth); } return FALSE; } GET_LONG(maxtmp, max + unit); GET_LONG(sizetmp, size + unit); if (repeat[unit] < maxtmp) { total_min += sizetmp; repeat[unit]++; if (total_min <= length) { if (unit <= idx) { idx = unit; break; } if (!attempt) break; } } } } } fis-gtm-V6.0-003/sr_port/do_xform.h0000644000032200000250000000274612201176155016031 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef DO_XFORM_INCLUDED #define DO_XFORM_INCLUDED #define DO_XFORM_RETURN_IF_NULL_STRING(INPUT, OUTPUT, LENGTH) \ { \ if (!INPUT->len) \ { /* If input string is the null subscript, we want the output (of the collation transformation function) \ * to be a null subscript as well. This is because the null subscript has special meaning as far as \ * GT.M subscript collation is concerned. In case the collation routine decides to map it to a non-null \ * subscript the user might start seeing undesirable collation orders. To be safe and avoid such \ * issues, the null subscript is handled specially by mapping it to a null subscript internally by GT.M \ * (without passing this to the collation routine) and returning right away. \ */ \ OUTPUT->len = 0; \ *LENGTH = 0; \ } \ } void do_xform(collseq *csp, int fc_type, mstr *input, mstr *output, int *length); /* * fc_type would be either XFORM (0) or XBACK (1) */ #endif /* DO_XFORM_INCLUDED */ fis-gtm-V6.0-003/sr_port/dollar_quit.c0000644000032200000250000002245312201176176016526 0ustar librarygtc/**************************************************************** * * * Copyright 2010, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include #include "stack_frame.h" #include "op.h" #include "get_ret_targ.h" #include "xfer_enum.h" #include "dollar_quit.h" #if defined(__sparc) # include "sparc.h" #elif defined(__s390__) || defined(__MVS__) # include "s390.h" #elif defined(__hppa) # include "hppa.h" #elif defined(__ia64) # include "ia64.h" #endif GBLREF int process_exiting; /* Determine value to return for $QUIT: * * 0 - no return value requested * 1 - non-alias return value requested * 11 - alias return value requested * * Determination of parm/no-parm is made by calling get_ret_targ() which checks the stack frames back to * a counted frame whether the ret_value field has a return mval, signifying that a return value is required. * If a return value is required, determination of the type of return value is made by examining the * generated instruction stream at the return point and checking for an OC_EXFUNRET or OC_EXFUNRETALS * (non-alias and alias type return var processor respectively) opcode following the return point. This is * done by isolating the instruction that indexes into the transfer table, extracting the xfer-table index * and checking against known values for op_exfunret and op_exfunretals to determine type of return. No match * means no return value. * * Because this routine looks at the generated code stream at the return point, it is highly platform * dependent. * * Note: If generated code changes for a platform, this module needs to be revisited. */ int dollar_quit(void) { stack_frame *sf; int xfer_index; union { unsigned char *instr; unsigned short *instr_type; unsigned char *instr_type_8; unsigned char *xfer_offset_8; short *xfer_offset_16; int *xfer_offset_32; } ptrs; /* There was no return value - return 0 */ if (NULL == get_ret_targ(&sf)) return 0; /* There is a return value - see if they want a "regular" or alias type return argument */ sf = sf->old_frame_pointer; /* Caller's frame */ # ifdef __i386 { ptrs.instr = sf->mpc; /* First figure out the potential length of the lea* instruction loading compiler temp offset */ if (0x078d == *ptrs.instr_type) ptrs.instr += 3; /* Past the 2 byte lea plus 1 byte push */ else if (0x478d == *ptrs.instr_type) ptrs.instr += 4; /* Past the 3 byte lea plus 1 byte push */ else if (0x878d == *ptrs.instr_type) ptrs.instr += 7; /* Past the 6 byte lea plus 1 byte push */ else ptrs.instr = NULL; /* Note the "long format call opcode" check below assumes that both of the EXFUNRET[ALS] calls remain at a * greater-than-128 byte offset in the transfer table (which they currently are). */ if ((NULL != ptrs.instr) && (0x93FF == *ptrs.instr_type)) { ptrs.instr += SIZEOF(*ptrs.instr_type); xfer_index = *ptrs.xfer_offset_32 / SIZEOF(void *); } else xfer_index = -1; } # elif defined(__x86_64__) { ptrs.instr = sf->mpc; if (0x8d49 == *ptrs.instr_type) { ptrs.instr += 2; /* Past first part of instruction type */ if (0x7e == *ptrs.instr_type_8) ptrs.instr += 2; /* past last byte of instruction type plus 1 byte offset */ else if (0xbe == *ptrs.instr_type_8) ptrs.instr += 5; /* past last byte of instruction type plus 4 byte offset */ else ptrs.instr = NULL; } else ptrs.instr_type = NULL; if ((NULL != ptrs.instr) && (0x93FF == *ptrs.instr_type)) { /* Long format CALL */ ptrs.instr += SIZEOF(*ptrs.instr_type); xfer_index = *ptrs.xfer_offset_32 / SIZEOF(void *); } else xfer_index = -1; /* Not an xfer index */ } # elif defined(_AIX) { ptrs.instr = sf->mpc + 4; /* Past address load of compiler temp arg */ if (0xE97C == *ptrs.instr_type) { /* ld of descriptor address from xfer table */ ptrs.instr += SIZEOF(*ptrs.instr_type); xfer_index = *ptrs.xfer_offset_16 / SIZEOF(void *); } else xfer_index = -1; } # elif defined(__alpha) /* Applies to both VMS and Tru64 as have same codegen */ { ptrs.instr = sf->mpc + 4; /* Past address load of compiler temp arg */ if (UNIX_ONLY(0xA36C) VMS_ONLY(0xA36B) == *(ptrs.instr_type + 1)) /* Different code for reg diff */ /* ldl of descriptor address from xfer table - little endian - offset prior to opcode */ xfer_index = *ptrs.xfer_offset_16 / SIZEOF(void *); else xfer_index = -1; } # elif defined(__sparc) { ptrs.instr = sf->mpc + 4; /* Past address load of compiler temp arg */ if (0xC85C == *ptrs.instr_type) { /* ldx of rtn address from xfer table */ ptrs.instr += SIZEOF(*ptrs.instr_type); xfer_index = (*ptrs.xfer_offset_16 & SPARC_MASK_OFFSET) / SIZEOF(void *); } else xfer_index = -1; } # elif defined(__s390__) || defined(__MVS__) { format_RXY instr_LG; ZOS_ONLY(format_RR instr_RR;) union { int offset; struct { /* Used to reassemble the offset in the LG instruction */ int offset_unused:12; int offset_hi:8; int offset_low:12; } instr_LG_bits; } RXY; /* Need to forward space past address load of compiler temp arg. On zOS, the position of the mpc can * differ. If the origin point is an external call, we have to forward space past the BCR following * the call point. If the origin point is an internal call, the call point is a branch with no * following BCR. So zOS needs to determine if it has to jump over a BCR call first. */ ZOS_ONLY(memcpy(&instr_RR, sf->mpc, SIZEOF(instr_RR))); ptrs.instr = sf->mpc; ZOS_ONLY(if ((S390_OPCODE_RR_BCR == instr_RR.opcode) && (0 == instr_RR.r1) && (0 == instr_RR.r2)) ptrs.instr += 2); /* Past BCR 0,0 from external call */ ptrs.instr += 6; /* Past address load of compiler temp arg */ memcpy(&instr_LG, ptrs.instr, SIZEOF(instr_LG)); if ((S390_OPCODE_RXY_LG == instr_LG.opcode) && (S390_SUBCOD_RXY_LG == instr_LG.opcode2) && (GTM_REG_SAVE_RTN_ADDR == instr_LG.r1) && (GTM_REG_XFER_TABLE == instr_LG.b2)) { /* LG of rtn address from xfer table */ RXY.offset = 0; RXY.instr_LG_bits.offset_hi = instr_LG.dh2; RXY.instr_LG_bits.offset_low = instr_LG.dl2; xfer_index = RXY.offset / SIZEOF(void *); } else xfer_index = -1; } # elif defined(__hppa) { hppa_fmt_1 instr_LDX; union { int offset; struct { signed int high:19; unsigned int low:13; } instr_offset; } fmt_1; ptrs.instr = sf->mpc + 8; /* Past address load of compiler temp arg plus rtn call to load of xfer * table call with offset in delay slot */ memcpy(&instr_LDX, ptrs.instr, SIZEOF(instr_LDX)); if (((HPPA_INS_LDW >> HPPA_SHIFT_OP) == instr_LDX.pop) && (GTM_REG_XFER_TABLE == instr_LDX.b) && (R22 == instr_LDX.t)) { /* ldx of rtn address from xfer table */ fmt_1.instr_offset.low = instr_LDX.im14a; fmt_1.instr_offset.high = instr_LDX.im14b; xfer_index = fmt_1.offset / SIZEOF(void *); } else xfer_index = -1; } # elif defined(__ia64) { ia64_bundle xfer_ref_inst; /* Buffer to put built instruction into */ ia64_fmt_A4 adds_inst; /* The actual adds instruction computing xfer reference */ union { int offset; struct { # ifdef BIGENDIAN signed int sign:19; unsigned int imm6d:6; unsigned int imm7b:7; # else unsigned int imm7b:7; unsigned int imm6d:6; signed int sign:19; # endif } instr_offset; } imm14; ptrs.instr = sf->mpc + 16; /* Past address load of compiler temp arg */ # ifdef BIGENDIAN xfer_ref_inst.hexValue.aValue = GTM_BYTESWAP_64(((ia64_bundle *)ptrs.instr)->hexValue.aValue); xfer_ref_inst.hexValue.bValue = GTM_BYTESWAP_64(((ia64_bundle *)ptrs.instr)->hexValue.bValue); # else xfer_ref_inst.hexValue.aValue = ((ia64_bundle *)ptrs.instr)->hexValue.aValue; xfer_ref_inst.hexValue.bValue = ((ia64_bundle *)ptrs.instr)->hexValue.bValue; # endif adds_inst.hexValue = xfer_ref_inst.format.inst3; /* Extract instruction from bundle */ if ((8 == adds_inst.format.pop) && (2 == adds_inst.format.x2a) && (GTM_REG_XFER_TABLE == adds_inst.format.r3) && (IA64_REG_SCRATCH1 == adds_inst.format.r1)) { /* We have an xfer computation instruction. Find the offset to find which opcode */ imm14.instr_offset.imm7b = adds_inst.format.imm7b; /* Low order bits */ imm14.instr_offset.imm6d = adds_inst.format.imm6d; /* upper bits minus sign */ imm14.instr_offset.sign = adds_inst.format.sb; /* Sign bit propagated */ xfer_index = imm14.offset / SIZEOF(void *); } else xfer_index = -1; } # else # error Unsupported Platform # endif if (xf_exfunret == xfer_index) /* Need a QUIT with a non-alias return value */ return 1; else if (xf_exfunretals == xfer_index) /* Need a QUIT with an alias return value */ return 11; else { /* Something weird afoot - had parm block can can't locate EXFUNRET[ALS] opcode. This can happen if * a fatal error occurs during a call before the callee stack frame is actually pushed and we are * called during GTM_FATAL_ERROR.* file creation. Assert that this is the case, else, we just pretend * we didn't find a parm block.. */ assert(process_exiting); return 0; } } fis-gtm-V6.0-003/sr_port/dollar_quit.h0000644000032200000250000000102712201176155016522 0ustar librarygtc/**************************************************************** * * * Copyright 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef DOLLAR_QUIT_INCLUDE #define DOLLAR_QUIT_INCLUDE int dollar_quit(void); #endif fis-gtm-V6.0-003/sr_port/dollar_system_init.c0000644000032200000250000000357212201176155020111 0ustar librarygtc/**************************************************************** * * * Copyright 2002, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "startup.h" #include "dollar_system_init.h" #include "gtm_logicals.h" #include "io.h" #include "iosp.h" #include "stringpool.h" #include "trans_log_name.h" GBLREF mval dollar_system; GBLREF spdesc stringpool; void dollar_system_init(struct startup_vector *svec) { int4 status; mstr val, tn; char buf[MAX_TRANS_NAME_LEN]; error_def(ERR_LOGTOOLONG); error_def(ERR_TRNLOGFAIL); dollar_system.mvtype = MV_STR; dollar_system.str.addr = (char *)stringpool.free; dollar_system.str.len = STR_LIT_LEN("47,"); memcpy(stringpool.free, "47,", dollar_system.str.len); stringpool.free += dollar_system.str.len; val.addr = SYSID; val.len = STR_LIT_LEN(SYSID); if (SS_NORMAL == (status = TRANS_LOG_NAME(&val, &tn, buf, SIZEOF(buf), dont_sendmsg_on_log2long))) { dollar_system.str.len += tn.len; memcpy(stringpool.free, tn.addr, tn.len); stringpool.free += tn.len; } else if (SS_NOLOGNAM == status) { dollar_system.str.len += svec->sysid_ptr->len; memcpy(stringpool.free, svec->sysid_ptr->addr, svec->sysid_ptr->len); stringpool.free += svec->sysid_ptr->len ; } # ifdef UNIX else if (SS_LOG2LONG == status) rts_error(VARLSTCNT(5) ERR_LOGTOOLONG, 3, LEN_AND_LIT(SYSID), SIZEOF(buf) - 1); # endif else rts_error(VARLSTCNT(5) ERR_TRNLOGFAIL, 2, LEN_AND_LIT(SYSID), status); assert(stringpool.free < stringpool.top); /* it's process initialization after all */ return; } fis-gtm-V6.0-003/sr_port/dollar_system_init.h0000644000032200000250000000115512201176155020111 0ustar librarygtc/**************************************************************** * * * Copyright 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef DOLLAR_SYSTEM_INIT_H_INCLUDED #define DOLLAR_SYSTEM_INIT_H_INCLUDED void dollar_system_init(struct startup_vector *svec); #endif /* DOLLAR_SYSTEM_INIT_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/dollar_zlevel.c0000644000032200000250000000235012201176176017037 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "stack_frame.h" #include "dollar_zlevel.h" GBLREF stack_frame *frame_pointer; int dollar_zlevel() { int count; stack_frame *fp, *fpprev; for (count = 0, fp = frame_pointer; NULL != fp; fp = fpprev) { assert((fp < fp->old_frame_pointer) || (NULL == fp->old_frame_pointer)); fpprev = fp->old_frame_pointer; if (!(fp->type & SFT_COUNT)) continue; if (NULL == fpprev) { /* Next frame is some sort of base frame */ # ifdef GTM_TRIGGER if (fp->type & SFT_TRIGR) { /* Have a trigger baseframe, pick up stack continuation frame_pointer stored by base_frame() */ fpprev = *(stack_frame **)(fp + 1); continue; } else # endif break; /* Some other base frame that stops us */ } count++; } return (count); } fis-gtm-V6.0-003/sr_port/dollar_zlevel.h0000644000032200000250000000103012201176155017033 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __DOLLAR_ZLEVEL_H__ #define __DOLLAR_ZLEVEL_H__ int dollar_zlevel(void); #endif fis-gtm-V6.0-003/sr_port/dollarx.c0000644000032200000250000001352312201176155015647 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "io.h" #include "iottdef.h" #include "dollarx.h" #include "patcode.h" #ifdef UNICODE_SUPPORTED #include "gtm_icu_api.h" /* needed by *TYPEMASK* macros defined in gtm_utf8.h */ #include "gtm_utf8.h" LITREF UChar32 u32_line_term[]; #endif GBLREF uint4 *pattern_typemask; GBLREF boolean_t gtm_utf8_mode; void dollarx(io_desc *io_ptr, unsigned char *str, unsigned char *strtop) { unsigned char *str1, *strnext, *strstart, *strcursor, *strprev; int4 esc_level, char_width, total; boolean_t utf8_term, utf8_active, utf8_crlast = FALSE; wint_t curr_char; utf8_active = (gtm_utf8_mode UNICODE_ONLY(&& CHSET_M != io_ptr->ochset)) ? TRUE : FALSE; utf8_term = (utf8_active && tt == io_ptr->type) ? TRUE : FALSE; strstart = strcursor = str; if (io_ptr->write_filter) { esc_level = (io_ptr->write_filter & ESC_MASK); while (str < strtop) { if (START != io_ptr->esc_state) { assert (esc_level); str1 = iott_escape(str, strtop, io_ptr); str = str1; if ((FINI == io_ptr->esc_state) || ( BADESC == io_ptr->esc_state)) io_ptr->esc_state = START; continue; } if (!utf8_active) { curr_char = *str; strnext = str + 1; } #ifdef UNICODE_SUPPORTED else strnext = UTF8_MBTOWC(str, strtop, curr_char); #endif if (io_ptr->write_filter & CHAR_FILTER) { switch(curr_char) { case NATIVE_LF: if (!utf8_crlast) { /* otherwise CR case will have handled */ io_ptr->dollar.y++; if (io_ptr->length) io_ptr->dollar.y %= io_ptr->length; } else utf8_crlast = FALSE; str = strnext; break; case NATIVE_CR: io_ptr->dollar.x = 0; if (utf8_active && gtmsocket != io_ptr->type) { /* CR implies LF for Unicode except for socket which recongizes only NATIVE_LF as a terminator unicode or not. */ utf8_crlast = TRUE; io_ptr->dollar.y++; if (io_ptr->length) io_ptr->dollar.y %= io_ptr->length; } str = strstart = strcursor = strnext; break; case NATIVE_BS: /* if bs at beginning of string but x > 0 need image of line */ if (io_ptr->dollar.x > 0) #ifdef UNICODE_SUPPORTED if (utf8_term) { /* get previous character relative to strcursor and back it up */ if (strstart < strcursor) { for ( ; strstart < strcursor; strcursor = strprev) { UTF8_LEADING_BYTE((strcursor - 1), strstart, strprev); UTF8_MBTOWC(strprev, strtop, curr_char); if (U_ISPRINT(curr_char)) break; } strcursor = strprev; /* back up cursor */ GTM_IO_WCWIDTH(curr_char, char_width); io_ptr->dollar.x -= char_width; } } else #endif io_ptr->dollar.x--; str = strnext; utf8_crlast = FALSE; break; case NATIVE_FF: io_ptr->dollar.x = io_ptr->dollar.y = 0; str = strstart = strcursor = strnext; utf8_crlast = FALSE; break; case NATIVE_ESC: utf8_crlast = FALSE; if (esc_level) { str1 = iott_escape(str, strtop, io_ptr); str = str1; if ((FINI == io_ptr->esc_state) || ( BADESC == io_ptr->esc_state)) io_ptr->esc_state = START; continue; } /*** Caution: FALL THROUGH ***/ default: utf8_crlast = FALSE; if (!gtm_utf8_mode) { if (!(pattern_typemask[*str] & PATM_C)) io_ptr->dollar.x++; str++; } UNICODE_ONLY( else { assert(str < strtop); /* PATTERN_TYPEMASK macro relies on this */ if (utf8_term) { if (curr_char == u32_line_term[U32_LT_NL] || curr_char == u32_line_term[U32_LT_LS] || curr_char == u32_line_term[U32_LT_PS]) { /* a line terminator not handled above */ io_ptr->dollar.y++; if (io_ptr->length) io_ptr->dollar.y %= io_ptr->length; io_ptr->dollar.x = 0; strstart = strcursor = strnext; char_width = 0; } else GTM_IO_WCWIDTH(curr_char, char_width); if (0 < char_width) { io_ptr->dollar.x += char_width; strcursor = strnext; } } else if (U_ISPRINT(curr_char)) io_ptr->dollar.x++; str = strnext; } ) /* UNICODE_ONLY */ break; } } else if (NATIVE_ESC == *str) { assert(esc_level); str1 = iott_escape(str, strtop, io_ptr); str = str1; if ((FINI == io_ptr->esc_state) || (BADESC == io_ptr->esc_state)) io_ptr->esc_state = START; } else { #ifdef UNICODE_SUPPORTED if (utf8_term) { GTM_IO_WCWIDTH(curr_char, char_width); io_ptr->dollar.x += char_width; } else #endif io_ptr->dollar.x++; str = strnext; } } #ifdef UNICODE_SUPPORTED } else if (utf8_active) { for (total = 0; str < strtop; str = strnext) { strnext = UTF8_MBTOWC(str, strtop, curr_char); if (utf8_term) { /* count display width */ GTM_IO_WCWIDTH(curr_char, char_width); total += char_width; } else total++; /* count number of Unicode characters */ } io_ptr->dollar.x += total; #endif } else io_ptr->dollar.x += (unsigned int)(strtop - str); if (io_ptr->dollar.x > io_ptr->width && io_ptr->wrap) { io_ptr->dollar.y += (io_ptr->dollar.x / io_ptr->width); if (io_ptr->length) io_ptr->dollar.y %= io_ptr->length; io_ptr->dollar.x %= io_ptr->width; } } fis-gtm-V6.0-003/sr_port/dollarx.h0000644000032200000250000000113212201176155015645 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef DOLLARX_INCLUDED #define DOLLARX_INCLUDED void dollarx(io_desc *io_ptr, unsigned char *str, unsigned char *strtop); #endif /* DOLLARX_INCLUDED */ fis-gtm-V6.0-003/sr_port/dpgbldir.c0000644000032200000250000002324612201176155015774 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gbldirnam.h" #include "hashtab_mname.h" #include "iosize.h" #include "probe.h" #include "dpgbldir.h" #ifdef UNIX #include "gtmio.h" #elif defined(VMS) #include #else #error unsupported platform #endif #include "dpgbldir_sysops.h" #include "targ_alloc.h" #include "gtm_logicals.h" GBLREF gd_addr *gd_header; GBLREF gv_namehead *gv_target_list; LITREF char gde_labels[GDE_LABEL_NUM][GDE_LABEL_SIZE]; STATICDEF gdr_name *gdr_name_head; STATICDEF gd_addr *gd_addr_head; error_def(ERR_GDINVALID); /*+ Function: ZGBLDIR This function searches the list of global directory names for the specified names. If not found, it adds the new name to the list and calls GD_LOAD. A pointer to the global directory structure is returned, and the name entry is pointed at it. The global directory pointer is then returned to the caller. Syntax: gd_addr *zgbldir(mval *v) Prototype: ? Return: *gd_addr -- a pointer to the global directory structure Arguments: mval *v -- an mval that contains the name of the global directory to be accessed. The name may require translation. Side Effects: NONE Notes: NONE -*/ gd_addr *zgbldir(mval *v) { gd_addr *gd_ptr; gdr_name *name; mstr temp_mstr, *tran_name; for (name = gdr_name_head; name; name = (gdr_name *)name->link) if (v->str.len == name->name.len && !memcmp(v->str.addr, name->name.addr, v->str.len)) return name->gd_ptr; if (!v->str.len) { temp_mstr.addr = GTM_GBLDIR; temp_mstr.len = SIZEOF(GTM_GBLDIR) - 1; tran_name = get_name(&temp_mstr); } else tran_name = get_name(&v->str); gd_ptr = gd_load(tran_name); name = (gdr_name *)malloc(SIZEOF(gdr_name)); if (name->name.len = v->str.len) /* Note embedded assignment */ { name->name.addr = (char *)malloc(v->str.len); memcpy(name->name.addr, v->str.addr, v->str.len); } /* Store translated global directory name as well */ assert(tran_name->len); name->exp_name = *tran_name; /* free up memory allocated for mstr field in get_name. * memory allocated for addr field of the mstr is needed as it has been copied over to "name->exp_name" */ free(tran_name); if (gdr_name_head) name->link = (gdr_name *)gdr_name_head; else name->link = 0; gdr_name_head = name; gdr_name_head->gd_ptr = gd_ptr; return gd_ptr; } /*+ Function: GD_LOAD Syntax: gd_addr *gd_load(mstr *gd_name) Open a global directory file and verify that it is a valid GD. Determine if it has already been opened. If not, setup and initialize the GT.M structures used to access the GD based on the information in the file, enter in the linked list of global directories and return a pointer to it. If already opened, return a pointer to it. Prototype: ? Return: gd_addr * (all errors are signalled) Arguments: gd_name is the name of the file to be opened Side Effects: None Notes: A) While checking may be done earlier for duplicate names, unique identification of files can require OS specific operations useable only after the file is open, so checks must be done within this function for duplicate files. -*/ gd_addr *gd_load(mstr *v) { void *file_ptr; /* This is a temporary structure as the file open and manipulations are currently stubs */ header_struct *header, temp_head; gd_addr *table, *gd_addr_ptr; gd_binding *map, *map_top; gd_region *reg, *reg_top; uint4 t_offset, size; short i; file_ptr = open_gd_file(v); for (gd_addr_ptr = gd_addr_head; gd_addr_ptr; gd_addr_ptr = gd_addr_ptr->link) { /* if already open then return old structure */ if (comp_gd_addr(gd_addr_ptr, file_ptr)) { close_gd_file(file_ptr); return gd_addr_ptr; } } file_read(file_ptr, SIZEOF(header_struct), (uchar_ptr_t)&temp_head, 1); /* Read in header and verify is valid GD */ for (i = 0; i < GDE_LABEL_NUM; i++) { if (!memcmp(temp_head.label, gde_labels[i], GDE_LABEL_SIZE - 1)) break; } if (GDE_LABEL_NUM == i) { close_gd_file(file_ptr); rts_error(VARLSTCNT(8) ERR_GDINVALID, 6, v->len, v->addr, LEN_AND_LIT(GDE_LABEL_LITERAL), SIZEOF(temp_head.label), temp_head.label); } size = LEGAL_IO_SIZE(temp_head.filesize); header = (header_struct *)malloc(size); file_read(file_ptr, size, (uchar_ptr_t)header, 1); /* Read in body of file */ table = (gd_addr *)((char *)header + SIZEOF(header_struct)); table->local_locks = (struct gd_region_struct *)((UINTPTR_T)table->local_locks + (UINTPTR_T)table); table->maps = (struct gd_binding_struct *)((UINTPTR_T)table->maps + (UINTPTR_T)table); table->regions = (struct gd_region_struct *)((UINTPTR_T)table->regions + (UINTPTR_T)table); table->segments = (struct gd_segment_struct *)((UINTPTR_T)table->segments + (UINTPTR_T)table); table->end = (table->end + (UINTPTR_T)table); for (map = table->maps, map_top = map + table->n_maps; map < map_top; map++) { t_offset = map->reg.offset; map->reg.addr = (gd_region *)((char *)table + t_offset); assert(SIZEOF(map->name) == (MAX_MIDENT_LEN + 1)); map->name[MAX_MIDENT_LEN] = '\0'; /* reset 32nd byte to 0 since only 31 bytes are used in map. * this is necessary so "mid_len" can be invoked on this * as it expects a null-terminated string. */ } for (reg = table->regions, reg_top = reg + table->n_regions; reg < reg_top; reg++) { t_offset = reg->dyn.offset; reg->dyn.addr = (gd_segment *)((char *)table + t_offset); } table->link = gd_addr_head; gd_addr_head = table; fill_gd_addr_id(gd_addr_head, file_ptr); close_gd_file(file_ptr); table->tab_ptr = (hash_table_mname *)malloc(SIZEOF(hash_table_mname)); init_hashtab_mname(table->tab_ptr, 0, HASHTAB_NO_COMPACT, HASHTAB_NO_SPARE_TABLE); return table; } /*+ Function: GET_NEXT_GDR This function returns the next entry in the list of open global directories. If the input parameter is zero, the first entry is returned, otherwise the next entry in the list is returned. If the input parameter is not a member of the list, then zero will be returned. Syntax: gd_addr *get_next_gdr(gd_addr *prev) Prototype: ? Return: *gd_addr -- a pointer to the global directory structure Arguments: The previous global directory accessed; Side Effects: NONE Notes: NONE -*/ gd_addr *get_next_gdr(gd_addr *prev) { gd_addr *ptr; if (!prev) return gd_addr_head; for (ptr = gd_addr_head; ptr && ptr != prev; ptr = ptr->link) if (!GTM_PROBE(SIZEOF(*ptr), ptr, READ)) /* Called from secshr, have to check access to memory */ return NULL; if (ptr && GTM_PROBE(SIZEOF(*ptr), ptr, READ)) return ptr->link; return NULL; } /* Maintain list of regions for GTCM_SERVER */ void cm_add_gdr_ptr(gd_region *greg) { gd_addr *ga; ga = (gd_addr *)malloc(SIZEOF(gd_addr)); ga->end = 0; /* signifies a GT.CM gd_addr */ ga->regions = greg; ga->n_regions = 1; ga->link = gd_addr_head; gd_addr_head = ga; return; } void cm_del_gdr_ptr(gd_region *greg) { gd_addr *ga1, *ga2; for (ga1 = ga2 = gd_addr_head; ga1; ga1 = ga1->link) { if (ga1->regions == greg) { if (ga1 == gd_addr_head) gd_addr_head = ga1->link; else ga2->link = ga1->link; free(ga1); break; } ga2 = ga1; } return; } boolean_t get_first_gdr_name(gd_addr *current_gd_header, mstr *log_nam) { gdr_name *name; for (name = gdr_name_head; name; name = (gdr_name *)name->link) { if (name->gd_ptr == current_gd_header) { *log_nam = name->exp_name; return (TRUE); } } return FALSE; } void gd_rundown(void) /* Wipe out the global directory structures */ { gd_addr *gda_cur, *gda_next; gdr_name *gdn_cur, *gdn_next; for (gda_cur = gd_addr_head; NULL != gda_cur; gda_cur = gda_next) { gda_next = gda_cur->link; if (gda_cur->end) { gd_ht_kill(gda_cur->tab_ptr, TRUE); free(gda_cur->tab_ptr); /* free up hashtable malloced in gd_load() */ free(gda_cur->id); /* free up gd_id malloced in gd_load()/fill_gd_addr_id() */ free((char *)gda_cur - SIZEOF(header_struct)); /* free up global directory itself */ } else free(gda_cur); /* GT.CM gd_addr and hence header_struct wasn't malloced in cm_add_gdr_ptr */ } assert(NULL == gv_target_list); gd_header = gd_addr_head = (gd_addr *)NULL; for (gdn_cur = gdr_name_head; NULL != gdn_cur; gdn_cur = gdn_next) { gdn_next = (gdr_name *)gdn_cur->link; if (gdn_cur->name.len) free(gdn_cur->name.addr); free(gdn_cur); } gdr_name_head = (gdr_name *)NULL; } void gd_ht_kill(hash_table_mname *table, boolean_t contents) /* wipe out the hash table corresponding to a gld */ { ht_ent_mname *tabent, *topent; gvnh_reg_t *gvnh_reg; gv_namehead *gvt; if (contents) { for (tabent = table->base, topent = tabent + table->size; tabent < topent; tabent++) { if (HTENT_VALID_MNAME(tabent, gvnh_reg_t, gvnh_reg)) { gvt = gvnh_reg->gvt; gvt->regcnt--; if (!gvt->regcnt) targ_free(gvt); free(gvnh_reg); } } } free_hashtab_mname(table); /* We don't do a free(table) in this generic routine because it is called both by GT.M and GT.CM * and GT.CM retains the table for reuse while GT.M doesn't. GT.M fgncal_rundown() takes care of * this by freeing it up explicitly (after a call to ht_kill) in gd_rundown() [dpgbldir.c] */ return; } fis-gtm-V6.0-003/sr_port/dpgbldir.h0000644000032200000250000000201312201176155015766 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2008 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __DBGBLDIR_H__ #define __DBGBLDIR_H__ typedef struct gvt_container_struct { gvnh_reg_t *gvnh_reg; struct gvt_container_struct *next_gvtc; } gvt_container; boolean_t get_first_gdr_name(gd_addr *current_gd_header, mstr *log_nam); gd_addr *zgbldir(mval *v); gd_addr *gd_load(mstr *v); gd_addr *get_next_gdr(gd_addr *prev); mstr *get_name(mstr *ms); void cm_add_gdr_ptr(gd_region *greg); void cm_del_gdr_ptr(gd_region *greg); void *open_gd_file(mstr *v); void gd_rundown(void); void gd_ht_kill(struct hash_table_mname_struct *table, boolean_t contents); #endif fis-gtm-V6.0-003/sr_port/dse.h0000644000032200000250000001503112201176155014756 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __DSE_H__ #define __DSE_H__ error_def(ERR_DSEWCREINIT); #define PATCH_SAVE_SIZE 128 #define DSE_DMP_TIME_FMT "DD-MON-YEAR 24:60:SS" #define SPAN_START_BYTE 0x02 #define SPAN_BYTE_MAX 255 #define SPAN_BYTE_MIN 1 #define GET_CURR_TIME_IN_DOLLARH_AND_ZDATE(dollarh_mval, dollarh_buffer, zdate_mval, zdate_buffer) \ { /* gets current time in the mval "dollarh_mval" in dollarh format and in the mval "zdate_mval" in ZDATE format \ * the ZDATE format string used is DSE_DMP_TIME_FMT \ * the dollarh_buffer and zdate_buffer are buffers which the corresponding mvals use to store the actual time string \ */ \ GBLREF mval dse_dmp_time_fmt; \ GBLREF spdesc stringpool; \ LITREF mval literal_null; \ \ op_horolog(&dollarh_mval); /* returns $H value in stringpool */ \ assert(SIZEOF(dollarh_buffer) >= dollarh_mval.str.len); \ /* if op_fnzdate (called below) calls stp_gcol, dollarh_mval might get corrupt because it is not known to stp_gcol. \ * To prevent problems, copy from stringpool to local buffer */ \ memcpy(dollarh_buffer, dollarh_mval.str.addr, dollarh_mval.str.len); \ dollarh_mval.str.addr = (char *)dollarh_buffer; \ stringpool.free -= dollarh_mval.str.len; /* now that we've made a copy, we don't need dollarh_mval in stringpool */ \ op_fnzdate(&dollarh_mval, &dse_dmp_time_fmt, (mval *)&literal_null, (mval *)&literal_null, &zdate_mval); \ /* op_fnzdate() returns zdate formatted string in stringpool */ \ assert(SIZEOF(zdate_buffer) >= zdate_mval.str.len); \ /* copy over stringpool string into local buffer to ensure zdate_mval will not get corrupt */ \ memcpy(zdate_buffer, zdate_mval.str.addr, zdate_mval.str.len); \ zdate_mval.str.addr = (char *)zdate_buffer; \ stringpool.free -= zdate_mval.str.len; /* now that we've made a copy, we don't need zdate_mval in stringpool anymore */ \ } typedef struct { block_id blk; char *bp; gd_region *region; char *comment; short int ver; } save_strct; enum dse_fmt { CLOSED_FMT = 0, GLO_FMT, ZWR_FMT, OPEN_FMT }; /* Grab crit for dse* functions taking into account -nocrit if specified */ #define DSE_GRAB_CRIT_AS_APPROPRIATE(WAS_CRIT, WAS_HOLD_ONTO_CRIT, NOCRIT_PRESENT, CS_ADDRS, GV_CUR_REGION) \ { \ if (!WAS_CRIT) \ { \ if (NOCRIT_PRESENT) \ CS_ADDRS->now_crit = TRUE; \ else \ grab_crit(GV_CUR_REGION); \ WAS_HOLD_ONTO_CRIT = CS_ADDRS->hold_onto_crit; \ CS_ADDRS->hold_onto_crit = TRUE; \ } \ } /* Rel crit for dse* functions taking into account -nocrit if specified */ #define DSE_REL_CRIT_AS_APPROPRIATE(WAS_CRIT, WAS_HOLD_ONTO_CRIT, NOCRIT_PRESENT, CS_ADDRS, GV_CUR_REGION) \ { \ if (!WAS_CRIT) \ { \ assert(CS_ADDRS->hold_onto_crit); \ assert((TRUE == WAS_HOLD_ONTO_CRIT) || (FALSE == WAS_HOLD_ONTO_CRIT)); \ CS_ADDRS->hold_onto_crit = WAS_HOLD_ONTO_CRIT; \ if (NOCRIT_PRESENT) \ CS_ADDRS->now_crit = FALSE; \ else \ rel_crit(GV_CUR_REGION); \ } \ } #ifdef UNIX # define GET_CONFIRM(X, Y) \ { \ PRINTF("CONFIRMATION: "); \ FGETS((X), (Y), stdin, fgets_res); \ Y = strlen(X); \ } #else # define GET_CONFIRM(X, Y) \ { \ if(!cli_get_str("CONFIRMATION",(X),&(Y))) \ { \ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DSEWCINITCON); \ return; \ } \ } #endif #define GET_CONFIRM_AND_HANDLE_NEG_RESPONSE \ { \ int len; \ char confirm[256]; \ \ len = SIZEOF(confirm); \ GET_CONFIRM(confirm, len); \ if (confirm[0] != 'Y' && confirm[0] != 'y') \ { \ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DSEWCINITCON); \ return; \ } \ } #define DSE_WCREINIT(CS_ADDRS) \ { \ assert(CS_ADDRS->now_crit); \ if (CS_ADDRS->hdr->acc_meth == dba_bg) \ bt_refresh(CS_ADDRS, TRUE); \ db_csh_ref(CS_ADDRS, TRUE); \ send_msg_csa(CSA_ARG(CS_ADDRS) VARLSTCNT(4) ERR_DSEWCREINIT, 2, DB_LEN_STR(gv_cur_region)); \ } void dse_ctrlc_setup(void); int dse_data(char *dst, int *len); int dse_getki(char *dst, int *len, char *qual, int qual_len); int dse_is_blk_in(sm_uc_ptr_t rp, sm_uc_ptr_t r_top, short size); int dse_ksrch(block_id srch, block_id_ptr_t pp, int4 *off, char *targ_key, int targ_len); int dse_key_srch(block_id srch, block_id_ptr_t pp, int4 *off, char *targ_key, int targ_len); int dse_order(block_id srch, block_id_ptr_t pp, int4 *op, char *targ_key, short int targ_len, bool dir_data_blk); void dse_rmsb(void); void dse_ctrlc_handler(int sig); void dse_exhaus(int4 pp, int4 op); void dse_m_rest(block_id blk, unsigned char *bml_list, int4 bml_size, sm_vuint_ptr_t blks_ptr, bool in_dir_tree); void dse_rmrec(void); void dse_find_roots(block_id index); boolean_t dse_fdmp(sm_uc_ptr_t data, int len); boolean_t dse_fdmp_output(void *addr, int4 len); void dse_adrec(void); void dse_adstar(void); void dse_all(void); boolean_t dse_b_dmp(void); void dse_cache(void); void dse_chng_bhead(void); void dse_chng_fhead(void); void dse_chng_rhead(void); void dse_crit(void); void dse_dmp(void); void dse_eval(void); void dse_f_blk(void); void dse_f_free(void); void dse_f_key(void); void dse_f_reg(void); void dse_flush(void); int parse_dlr_char(char *src, char *top, char *dlr_subsc); void dse_help(void); void dse_version(void); void dse_integ(void); bool dse_is_blk_free (block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr); int4 dse_lm_blk_free(int4 blk, sm_uc_ptr_t base_addr); void dse_maps(void); void dse_open (void); void dse_close(void); void dse_over(void); void dse_page(void); boolean_t dse_r_dmp(void); void dse_range(void); void dse_rest(void); void dse_save(void); void dse_shift(void); void dse_wcreinit (void); sm_uc_ptr_t dump_record(sm_uc_ptr_t rp, block_id blk, sm_uc_ptr_t bp, sm_uc_ptr_t b_top); void dse_dmp_fhead (void); void dse_ctrlc_handler(int sig); void dse_remove(void); #endif fis-gtm-V6.0-003/sr_port/dse.hlp0000644000032200000250000031255612201176155015326 0ustar librarygtc1 Operations Operations The GT.M Database Structure Editor, DSE, is primarily a tool for authorized GT.M consultants to examine and, under unusual circumstances, repair GT.M Database Structure (GDS) databases. With DSE, it is possible to see and change most of the attributes of a GT.M database. DSE gives all possible control over a database and therefore, it may cause irreparable damage when used without knowing the consequences. Therefore, you unless you have extensive experience, you should always get guidance from FIS or an equivalently knowledgeable support resource before running any DSE command that changes any attribute of any production database or other database you value. However, you can use those DSE commands that let you see the attributes of your database for collecting database metrics and monitoring status. GT.M installation procedure places the DSE utility program in a directory specified by the environment variable gtm_dist. Invoke DSE using the "dse" command at the shell prompt. If this does not work, consult your system manager to investigate setup and file access issues. Example: $gtm_dist/dse File/usr/name/mumps.dat Region DEFAULT DSE> DSE displays the DSE> prompt. You may also specify a command when entering DSE. By default, DSE starts with the region that stands first in the list of regions arranged in alphabetical order. In the above example, the first region is DEFAULT. You may also specify a command when entering DSE. Example: $gtm_dist/dse dump -fileheader This command displays the fileheader of the region that stands first in the list of regions arranged in alphabetical order and then returns to the shell prompt. To look at other regions, at the DSE prompt you must first issue a FIND -REGION= command. As previously mentioned, DSE provides control over most of the attributes of your database. With DSE, it is possible to examine them and,with a few exceptions, change them. All DSE commands are divided into two categories-Change commands and Inquiry commands. Change commands allow you to modify the attribute of your database, in most cases without any warning or error. As the low level tool of last resort, Change commands allow you to take certain actions that can cause extensive damage when undertaken without an extensive understanding of the underlying data structures on disk and in memory and with an imperfect understanding of the commands issued. Do not use the Change commands unless you know exactly what you are doing and have taken steps to protect yourself against mistakes, both inadvertent and resulting from an incomplete understanding of the commands you issue. Change commands are not required for normal operation, and are usually only used under the direction of FIS support to recover from the unanticipated consequences of failures not adequately planned for (for example, you should configure GT.M applications such that you never need a Change command to recover from a system crash). Inquiry commands let you see the attributes of your database. You may frequently use the inquiry commands for collecting your database metrics and status reporting. The list of Change commands is as follows: AD[D] AL[L] B[UFFER _FLUSH] CH[ANGE] CR[ITICAL] REM[OVE] RES[TORE] SH[IFT] W[CINIT] OV[ERWRITE] M[APS] -BU[SY] -F[REE] -M[ASTER] -R[ESTORE_ALL] The list of Inquiry commands is as follows: CL[OSE] D[UMP] EV[ALUATE] EX[IT] F[IND] H[ELP] I[NTEGRIT] M[APS] -BL[OCK] OP[EN] P[AGE] RA[NGE] SA[VE] SP[AWN] Although DSE can operate concurrently with other processes that access the same database file, FIS strongly recommends using DSE in standalone mode when using Change commands. Some DSE operations can adversely impact the database when they occur during active use of the database. Other DSE operations may be difficult to perform in a logically sound fashion because a DSE operator works on a block at a time, while normal database operations update all related blocks almost simultaneously. **Caution** When DSE attaches to a database with a version that does not match the DSE version, DSE issues an informational message and continues. At this point, you should exit DSE and find the version of DSE that matches the database. You should continue after this warning if and only if you are certain that the DSE is indeed from the GT.M version that has the database open (and hence the error results from a damaged database file header or shared memory that you intend to repair, following instructions from FIS). Use the DSE EXIT, or QUIT command to leave DSE. 1 Commands Commands The format for DSE commands is: DSE> command [-qualifier[...]] [object[,...]] DSE interprets all numeric input as hexadecimal, except for time values, the values for the following qualifiers when used with CHANGE -FILEHEADER: -BLK_SIZE=, DECLOCATION=, -KEY_MAX_SIZE=, -RECORD_MAX_SIZE, -REFERENCE_COUNT=, -TIMERS_PENDING and -WRITES_PER_FLUSH, and the value for -VERSION= when used with the REMOVE and RESTORE commands. These conventions correspond to the displays provided by DSE and by MUPIP INTEG. 2 ADD ADD Adds a record to a block. The format of the ADD command for blocks with a level greater than zero (0) is: ADD [-B[LOCK]=[block] {-OFFSET=offset|-RECORD=record} -STAR -POINTER=block or ADD [-B[LOCK]=[block] {-OFFSET=offset|-RECORD=record} -KEY=key -POINTER=pointer The format of the ADD command for level 0 blocks is: ADD [-B[LOCK]=[block] {-OFFSET=offset|-RECORD=record} -KEY=key -DATA=string The ADD command requires either the -OFFSET or -RECORD qualifier to position the record in the block, and either the -KEY or the -STAR qualifier to define the key for the block. The -STAR qualifier is invalid at level 0 (a data block). The ADD command requires the -DATA qualifier at level 0 or the -POINTER qualifier at any other level to provide record content. 3 Qualifiers Qualifiers -B[LOCK]=block-number Specifies the block to receive the new record. On commands with no -BLOCK= qualifier, DSE uses the last block handled by a DSE operation. When no block has been accessed, that is, on the first block-oriented command, DSE uses block one (1). -D[ATA]=string Specifies the data field for records added to a data block. Use quotation marks around the string and escape codes of the form \a\b, where "a" and "b" are hexadecimal digits representing non-printing characters. \\ translates to a single backslash. \'\' translates to a NULL value. Incompatible with: -STAR,-POINTER -K[EY]=key Specifies the key of the new record. Enclose M-style global references, including the leading caret symbol (^), in quotation marks (" "). Incompatible with: -STAR -O[FFSET]=offset Adds the new record at the next record boundary after the specified offset. Incompatible with: -RECORD, -STAR -P[OINTER]=pointer Specifies the block pointer field for records added to an index block. The -POINTER qualifier cannot be used at level 0. Note this means that to add pointers at level 0 of the Directory Tree you must specify a string of bytes or temporarily change the block level. Incompatible with: -DATA -R[ECORD]=record-number Specifies a record number of the new record. Incompatible with: -OFFSET,-STAR -S[TAR] Adds a star record (that is, a record that identifies the last record in an indexed block) at the end of the specified block. The -STAR qualifier cannot be used at level 0. Incompatible with: -DATA,-KEY,-OFFSET,-RECORD 3 Examples Examples DSE>add -block=6F -record=57 -key="^Capital(""Mongolia"")" -data="Ulan Bator" This command adds a new record with key ^Capital("Mongolia") at the specified location. Note that this command is applicable to level 0 blocks only. Example: DSE>add -star -bl=59A3 -pointer=2 This command adds a star record in block 59A3. Note that this command is applicable to blocks > level 0. Example: DSE>add -block=3 -record=4 -key="^Fruits(4)" -data="Grapes" Suppose your database has 3 global nodes -- ^Fruits(1)="Apple", ^Fruits(2)="Banana", and ^Fruits(3)="Cherry", then the above command adds a new node ^Fruits(4)="Grapes" at record 4. Note that this command is applicable to level 0 blocks only. The interpreted output as a result of the above command looks like the following: Block 3 Size 4B Level 0 TN 6 V5 Rec:1 Blk 3 Off 10 Size 14 Cmpc 0 Key ^Fruits(1) 10 : | 14 0 0 0 46 72 75 69 74 73 0 BF 11 0 0 41 70 70 6C 65| | . . . . F r u i t s . . . . . A p p l e| Rec:2 Blk 3 Off 24 Size D Cmpc 8 Key ^Fruits(2) 24 : | D 0 8 0 21 0 0 42 61 6E 61 6E 61 | | . . . . ! . . B a n a n a | Rec:3 Blk 3 Off 31 Size D Cmpc 8 Key ^Fruits(3) 31 : | D 0 8 0 31 0 0 43 68 65 72 72 79 | | . . . . 1 . . C h e r r y | Rec:4 Blk 3 Off 3E Size D Cmpc 8 Key ^Fruits(4) 3E : | D 0 8 8 41 0 0 47 72 61 70 65 73 | | . . . . A . . G r a p e s | Example: $dse add -star -bl=1 -pointer=2 This command adds a star record in block 1. Note that this command is applicable to blocks > Level 0. Example: $ dse add -block=4 -key="^Vegetables" -pointer=7 -offset=10 This command creates a block with key ^Vegetables pointing to block 7. Example: DSE> add -record=2 -key="^foo" -data=\'\' This example adds a new node (set ^foo="") as the second record of the current database block. 2 ALL ALL Applies action(s) specified by a qualifier to all GDS regions defined by the current global directory. The format of the ALL command is: AL[L] -B[UFFER_FLUSH] -C[RITINIT] -[NO]F[REEZE] -O[VERRIDE]] -REF[ERENCE] -REL[EASE] -REN[EW] -S[EIZE] -W[CINIT] o This is a very powerful command; use it with caution. o Be especially careful if you have an overlapping database structure (for example, overlapping regions accessed from separate application global directories). o If you use this type of database structure, you may need to construct special Global Directories that exclude overlapped regions to use with DSE. 3 Qualifiers Qualifiers -BUFFER_FLUSH Flushes to disk the file header and all pooled buffers for all regions of the current global directory. Incompatible with: -RENEW -C[RITINIT] Initializes critical sections for all regions of the current directory. Incompatible with: -RENEW, -RELEASE, -SIEZE **Caution** Never use CRITINIT while concurrent updates are in progress as doing so may damage the database. -[NO]F[REEZE] Freezes or prevents updates all regions of the current global directory. o The FREEZE qualifier freezes all GDS regions except those previously frozen by another process . Regions frozen by a particular process are associated with that process . o A frozen region may be unfrozen for updates in one of two ways: The process which froze the region may unfreeze it with the -NOFREEZE qualifier; or another process may override the freeze in conjunction with the -OVERRIDE qualifier. o By default, the -NOFREEZE qualifier unfreezes only those GDS regions that were previously frozen by a process . Once a region is unfrozen, it may be updated by any process .To unfreeze all GDS regions of the Global Directory, use the -OVERRIDE qualifier. o DSE releases any FREEZE it holds when it exits, therefore, use the same DSE invocation or SPAWN to perform operations after executing the ALL -FREEZE command. Incompatible with: -RENEW -O[VERRIDE] Overrides the ALL -FREEZE or ALL -NOFREEZE operation. When used with -NOFREEZE, -OVERRIDE unfreezes all GDS regions, including those frozen by other users. When used with -FREEZE, -OVERRIDE freezes all GDS regions, including those frozen by other processes associating all such freezes with the current process. The current process must then use -NOFREEZE to unfreeze the database; any other process attempting a -NOFREEZE should also have to include the -OVERRIDE qualifier. Meaningful only with: [NO]FREEZE -REF[ERENCE] Resets the reference count field to 1 for all regions of the current global directory. o A Reference count is a file header element field that tracks how many processes are accessing the database with read/write permissions. o This qualifier is intended for use when DSE is the only process attached to the databases of the curent global directory. Using it when there are other users attached produces an incorrect value. Incompatible with: -RENEW -REL[EASE] Releases critical sections for all regions of the current global directory. Incompatible with: -CRITINIT, -RENEW, -SEIZE -REN[EW] Reinitializes the critical sections (-CRITICAL) and buffers (-WCINIT), resets reference counts (-REFERENCE_COUNT) to 1, and clears freeze (-NOFREEZE) for all regions of the current global directory . o -RENEW requires confirmation. o The RENEW action will cause all current accessors of the affected database regions to receive a fatal error on their next access attempt. o This operation is dangerous, drastic, and a last resort if multiple database have hangs that have not yielded to other resolution attempts; there is almost never a good reason to use this option. -S[EIZE] Seizes the critical section for all regions of the current global directory. The -SEIZE qualifier is useful when you encounter a DSEBLKRDFAIL error, generated when DSE is unable to read a block from the database. Incompatible with: -RENEW, -RELEASE, -CRITINIT -W[CINIT] Reinitializes the buffers for all regions of the current global directory. -WCINIT requires confirmation. **Caution** This operation is likely to cause database damage when used while concurrent updates are in progress. Incompatible with: -RENEW 3 Examples Examples Example: DSE> all flush -buffer_flush This command flushes the file header and cache buffers to disk for all regions. Example: DSE> ALL -CRITINIT This command initializes critical sections for all regions of the current directory. Example: DSE> ALL -FREEZE DSE> SPAWN "mumps -dir" The first command freezes all regions of the current global directory. The second command creates an child (shell) process and executes the "mumps -dir" command. Then type S ^A=1 at GTM prompt. Notice that the command hangs because of the DSE FREEZE in place. Example: DSE> ALL -NOFREEZE -OVERRIDE This command removes the FREEZE on all current region including the FREEZE placed by other users. Example: DSE> ALL -REFERENCE This command sets the reference count field in the file header(s) to 1. Example: DSE> ALL -RELEASE This command releases critical sections owned by the current process for all regions of the current global directory. Example: DSE> ALL -RENEW This command reinitializes critical sections, buffers, resets the reference count to 1, and clears freeze for all regions of the current global directory. Example: DSE> ALL -SEIZE This command seizes all critical sections for all regions of the current global directory. Example: DSE> WCINIT This command reinitializes the buffers for all regions of the current global directory. 2 Buffer_flush Buffer_flush Flushes the file header and the current region's buffers to disk. The format of the BUFFER_FLUSH command is: B[UFFER_FLUSH] The BUFFER_FLUSH command has no qualifiers. 2 CHange CHange The CHANGE command changes fields of a block, file, or record header. The format of the CHANGE command is: CH[ANGE] The CHANGE command either has a -FILEHEADER qualifier or an implicit or explicit -BLOCK qualifier, plus one or more of their associated qualifiers, to define the target of the change. -BL[OCK]=block-number and one or more of the following qualifiers: -BS[IZ]=block-size -L[EVEL]=level -TN[=transaction-number] -OF[FSET]=offset -RE[CORD]=record-number -CM[PC]=compression-count -RS[IZ]=record-size or -F[ILEHEADER] and one or more of the following qualifiers: -AB[ANDONED_KILLS]=value -AVG_BLKS_READ=Average-blocks-read -B_B[YTESTREAM]=transaction-number -B_C[OMPREHENSIVE]=transaction-number -B_D[ATABASE]=transaction-number -B_I[NCREMENTAL]=transaction-number -B_R[ECORD]=transaction-number -BLK_SIZE=block-size -BLO[CKS_FREE]=free-blocks -CU[RRENT_TN]=transaction-number -COM[MITWAIT_SPIN_COUNT]=boolean -DEC[LOCATION]=value -DEF[_COLLATION]=value -ENCRYPTION_HASH -FL[USH_TIME][=delta-time] -FR[EEZE]=value -FU[LLY_UPGRADED]=boolean -GV[STATSRESET] -HARD_SPIN_CPUNT=Mutex-hard-spin-sount -[HEXLOCATION]=value -INT[ERRUPTED_RECOV]=boolean -JNL_YIELD_LIMIT=journal-yeild-limit -KE[Y_MAX_SIZE]=key-max-size -KI[LL_IN_PROG]=value -M[ACHINE_NAM]=value -N[ULL_SUBSCRIPTS]=value -NO[CRIT] -OV[ERRIDE] -Q[DBRUNDOWN] -RC_SRV_COUNT -RE_READ_TRIGGER=read-trigger -REC[ORD_MAX_SIZE]=record-max-size -REF[ERENCE_COUNT]=reference-count -REG[_SEQNO]=sequence-number -RESERVED_BYTES=reserved-bytes -SLEEP_SPIN_COUNT=mutex-sleep-spin-count -SPIN_SLEEP_TIME=mutex-sleep-time -STRM_NUM=stream-number STRM_REG_SEQNO=hexa -TIM[ERS_PENDING]=integer -TO[TAL_BLKS]=total-blocks -TR[IGGER_FLUSH]=trigger-flus -UPD_RESERVED_AREA=reserved- area -UPD_WRITER_TRIGGER_FACTOR=trigger-factor -W[RITES_PER_FLUSH]=writes-per-flush -WAIT_DISK=wait-disk -Zqgblmod_S[EQNO]=sequence-number -Zqgblmod_T[rans]=sequence-number 3 BLock_Qualifiers BLock Qualifiers This section describes -BLOCK and all of its qualifiers. -BL[OCK]=block_number Specifies the block to modify. The -BLOCK qualifier is incompatible with the -FILEHEADER qualifier and all qualifiers related to -FILEHEADER. -BLOCK is the default qualifier. On commands with neither a -BLOCK nor a -FILEHEADER qualifier, DSE uses the last block handled by a DSE operation. When no block has been accessed, that is, on the first block-oriented command, DSE uses block one (1). Incompatible with: -FILEHEADER and qualifiers used with -FILEHEADER The following qualifiers operate on a block header. -BS[IZ]=block_size Changes the block size field of the specified block. o block_size is in hexadecimal form. o Decreasing the block size can result in loss of existing data. **Note** The block size must always be less than or equal to the block size in the file header. Use only with: -BLOCK, -LEVEL, -TN -L[EVEL]=level Changes the level field for the specified block. **Note** DSE lets you change the level of a bitmap block to -1 (the value of the level for a bitmap block) when the bitmap level gets corrupted and takes on an arbitrary value. Note that you should specify -1 in hexadecimal form, that is, FF. Use only with: -BLOCK, -BSIZ, -TN Example: DSE >change -level=FF -TN[=transaction_number] Changes the transaction number for the current block. o When a CHANGE command does not include a -TN=, DSE sets the transaction number to the current transaction number. o Manipulation of the block transaction number affects MUPIP BACKUP -BYTESTREAM, and -ONLINE. Use only with: -BLOCK, -BSIZ, -LEVEL -OF[FSET]=offset Specifies the offset, in bytes, of the target record within the block. If the offset does not point to the beginning of a record, DSE rounds down to the last valid record start (for example, CHANGE -OFFSET=10 starts at -OFFSET=A, if that was the last record). Use only with: -BLOCK, -CMPC, and -RSIZ. -RE[CORD]=record_number Specifies the record number of the target record. Use only with: -BLOCK, -CMPC, and -RSIZ. -CM[PC]=compression_count Change the compression count field of the specified record. o The compression count specifies the number of bytes at the beginning of a key that are common to the previous key in the same block. o Because compression counts propagate from the "front" of the block, this can potentially change the keys of all records following it in the block. If the goal is to change only a single record, it may be preferable to add a new record and remove the old one. Use only with: -BLOCK, -RECORD, -OFFSET, -RSIZE -RS[IZ]=record_size Changes the record size field of the specified record. **Caution** Changing -RSIZ impacts all records following it in the block. Use only with: -BLOCK, -RECORD, -CMPC, -OFFSET Example: DSE> change -record=3 -rsiz=3B -block=2 This command changes the record size of record 3 block 2 to 59 (Hex: 3B) bytes. 3 FIleheader_Qualifiers FIleheader Qualifiers This section describes the -FILEHEADER qualifier and the other qualifiers that operate on a file header. -FI[LEHEADER] Modifies a file header element that you specify with an associated qualifier. Incompatible with: -BSIZ, -CMPC, -TN, -LEVEL, -OFFSET, -RECORD, -RSIZ -AB[ANDONED_KILLS]=value Changes the value of the Abandoned Kills field. The value can be "NONE" or a positive integer. Use only with: -FILEHEADER; decimal -BLK[_SIZE]=block_size Changes the decimal block size field of the current file. o DSE does not allow you to change the block size to any arbitrary value. It always rounds the block size to the next higher multiple of 512. o Use the CHANGE -BLK_SIZE qualifier only upon receiving instructions from FIS and only in conjunction with the -FILEHEADER qualifier. This DSE command cannot change the working block size of a database and is useful only under very limited and extrordinary circumstances. If you need to change the block size on a database file, unload the data with MUPIP EXTRACT (or an appropriate alternative), change the global directory with GDE to specify the new block size, recreate the database with MUPIP CREATE and reload the data with MUPIP LOAD (or appropriate alternative). Use only with: -FILEHEADER -BLO[CKS_FREE]=free blocks Changes the free blocks field of the current file. Use this to correct a value that MUPIP INTEG reports as needing a correction, but note that the "correct" value reported by INTEG may go out-of-date with the next update. It may be necessary to calculate a delta value from the INTEG report, FREEZE the region with DSE, DUMP the current -FILEHEADER value, then apply the delta and CHANGE the -BLOCKS_FREE, and finally turn -OFF the FREEZE. Use only with: -FILEHEADER -B[YTESTREAM]=transaction_number Changes the transaction number in the file header of the last incremental backup to the value specified. Use this qualifier only in conjunction with the -FILEHEADER qualifier. For compatibility issues with priot versions, this can still be specified as -B_COMPREHENSIVE. -D[ATABASE]=transaction_number Changes the transaction number in the file header of the last comprehensive backup to the value specified. Use this qualifier only in conjunction with the -FILEHEADER qualifier. For compatibility issues with prior versions, this can still be specified as -B_COMPREHENSIVE. -B_R[ECORD]=transaction_number Changes the transaction number in the file header field that maintains this information about the last -RECORD backup. -CO[RRUPT_FILE]=boolean Indicates whether or not a region completed a successful recovery with the MUPIP JOURNAL -RECOVER command. Possible values are: T[RUE] or F[ALSE]. Changing this flag does not correct or cause database damage. When CORRUPT_FILE is set to TRUE, the DSE DUMP command displays a message like the following: %GTM-W-DBFLCORRP, /home/gtmnode1/mumps.dat Header indicates database file is corrupt **Caution** After a CHANGE -FILEHEADER -CORRUPT=TRUE, the file is unavailable to future GT.M access other than DSE. Under normal conditions, there should never be a need to change this flag manually. A MUPIP SET -PARTIAL_BYPASS_RECOV sets this flag to false. Use only with: -FILEHEADER -COM[MITWAIT_SPIN_COUNT]=value Specifies the number of times a GT.M process waiting for control of a block to complete a block update should spin before yielding the CPU when GT.M runs on SMP machines. When run on a uniprocessor system, GT.M ignores this parameter. On SMP systems, when a process needs a critical section that another process has, if critical sections are short (as they are by design in GT.M), spinning a little with the expectation that the process with the critical section will release it shortly provides a way to enhance performance at the cost of increased CPU usage. Eventually, a process awaiting a critical section yields the CPU if spinning for a little does not get it the needed critical section. Note that on heavily loaded systems, increasing COMMITWAIT_SPIN_COUNT may not trade off CPU for throughput, but may instead degrade both. If you set the COMMITWAIT_SPIN_COUNT to 0, the waiting process performs a sequence of small sleeps instead of the spins or yields. The default value is 16. Use only with: -FILEHEADER -CU[RRENT_TN]=transaction_number Changes the current transaction number for the current region. o Raising the -CURRENT_TN can correct "block transaction number too large" errors o This qualifier has implications for MUPIP BACKUP -INCREMENTAL and -ONLINE. o Used with the -BLOCK qualifier, CURRENT_TN places a transaction number in a block header. Use only with: -FILEHEADER -DECLOCATION Specifies an offset with the file header. If -VALUE is specified, GT.M puts it at that location. Use only with: -FILEHEADER; decimal -E[NCRYPTION_HASH] Changes the hash of the password stored in the database file header if and when you change the hash library. **Caution** An incorrect hash renders the database useless. Use only with: -FILEHEADER -FL[USH_TIME][=delta_time] Changes the flush_time default interval (in delta_time). o The time entered must be between zero and one hour. Input is interpreted as decimal. o A -FLUSH_TIME with no value resets the -FLUSH_TIME to the default value (one second for BG and 30 seconds for MM). o The units of delta_time are hours:minutes:seconds:centi-seconds (hundredths of a second). For example, to change the flush time interval to a second, delta_time would be 00:00:01:00. To change it to 30 minutes, delta_time would be 00:30:00:00. Valid values for the qualifier are one centi-second to one hour. Use only with: -FILEHEADER -FR[EEZE]=value Sets availability of the region for update. Possible values are: T[RUE] or F[ALSE]. Use to "freeze" (disable database writes) or "unfreeze" the database. Use only with: -FILEHEADER DSE releases -FREEZE when it EXITs. To hold the database(s), CHANGE -FILEHEADER -FREEZE=TRUE and then SPAWN to perform other operations. -FU[LLY_UPGRADED]=boolean Sets a flag that indicates whether or not the database was fully upgraded from V4 to V5 database format.. The value is either T[RUE] or F[ALSE]. Use only with: -FILEHEADER -GV[STATSRESET] Resets all the database file header global access statistics to 0. Note that this erases all statistics previously accumulated in the database file header. Use only with: -FILEHEADER -HEXLOCATION Specifies an offset with the file header. If -VALUE is specified, GT.M puts it at that location. Use only with: -FILEHEADER; hexadecimal -INT[ERRUPTED_RECOV]=boolean Sets a flag that indicates whether or not a recovery with the MUPIP JOURNAL -RECOVER command was interrupted. The value is either T[RUE] or F[ALSE]. Use only with: -FILEHEADER -K[EY_MAX_SIZE]=key_max_size Changes the decimal value for the maximum allowable key size. Reducing KEY_MAX_SIZE can restrict access to existing data and cause GT.M to report errors. Do not create incompatible key and record sizes. Before permanently changing the key size using DSE, use GDE to check that the appropriate Global Directory contains the same key size for the region. This prepares for future MUPIP CREATEs and performs a consistency check on the key and record size values. Use only with: -FILEHEADER; decimal -KI[LL_IN_PROG]=value Changes the value of the KILLs in progress field. The value can be "NONE" or a positive integer. Use only with: -FILEHEADER; decimal -N[ULL_SUBSCRIPTS]=value Controls whether GT.M accepts null subscripts in database keys. o value can either be T[RUE], F[ALSE], ALWAYS, NEVER, or EXISTING. See GDE book for more information on these values of null_subscript. o Prohibiting null subscripts can restrict access to existing data and cause GT.M to report errors. o The default value is never. o DSE cannot change the null subscript collation order. Instead, use GDE to change the null subscript collation order, MUPIP EXTRACT the current content, MUPIP CREATE the database file(s) with the updated collation and MUPIP LOAD the content. Use only with: -FILEHEADER -OV[ERRIDE] Releases or "steals" a FREEZE owned by another process. Use only with: -FREEZE -[NO]Q[DBRUNDOWN] Sets a flag that indicates whether or not the database is enabled for quick rundown. The default value is -NOQDBRUNDOWN. -REC[ORD_MAX_SIZE]=record_max_size Changes the decimal value for the maximum allowable record size. Use the -RECORD_MAX_SIZE qualifier only in conjunction with the -FILEHEADER qualifier. Reducing RECORD_MAX_SIZE can restrict access to existing data and cause GT.M to report errors. Do not create incompatible key and record sizes. Before making a permanent change to the records size using DSE, use GDE to check that the appropriate Global Directory contains the same record size for the region. This prepares for future MUPIP CREATEs and performs a consistency check on the key and record size values. -REF[ERENCE_COUNT]=reference_count Sets a field that tracks how many processes are accessing the database with read/write permissions. MUPIP INTEG and DSE use decimal numbers for -REFERENCE_COUNT. To accurately determine the proper reference count, restrict CHANGE -FILEHEADER -REFERENCE_COUNT to the case where the process running DSE has exclusive (standalone) access to the database file. When DSE has sole access to a database file the -REFERENCE_COUNT should be one (1). This is an informational field and does not have any effect on processing. -REG[_SEQNO]=sequence-number In an LMS environment, this sets the "Region Seqno" field. -RESYNC_S[EQNO]=sequence-number In an LMS environment, this sets the "Resync Seqno" field. -RESYNC_T[N]=sequence-number In an LMS environment, this sets the "Resync transaction" field. -STRM_NUM=stream-number -STRM_R[EG_SEQNO]=str_num's_region_sequence_number Changes the Stream and its Reg Seqno. Use -STRM_NUM and -STRM_REG_SEQNO together as part of the same CHANGE -FILEHEADER command. Use only with: -FILEHEADER; hexa -TI[MERS_PENDING]=timers_pending -TI[MERS_PENDING]=timers_pending Sets a field that tracks the number of processes considering a timed flush. Proper values are 0, 1, and 2. Use the CHANGE -TIMERS_PENDING qualifier only upon receiving instructions from FIS. Use only with: -FILEHEADER; decimal -TO[TAL_BLKS]=total_blocks Changes the total blocks field of the current file. Use only with: -FILEHEADER; decimal **Caution** The total blocks field should always reflect the actual size of the database. Change this field only if it no longer reflects the database size. -TR[IGGER_FLUSH]=trigger_flush Sets the decimal value for the triggering threshold, in buffers, for flushing the cache-modified queue. Use the CHANGE -TRIGGER_FLUSH qualifier only upon receiving instructions from FIS, and only in conjunction with the -FILEHEADER qualifier. -WR[ITES_PER_FLUSH]=writes_per_flush Set the decimal number of block to write in each flush. The default value is 7. Use only with -FILEHEADER 3 Examples Examples Example: DSE> change -block=3 -bsiz=400 This command changes the size of block 3 to 1024 bytes. Example: DSE> change -block=4 -tn=10000 This command changes sets the transaction number to 65536 (Hex: 10000) for block 4. Example: DSE> change -block=2 -record=4 -CMPC=10 -key="^CUS(""Jones,Vic"")" This command changes the compression count of the key ^CUS(Jones,Vic) to 10. It is assumed that the key CUS(Jones,Tom) already exists. The following table illustrates how GT.M calculates the value of CMPC in this case. +----------------------------------------------------------------+ | RECORD KEY | COMPRESSION COUNT | RESULTING KEY in Record | |------------------+-------------------+-------------------------| | CUS(Jones,Tom) | 0 | CUS(Jones,Tom) | |------------------+-------------------+-------------------------| | CUS(Jones,Vic) | 10 | Vic) | |------------------+-------------------+-------------------------| | CUS(Jones,Sally) | 10 | Sally) | |------------------+-------------------+-------------------------| | CUS(Smith,John) | 4 | Smith,John) | +----------------------------------------------------------------+ Example: DSE> dump -fileheader This command displays fields of the file header. Example: DSE> change -fileheader -blk_siz=2048 This command changes the block size field of the fileheader to 2048 bytes. The block field must always be a multiples of 512 bytes. Example: DSE> change -fileheader -blocks_free=5B This command changes the blocks free fields of the file header to 91 (Hex: 5B). Example: Example: DSE> change -fileheader -b_record=FF This command sets the RECORD backup transaction to FF. Example: DSE> change -fileheader corrupt_file=FALSE This command sets the CORRUPT_FILE field to false. Example: DSE> change -fileheader -current_tn=1001D1BF817 This command changes the current transaction number to 1100000000023 (Hex: 1001D1BF817). After you execute this command, subsequent transaction numbers will be greater than 1001D1BF817. Example: DSE> change -fileheader -flush_time=00:00:02:00 This command changes the flush time field of the file header to 2 seconds. Example: DSE> change -fileheader -freeze=true This command makes the default region unavailable for updates. Example: DSE> change -fileheader -key_max_size=20 This command changes the maximum key size to 20. Note that the default max key size is 64. Example: DSE> CHANGE -FILEHEADER -NULL_SUBSCRIPTS="EXISTING" This command changes the Null Subscripts field of the file header to EXISTING. Note that DSE cannot change the null subscript collation order. See GDE book for more information on changing the null subscript collation. Example: DSE> change -fileheader -reserved_bytes=8 -record_max_size=496 This command sets the maximum record size as 496 for the default region. Example: DSE> change -fileheader -reference_count=5 This command sets the reference count field of the file header to 5. Example: DSE> change -fileheader -timers_pending=2 This command sets the timers pending field of the file header to 2. Example: DSE> change -fileheader -TOTAL_BLKS=64 This command sets the total size of the database to 100 (Hex: 64) blocks. Example: DSE> change -fileheader -trigger_flush=1000 This command sets the Flush Trigger field of the file header to 1000. Note the default value of Flush Trigger is 960. Example: DSE> change -fileheader -writes_per_flush=10 This command changes the number of writes/flush field of the file header to 10. Note that the default value for the number of writes/flush is 7. Example: DSE> change -fileheader -zqgblmod_seqno=FF This command changes the ZGBLMOD_SEQNO field to 255(Hex: FF). 2 CAche CAche Operates on the cache of a database having BG access method. The format of the CACHE command is: CA[CHE] -ALL -RE[COVER -VE[RIFY] 3 Qualifiers Qualifiers -RE[COVER] [-ALL] Resets the cache of a database having BG access method to a "clean" state. o With -ALL specified, DSE includes all region of the current global directory for cache recovery. o Attempt DSE -RECOVER only if a DSE CACHE -VERIFY commands reports the cache is "NOT clean". -VE[RIFY] [-ALL] Verifies the integrity of the cache data structures as well as the internal consistency of any GDS blocks in the global buffers of the current region. o With -ALL specified, DSE performs cache verification on all regions of the current global directory. o It reports the time, the region and a boolean result indicating whether the cache is clean or NOT clean. If you see "NOT clean" in report, execute DSE CACHE -RECOVER as soon as possible to reset the cache in a clean state. 3 Examples Examples Example: DSE> CACHE -VERIFY This command checks the integrity of the cache data structures as well as the internal consistency of GDS blocks in the global buffers of the current region. Example: DSE> CACHE -VERIFY -ALL Time 26-FEB-2011 14:31:30 : Region DEFAULT : Cache verification is clean Execute CACHE recover command if Cache verification is "NOT" clean. This command reports the state of database cache for all regions. Example: DSE> CACHE -RECOVER This command reinitializes the cache data structures of the current region and reverts the cache of a database having BG access to "clean" state. 2 CLose CLose The CLOSE command closes the currently open output file. The format of the CLOSE command is: CL[OSE] The CLOSE command has no qualifiers. 2 CRitical CRitical Displays and/or modifies the status and contents of the critical section for the current region. The format of the CRITICAL command is: CR[ITICAL] -I[NIT] -O[WNER] -REL[EASE] -REM[OVE] -RES[ET] -S[EIZE] o The critical section field identifies, by its process identification number (PID), the process presently managing updates to database. o Think of a critical section as a common segment of a train track. Just as a train moves through the common segment as quickly as possible, the same way a process moves as quickly as possible through any critical section so that other processes can use it. o By default, the CRITICAL command assumes the -OWNER qualifier, which displays the status of the critical section. 3 Qualifiers Qualifiers -I[NIT] Reinitializes the critical section. o The -INIT and -RESET qualifiers together cause all GT.M processes actively accessing that database file to signal an error. o FIS recommends against using -INIT without the -RESET parameter when other processes are actively accessing the region because it risks damaging the database. Use only with: -RESET -O[WNER] Displays the ID of the process at the head of the critical section. DSE displays a warning message when the current process owns the critical section. Use alone Example: DSE> critical -OWNER Write critical section is currently unowned -REL[EASE] Releases the critical section if the process running DSE owns the section. Use alone. -REM[OVE] Terminates any write ownership of the critical section. Use this when the critical section is owned by a process that is nonexistent or is known to no longer be running a GT.M image. Use alone. **Caution** Using CRITICAL -REMOVE when the write owner of a critical section is an active GT.M process may cause structural database damage. -RES[ET] Displays the number of times the critical section has been through an online reinitialization. Using -RESET with -INIT causes an error for processes that are attempting to get the critical section of the region. Under the guidance of FIS, use -RESET -INIT as a way to clear certain types of hangs. Use only with: -INIT -S[EIZE] Seizes the critical section (if available). o You can also use SEIZE to temporarily suspend database updates. o Subsequently, execute CRITICAL -RELEASE command to restore normal operation. 3 Examples Examples Example: DSE> critical -OWNER Write critical section owner is process id 4220 This command displays the ID of the process holding the critical section. Note that on catching a process ID on a lightly loaded (or unloaded) system (for example, text environment) is like catching lightening in a bottle. Therefore, you can artificially hold a critical section using the DSE CRIT -SEIZE command in one session and view the owner using a different session. 2 Dump Dump Displays blocks, records, or file headers. DUMP is one of the primary DSE examination commands. The format of the DUMP command is: D[UMP] -A[LL] -B[LOCK]=block_number -C[OUNT]=count -F[ILEHEADER] -G[LO] -G[VSTATS] -[NO]C[RIT] -[NO]H[EADER] -O[FFSET]=offset -R[ECORD]=record-number -U[PDPROC] -Z[WR] Use the error messages reported by MUPIP INTEG to determine what to DUMP and examine in the database. DUMP also can transfer records to a sequential file for future study and/or for input to MUPIP LOAD (see the section on OPEN). The DUMP command requires specification of an object using either -BLOCK, -HEADER, -RECORD, or -FILEHEADER. 3 Qualifiers Qualifiers -A[LL] When used with -FILEHEADER, the -A[LL] qualifier displays additional information on the database most of which is useful for FIS in diagnosing issues. A complete description of all the elements that show up with the DSE DUMP -FILEHEADER -ALL command are beyond the scope of this book. Use only with -FILEHEADER or -UPDPROC (which is actually redundant as -ALL displays the UPDPROC information). -B[LOCK]=block-number Specifies the starting block of the dump. For commands without an object qualifier, DSE uses the last block handled by a DSE operation. When no block has been accessed, (thatis, on the first block-oriented command), DSE uses block one (1). Incompatible with: -ALL, -FILEHEADER and -UPDPROC. -C[OUNT]=count Specifies the number of blocks, block headers, or records to DUMP. Incompatible with: -ALL, -FILEHEADER and -UPDPROC. -F[ILEHEADER] Dumps file header information. A DSE dump of a database file header prints a 0x prefix for all fields printed in hexadecimal format. Refer to the "Introduction" section for a description of the file header fields. Use only with -ALL or -UPDPROC -G[LO] Dumps the specified record or blocks into the current output file in Global Output (GO) format. FIS strongly suggests using -ZWR rather than -GLO as the ZWR format handles all possible content values, including some that are problematic with -GLO. Incompatible with: -ALL, -FILEHEADER, -UPDPROC and -ZWR. -G[VSTATS] Displays the access statistics for global variables and database file(s). -NO[CRIT] Allows DSE DUMP to work even if another process is holding a critical section. Since results in this mode may be inconsistent, it should only be used if the critical section mechanism is not operating normally. -[NO]H[EADER] Specifies whether the dump of the specified blocks or records is restricted to, or excludes, headers. -HEADER displays only the header, -NOHEADER displays the block or record with the header suppressed. DUMP without the -[NO]HEADER qualifier dumps both the block/record and the header. By default, DUMP displays all information in a block or record. Incompatible with: -ALL, -FILEHEADER, -GLO, -UPDPROC and -ZWR. -O[FFSET]=offset Specifies the offset, in bytes, of the starting record for the dump. If the offset does not point to the beginning of a record, DSE rounds down to the last valid record start (e.g., DUMP -OFF=10 starts at -OFF=A if that was the beginning of the record containing offset 10). Incompatible with: -ALL, -FILEHEADER, and -RECORD. -R[ECORD]=record_number Specifies the record number of the starting record of the dump. If you try to dump a record number that is larger than the last actual record in the block, a DSE error message provides the number of the last record in the block. Incompatible with: -ALL, -FILEHEADER, and -OFFSET. -U[PDPROC] Displays the helper process parameters with the fileheader elements. Use only with -FILEHEADER. -Z[WR] Dumps the specified record or blocks into the current output file in ZWRITE (ZWR) format. Incompatible with: -ALL, -GLO, -HEADER and -FILEHEADER. 3 Examples Examples Example: DSE> DUMP -FILEHEADER This command displays an output like the following: File /home/gtmuser1/mumps.dat Region DEFAULT Date/Time 27-OCT-2009 04:25:12 [$H = 61661,15912] Access method BG Global Buffers 1024 Reserved Bytes 0 Block size (in bytes) 1024 Maximum record size 256 Starting VBN 129 Maximum key size 64 Total blocks 0x00000191 Null subscripts NEVER Free blocks 0x0000002A Standard Null Collation FALSE Free space 0x00000000 Last Record Backup 0x0000000000000001 Extension Count 100 Last Database Backup 0x0000000000000001 Number of local maps 1 Last Bytestream Backup 0x0000000000000001 Lock space 0x00000028 In critical section 0x00000000 Timers pending 0 Cache freeze id 0x00000000 Flush timer 00:00:01:00 Freeze match 0x00000000 Flush trigger 960 Current transaction 0x0000000000007539 No. of writes/flush 7 Maximum TN 0xFFFFFFFFE3FFFFFF Certified for Upgrade to V5 Maximum TN Warn 0xFFFFFFFF73FFFFFF Desired DB Format V5 Master Bitmap Size 112 Blocks to Upgrade 0x00000000 Create in progress FALSE Modified cache blocks 0 Reference count 1 Wait Disk 0 Journal State [inactive] ON Journal Before imaging TRUE Journal Allocation 100 Journal Extension 100 Journal Buffer Size 128 Journal Alignsize 128 Journal AutoSwitchLimit 8388600 Journal Epoch Interval 30 Journal Yield Limit 8 Journal Sync IO TRUE Journal File: /home/gtmuser1/mumps.mjl Mutex Hard Spin Count 128 Mutex Sleep Spin Count 128 Mutex Spin Sleep Time 2048 KILLs in progress 0 Replication State OFF Region Seqno 0x0000000000000001 Zqgblmod Seqno 0x0000000000000000 Zqgblmod Trans 0x0000000000000000 Endian Format LITTLE Commit Wait Spin Count 17 Database file encrypted FALSE Note that the certain fileheader elements appear depending on the current state of database. For example, as Journaling is not enabled in the database, DSE does not display Journal data element fields. Example: $ dse dump -fileheader -updproc This command displays the fileheader elements along with the following helper process parameters: Upd reserved area [% global buffers] 50 Avg blks read per 100 records 200 Pre read trigger factor [% upd rsrvd] 50 Upd writer trigger [%flshTrgr] 33 2 EValuate EValuate Translates a hexadecimal number to decimal, and vice versa. The format of the EVALUATE command is: EV[ALUATE] -D[ECIMAL] -H[EXADECIMAL] -N[UMBER]=number The -DECIMAL and -HEXADECIMAL qualifiers specify the input base for the number. The -NUMBER qualifier is mandatory. By default, EVALUATE treats the number as having a hexadecimal base. 3 Qualifiers Qualifiers -D[ECIMAL] Specifies that the input number has a decimal base. Incompatible with: -HEXADECIMAL . -H[EXADECIMAL] Specifies that the input number has a hexadecimal base. Incompatible with: -DECIMAL -N[UMBER]=number Specifies the number to evaluate. Required. 3 Examples Examples Example: DSE> evaluate -number=10 -decimal Hex: A Dec: 10 This command displays the hexadecimal equivalent of decimal number 10. Example: DSE> evaluate -number=10 -hexadecimal Hex: 10 Dec: 16 This command displays the decimal equivalent of hexadecimal 10. Example: $ dse evaluate -number=10 Hex: 10 Dec: 16 This command displays the decimal equivalent of Hexadecimal 10. Note that if you do not specify an qualifier with -NAME, then EVALUATE assumes Hexadecimal input. 2 EXit EXit The EXIT command ends a DSE session. The format of the EXIT command is: EX[IT] The EXIT command has no qualifiers. 2 Find Find Locates a given block or region. The format of the FIND command is: F[IND] -B[LOCK]=block-number -E[XHAUSTIVE] -F[REEBLOCK] /H[INT] -K[EY]=key -[NO]C[RIT] -R[EGION][=region] -S[IBLINGS] o At the beginning of a DSE session, use the FIND -REGION command to select the target region. o The FIND command, except when used with the -FREEBLOCK and -REGION qualifiers, uses the index tree to locate blocks. FIND can locate blocks only within the index tree structure. If you need to locate keys independent of their attachment to the tree, use the RANGE command. 3 Qualifiers Qualifiers -B[LOCK]=block_number Specifies the block to find. On commands without the -BLOCK= qualifier, DSE uses the last block handled by a DSE operation. When no block has been accessed, that is, on the first block-oriented command, DSE uses block one (1). Incompatible with: -KEY, -REGION -E[XHAUSTIVE] Searches the entire index structure for the desired path or siblings. o FIND -EXHAUSTIVE locates blocks that are in the tree but not indexed correctly. o FIND -EXHAUSTIVE locates all paths to a "doubly allocated" block. **Note** A doubly allocated block may cause inappropriate mingling of data. As long as no KILLs occur, double allocation may not cause permanent loss of additional data. However, it may cause the application programs to generate errors and/or inappropriate results. When a block is doubly allocated, a KILL may remove data outside its proper scope. See "Maintaining Database Integrity Chapter" for more information on repairing doubly allocated blocks. Incompatible with: -KEY, -REGION, -FREEBLOCK -F[REEBLOCK] Finds the nearest free block to the block specified by -HINT. o The -FREEBLOCK qualifier is incompatible with all other qualifiers except -BLOCK and -HINT. o The -HINT qualifier is required with the -FREEBLOCK qualifier. o FIND -FREEBLOCK relies on the bitmaps to locate its target, so be sure to fix any blocks incorrectly marked "FREE" before using this command. See MAP -BUSY for more information on fixing incorrectly marked free errors. Required with -HINT; compatible with -BLOCK and [NO]CRIT. -H[INT]=block_number Designates the starting point of a -FREEBLOCK search. FIND -FREE -HINT locates the "closest" free block to the hint. This provides a tool for locating blocks to add to the B-tree, or to hold block copies created with SAVE that would otherwise be lost when DSE exits. FIND -FREE relies on the bitmaps to locate its target, so be sure to fix any blocks incorrectly marked "FREE" before using this command. Required with: -FREEBLOCK; compatible with -BLOCK and [NO]CRIT. -K[EY]=key Searches the database for the block containing the specified key or if the key does not exist, the block that would contain it, if it existed. o Enclose an M-style key in quotation marks (" "). FIND -KEY is useful in locating properly indexed keys. The -KEY qualifier is incompatible with all other qualifiers. o FIND -KEY= uses the index to locate the level zero (0) block , or data block, containing the key. If the key does not exist, it uses the index to locate the block in which it would reside. Note that FIND only works with the index as currently composed. In other words, it cannot FIND the "right" place, only the place pointed to by the index at the time the command is issued. These two locations should be, and may well be, the same; however, remind yourself to search for, understand and take into account all information describing any current database integrity issues. Compatible only with [NO]CRIT. -[NO]C[RIT] Allows FIND to work even if another process is holding a critical section. As results in this mode may be inconsistent, it should only be used if the critical section mechanism is not operating normally -R[EGION][=region] Switches to the named Global Directory region. -REGION without a specified region, or -REGION="*", displays all existing regions in the database. Use Alone. -S[IBLINGS] Displays the block number of the specified block and its logical siblings in hexadecimal format. The logical siblings are the blocks, if any, that logically exist to the right and left of the given block in the database tree structure. Incompatible with: -FREEBLOCK, -HINT, -KEY, -REGION 3 Examples Examples Example: DSE> find -exhaustive -block=180 Directory path Path--blk:off 1:10 2:1E Global paths Path--blk:off 6:51 1A4:249 180 This command locates block 180 by looking through the B-tree index for any pointer to the block. This command finds even those blocks that are connected to the tree but the first key in the block does not match the index path. Example: DSE> find -free -hint=180 Next free block is D8F. This command locates the "closest" free block to block 180. You can use this command as a tool for locating blocks to add to the B-tree, or to hold block copies created with SAVE that would otherwise be lost when DSE exits. Example: DSE>find -key="^biggbl(1)" This command locates the key ^biggbl(1) in the database. Example: DSE> find -freeblock -hint=232 This commands starts to search for free block after block 232. Example: DSE> FIND -FREEBLOCK -HINT=232 -NOCRIT This command searches for freeblocks after block 232 even if another process is holding a critical section. Example: DSE> find -sibling -block=10 This command operates like FIND -BLOCK; however it reports the numbers of the blocks that logically fall before and after block 180 on the same level. This command produces an output like the following: Left sibling Current block Right sibling 0x0000000F 0x00000010 0x00000011 2 Help Help The HELP command explains DSE commands. The format of the HELP command is: -H[ELP] [help topic] 2 Integrit Integrit Checks the internal consistency of a single non-bitmap block. INTEGRIT reports errors in hexadecimal notation. The format of the INTEGRIT command is: I[NTEGRIT] -B[LOCK]=block-number **Note** Unlike MUPIP INTEG, this command only detects errors internal to a block and cannot detect errors such as indices incorrectly pointing to another block. 3 Qualifiers Qualifiers -B[LOCK]=block_number Specifies the block for DSE to check. On commands with no -BLOCK qualifier, DSE uses the last block handled by a DSE operation. When no block has been accessed, that is, on the first block-oriented command, DSE uses block one (1). -NO[CRIT] Allows DSE INTEG to work even if another process is holding a critical section. Since results in this mode may be inconsistent, it should only be used if the critical section mechanism is not operating normally. 2 Maps Maps Examines or updates bitmaps. The format of the MAPS command is: M[APS] -BL[OCK]=block-number -BU[SY] -F[REE] -M[ASTER] -R[ESTORE_ALL] MAPS can flag blocks as being either -BUSY or -FREE. The -MASTER qualifier reflects the current status of a local bitmap back into the master map. The -RESTORE_ALL qualifier rebuilds all maps and should be used with caution since it can destroy important information. By default, MAPS shows the status of the bitmap for the specified block. 3 Qualifiers_for_MAP Qualifiers for MAP -BL[OCK]=block_number Specifies the target block for MAPS. The -BLOCK qualifier is incompatible with the -RESTORE_ALL qualifier. On commands with no -BLOCK= or -RESTORE_ALL qualifier, DSE uses the last block handled by a DSE operation. When no block has been accessed, that is, on the first block-oriented command, DSE uses block one (1). Incompatible with: -RESTORE_ALL -BU[SY] Marks the current block as busy in the block's local map and appropriately updates the master bitmap. Compatible only with: -BLOCK -F[REE] Marks the current block as free in the block's local map and appropriately updates the master bitmap. Compatible only with: -BLOCK -M[ASTER] Sets the bit in the master bitmap associated with the current block's local map according to whether or not that local map is full. Use only with: -BLOCK. -R[ESTORE_ALL] Sets all local bitmaps and the master bitmap to reflect the blocks used in the database file. Use -RESTORE_ALL only if the database contents are known to be correct, but a large number of the bitmaps require correction. **Caution** The -RESTORE_ALL qualifier rebuilds all maps and should be used with a great deal of caution as it can destroy important information. Use alone. 3 Examples_for_MAPS Examples for MAPS Example: DSE> MAPS -BLOCK=20 -FREE This command flags block 20 as free. A sample DSE DUMP output block 0 is as follows: Block 0 Size 90 Level -1 TN 10B76A V5 Master Status: Free Space Low order High order Block 0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | Block 20: | :XXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | Block 40: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | Block 60: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | Block 80: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | Block A0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | Block C0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | Block E0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | Block 100: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | Block 120: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | Block 140: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | Block 160: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | Block 180: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | Block 1A0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | Block 1C0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | Block 1E0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX | 'X' == BUSY '.' == FREE ':' == REUSABLE '?' == CORRUPT Note that BLOCK 20 is marked as REUSABLE, which means FREE but in need of a before-image journal record. Example: DSE> maps -block=20 -busy This command marks block 20 as busy. A sample DSE DUMP output of block 0 is as follows: Block 0 Size 90 Level -1 TN 1 V5 Master Status: Free Space Low order High order Block 0: | XXX..... ........ ........ ........ | Block 20: | X....... ........ ........ ........ | Block 40: | ........ ........ ........ ........ | Block 60: | ........ ........ ........ ........ | Block 80: | ........ ........ ........ ........ | Block A0: | ........ ........ ........ ........ | Block C0: | ........ ........ ........ ........ | Block E0: | ........ ........ ........ ........ | Block 100: | ........ ........ ........ ........ | Block 120: | ........ ........ ........ ........ | Block 140: | ........ ........ ........ ........ | Block 160: | ........ ........ ........ ........ | Block 180: | ........ ........ ........ ........ | Block 1A0: | ........ ........ ........ ........ | Block 1C0: | ........ ........ ........ ........ | Block 1E0: | ........ ........ ........ ........ | 'X' == BUSY '.' == FREE ':' == REUSABLE '?' == CORRUPT Note that the BLOCK 20 is marked as BUSY. 2 OPen OPen Use the OPEN command to open a file for sequential output of global variable data. The format of the OPEN command is: OP[EN] F[ILE]=file o OPEN a file to which you want to "dump" information. o If an OPEN command does not have a -FILE qualifier, DSE reports the name of the current output file. 3 Qualifiers_for_OPEN Qualifiers for OPEN -F[ILE]=file-name Specifies the file to open. 3 Examples Examples Example: DSE> OPEN Current output file: var.out This command displays the current output file. In this case, the output file is var.out. Example: DSE> OPEN -FILE=var1.out The command OPEN -FILE=var1.out sets the output file to var1.out. 2 OVerwrite OVerwrite Overwrites the specified string on the given offset in the current block. Use extreme caution when using this command. The format of the OVERWRITE command is: OV[ERWRITE] -D[ATA]=string -O[FFSET]=offset 3 Qualifiers_for_OVERWRITE Qualifiers for OVERWRITE -B[LOCK]=block number Directs DSE to OVERWRITE a specific block. If no block number is specified, the default is the current block. -D[ATA]=string Specifies the data to be written. Use quotation marks around the string and escape codes of the form \a or \ab, where "a" and "b" are hexadecimal digits representing non-printing characters. \\ translates to a single backslash. -O[FFSET]=offset Specifies the offset in the current block where the overwrite should begin. 3 Examples Examples Example: DSE>overwrite -block=31 -data="Malvern" -offset=CA This command overwrites the data at the specified location. 2 Page Page Sends one form feed to the output device. Use PAGE to add form feeds to a dump file, making the hard copy file easier to read. If you plan to use the dump file with MUPIP LOAD, do not use PAGE. The format of the PAGE command is: P[AGE] The PAGE command has no qualifiers. 2 RAnge RAnge The RANGE command finds all blocks in the database whose first key falls in the specified range of keys. The RANGE command may take a very long time unless the range specified by -FROM and -TO is small. Use FIND -KEY and/or FIND -KEY -EXHAUSTIVE first to quickly determine whether the key appears in the index tree. The format of the RANGE command is: RA[NGE] -F[ROM]=block-number -T[O]=block-number -I[NDEX] -LOS[T] -[NO]C[RIT] -[NO]BU[SY] -S[TAR] -LOW[ER]=key -U[PPER]=key 3 Qualifiers Qualifiers -F[ROM]=block_number Specifies a starting block number for the range search. By default, RANGE starts processing at the beginning of the file. -T[O]=block-number Specifies an ending block number for the range search. By default, RANGE stops processing at the end of the file. -I[NDEX] Restricts a search to index blocks. -LOS[T]=block_number Restricts a search to blocks not found by a FIND -BLOCK. -LOW[ER]=key Specifies the lower bound for the key range. -[NO]BU[SY]=busy/free Restricts a search to either BUSY or FREE blocks. -[NO]C[RIT] Allows DSE RANGE to work even if another process is holding a critical section. Since results in this mode may be inconsistent, it should only be used if the critical section mechanism is not operating normally. -S[TAR] Includes index blocks that contain a single star key. -U[PPER]=key Specifies the upper bound for the key range. 3 Examples Examples Example: DSE> range -lower="^abcdefgh" -upper="^abcdefghi" -from=A -to=CC This command searches for a specified keys between block 10 and block 204. Note that the range (between FROM and TO) of blocks must be valid blocks specified in hexadecimal. Example: DSE> range -lower="^abcdefgh" -upper="^abcdefghi" -from=A -to=CC -noindex This command searches only data blocks for the specified keys between block 10 and block 204. Example: DSE> range -lower="^abcdefgh" -upper="^abcdefghi" -from=A -to=CC -index This command searches only index blocks for the specified keys between block 10 and block 204. Example: DSE> range -lower="^abcdefgh" -upper="^abcdefghi" -lost This command includes lost blocks while searching for the specified keys and reports only blocks which are not currently indexed. Example: DSE> range -lower="^Fruits(15)" -upper="^Fruits(877)" -from=A -to=F Blocks in the specified key range: Block: 0000000A Level: 0 Block: 0000000B Level: 0 Block: 0000000C Level: 0 Block: 0000000D Level: 0 Block: 0000000E Level: 0 Block: 0000000F Level: 0 Found 6 blocks This command search for keys between ^Fruits(15) and ^Fruits(877). 2 REMove REMove Removes one or more records or a save buffer. The format of the REMOVE command is: REM[OVE] -B[LOCK]=block-number -C[OUNT]=count -O[FFSET]=offset -R[ECORD]=record-number -V[ERSION]=version-number The version number is specified in decimal. 3 Qualifiers Qualifiers -B[LOCK]=block_number Specifies the block associated with the record or buffer being deleted. On commands with no -BLOCK= qualifier, DSE uses the last block handled by a DSE operation. When no block has been accessed, that is, on the first block-oriented command, DSE uses block one (1). -C[OUNT]=count Specifies the number of records to remove. By default, REMOVE deletes a single record. Incompatible with: -VERSION -O[FFSET]=offset Specifies the offset (in bytes) of the record to be removed. If the offset does not point to the beginning of a record, DSE rounds down to the beginning of the record containing the offset (for example, REMOVE -OFF=10 starts at OFF=A if that was the last prior record boundry). Incompatible with: -VERSION, -RECORD -R[ECORD]=record_number Specifies the number that identifies the record to remove. The -RECORD qualifier is incompatible with the -OFFSET and -VERSION qualifiers. Incompatible with: -VERSION, -OFFSET -V[ERSION]=version_number Specifies the version number, in decimal, of the save buffer to remove. -VERSION is required to REMOVE a SAVE buffer. -VERSION is incompatible with all qualifiers except -BLOCK. Use only with: -BLOCK; decimal 2 REStore REStore The RESTORE command restores saved versions of blocks. RES[TORE] B[LOCK]=block-number F[ROM]=from R[EGION]=region V[ERSION]=version-number The version number is specified in decimal. 3 Qualifiers Qualifiers -B[LOCK]=block_number Specifies the block to restore. For commands with no -BLOCK= qualifier, DSE uses the last block handled by a DSE operation. When no block has been accessed, (i.e., on the first block-oriented command), DSE uses block one (1). -F[ROM]=block_number Specifies the block number of the SAVE buffer to restore. DSE restores the block specified with -BLOCK qualifier with the block specified by the -FROM qualifier. By default, RESTORE uses the target block number as the -FROM block number. -R[EGION]=region Specifies the region of the saved buffer to restore. By default, RESTORE uses SAVE buffers from the current region. -V[ERSION]=version_number Specifies the decimal version number of the block to restore. The version number is required. 2 SAve SAve The SAVE command preserves versions of blocks, or displays a listing of saved versions for the current DSE session. Saved information is lost when DSE EXITs. Use with the RESTORE command to move SAVEd blocks to a permanent location, and as a safety feature use SAVE to retain copies of database blocks before changing them. The format of the SAVE command is: SA[VE] -B[LOCK]=block-number -C[OMMENT]=string -L[IST] -[NO]C[RIT] 3 Qualifiers Qualifiers -B[LOCK]=block_number Specifies the block to restore. On commands with no -BLOCK= qualifier, DSE uses the last block handled by a DSE operation. When no block has been accessed, that is, on the first block-oriented command, DSE uses block one (1). -C[OMMENT]=string Specifies a comment to save with the block. Enclose the comment in quotation marks (" "). Incompatible with: -LIST -L[IST] Lists saved versions of specified blocks. The -LIST qualifier is incompatible with the -COMMENT qualifier. By default, SAVE -LIST provides a directory of all SAVEd blocks. Incompatible with: -COMMENT -[NO]C[RIT] Allows DSE SAVE to work even if another process is holding a critical section. Since results in this mode may be inconsistent, it should only be used if the critical section mechanism is not operating normally. 2 SHift SHift Use the SHIFT command to shift data in a block, filling the block with zeros, or shortening the block. The format of the SHIFT command is: SH[IFT] -B[ACKWARD]=b_shift -F[ORWARD]=f_shift -O[FFSET]=offset b_shift must always be less than or equal to offset. This means that DSE SHIFT in the backward direction is restricted to the maximum of OFFSET number of bytes. This ensures that the shift does not cross block boundaries, either intentionally or unintentionally. 3 Qualifiers Qualifiers -B[ACKWARD]=shift Specifies the number of bytes to shift data in the direction of the block header. Incompatible with: -FORWARD -F[ORWARD]=shift Specifies the number of bytes to shift data toward the end of the block. Incompatible with: -BACKWARD -O[FFSET]=offset Specifies the starting offset, in bytes, of the portion of the block to shift. -SPawn 2 SPawn SPawn Use the SPAWN command to fork a child process for access to the shell without terminating the current DSE environment. The format of the SPAWN command is: SP[AWN] [shell-command] o The SPAWN command accepts an optional command string for execution by the spawned sub-process. If the SPAWN has no command string parameter, the created sub-process issues a shell prompt and accepts any legal shell command. To terminate the sub-process, use the shell logout command. o The SPAWN command has no qualifiers. o DSE SPAWN works with an argument. If the argument contains spaces, enclose it with quotes. The SPAWN command has no qualifiers. DSE SPAWN works with an argument. If the argument contains spaces, enclose it with quotes. 3 Examples Examples Example: DSE> SPAWN "mumps -run ^GDE" This command suspends a DSE session and executes the shell command mumps -run ^GDE. 2 Wcinit Wcinit Use the WCINIT command to reinitialize the global buffers of the current region. Because it cleans out the cache, the WCINIT command should not be used except under the guidance of FIS. **Caution** A WCINIT command issued while normal database operations are in progress can cause catastrophic damage to the database. The format of the WCINIT command is: W[CINIT] o The WCINIT command has no qualifiers. o When you issue the WCINIT command, DSE issues the CONFIRMATION: prompt. You must verify the WCINIT command by responding with "YES." If you do not confirm the WCINIT, DSE issues the message: No action taken, enter yes at the CONFIRMATION prompt to initialize global buffers. o WCINIT operations are more safely performed by MUPIP RUNDOWN. Use this command only under instructions from FIS. 1 Summary Summary +------------------------------------------------------------------------+ | COMMAND | QUALIFIERS | COMMENTS | |-------------+-----------------------------------+----------------------| | AD[D] | -B[LOCK]=block number | - | |-------------+-----------------------------------+----------------------| | - | -D[ATA]=string | Incompatible with | | | | -POINTER, -STAR | |-------------+-----------------------------------+----------------------| | - | -K[EY]=key | Incompatible with | | | | -STAR | |-------------+-----------------------------------+----------------------| | - | -O[FFSET]=offset | Incompatible with | | | | -RECORD, -STAR | |-------------+-----------------------------------+----------------------| | - | -P[OINTER]=pointer | Incompatible with | | | | -DATA | |-------------+-----------------------------------+----------------------| | - | -R[ECORD]=record-number | Incompatible with | | | | -OFFSET, -STAR | |-------------+-----------------------------------+----------------------| | | | Incompatible with | | - | -S[TAR] | -DATA,-KEY, -OFFSET, | | | | -RECORD | |-------------+-----------------------------------+----------------------| | AL[L] | -B[UFFER_FLUSH] | Incompatible with | | | | -RENEW | |-------------+-----------------------------------+----------------------| | | | Incompatible with | | - | -C[RITINIT] | -RENEW, -RELEASE, | | | | -SEIZE | |-------------+-----------------------------------+----------------------| | - | -[NO]F[REEZE] | Incompatible with | | | | -RENEW | |-------------+-----------------------------------+----------------------| | - | -O[VERRIDE] | Meaningful only with | | | | -[NO]FREEZE | |-------------+-----------------------------------+----------------------| | - | -REF[ERENCE] | Incompatible with | | | | -RENEW | |-------------+-----------------------------------+----------------------| | | | Incompatible with | | - | -REL[EASE] | -CRITINIT, | | | | -RENEW,-SEIZE | |-------------+-----------------------------------+----------------------| | - | -REN[EW] | Use alone | |-------------+-----------------------------------+----------------------| | | | Incompatible with | | - | -S[EIZE] | -RENEW, -RELEASE, | | | | -CRITINIT | |-------------+-----------------------------------+----------------------| | - | -W[CINIT] | Incompatible with | | | | -RENEW | |-------------+-----------------------------------+----------------------| | B[UFFER | - | - | | _FLUSH] | | | |-------------+-----------------------------------+----------------------| | | | Incompatible with | | CH[ANGE] | -BL[OCK]=block number | -FILEHEADER and | | | | qualifiers used with | | | | -FILEHEADER | |-------------+-----------------------------------+----------------------| | - | -BS[IZ]=block-size | Use only with | | | | -BLOCK, -LEVEL, -TN | |-------------+-----------------------------------+----------------------| | - | -L[EVEL]=level | Use only with | | | | -BLOCK, -BSIZ, -TN | |-------------+-----------------------------------+----------------------| | | | Use only with | | - | -TN [=transaction number] | -BLOCK, -BSIZ, | | | | -LEVEL | |-------------+-----------------------------------+----------------------| | - | -OF[FSET]=offset | Use only with | | | | -BLOCK, -CMPC, -RSIZ | |-------------+-----------------------------------+----------------------| | - | -RE[CORD]=record number | Use only with | | | | -BLOCK, -CMPC, -RSIZ | |-------------+-----------------------------------+----------------------| | | | Use only with | | - | -CM[PC]= compression count | -BLOCK, -RECORD, | | | | -OFFSET, -RSIZ | |-------------+-----------------------------------+----------------------| | | | Use only with -CMPC | | - | -RS[IZ]=record size | -OFFSET, -RECORD, | | | | -BLOCK | |-------------+-----------------------------------+----------------------| | | | Incompatible with | | - | -F[ILEHEADER] | -BSIZ, -CMPC, -TN, | | | | -LEVEL, -OFFSET, | | | | -RECORD, -RSIZ | |-------------+-----------------------------------+----------------------| | - | AVG_BLKS_READ=Average blocks read | | |-------------+-----------------------------------+----------------------| | - | B_B[YTESTREAM]=transaction number | | |-------------+-----------------------------------+----------------------| | - | -B_C[OMPREHENSIVE]=transaction | Use only with | | | number | -FILEHEADER; decimal | |-------------+-----------------------------------+----------------------| | - | B_D[ATABASE] = transaction number | Use only with | | | | -FILEHEADER; decimal | |-------------+-----------------------------------+----------------------| | - | -B_I[NCREMENTAL] = transaction | Use only with | | | number | -FILEHEADER; decimal | |-------------+-----------------------------------+----------------------| | - | -BLK[_SIZE]=block size | Use only with | | | | -FILEHEADER; decimal | |-------------+-----------------------------------+----------------------| | - | -BLO[CKS_FREE]=free blocks | Use only with | | | | -FILEHEADER; decimal | |-------------+-----------------------------------+----------------------| | - | -B_R[ECORD]=transaction number | Use only with | | | | -FILEHEADER; decimal | |-------------+-----------------------------------+----------------------| | - | -CO[RRUPT_FILE]=value | Use only with | | | | -FILEHEADER | |-------------+-----------------------------------+----------------------| | - | -CU[RRENT_TN]=transaction number | Use only with | | | | -FILEHEADER | |-------------+-----------------------------------+----------------------| | - | DECL[OCATION]=value | Use only with | | | | -FILHEADER; decimal | |-------------+-----------------------------------+----------------------| | - | DEF[_COLLATION]=value | Use only with | | | | -FILEHEADER; | |-------------+-----------------------------------+----------------------| | - | -ENCRYPTION_HASH | Use only with | | | | -FILEHEADER | |-------------+-----------------------------------+----------------------| | - | -FL[USH_TIME][=delta time] | Use only with | | | | -FILEHEADER | |-------------+-----------------------------------+----------------------| | - | -FR[EEZE]=value | Use only with | | | | -FILEHEADER | |-------------+-----------------------------------+----------------------| | - | -FU[LLY_UPGRADED]=boolean | Use only with | | | | -FILEHEADER | |-------------+-----------------------------------+----------------------| | - | -GV[STATSRESET] | Use only with | | | | -FILEHEADER | |-------------+-----------------------------------+----------------------| | - | -HARD_SPIN_CPUNT=Mutex hard spin | Use only with | | | count | -FILEHEADER | |-------------+-----------------------------------+----------------------| | | -HEXL[OCATION]=value | Use only with | | | | -FILEHEADER;hexa | |-------------+-----------------------------------+----------------------| | - | -INT[ERRUPTED_RECOV]=boolean | | |-------------+-----------------------------------+----------------------| | - | -JNL_YIELD_LIMIT=journal yeild | | | | limit | | |-------------+-----------------------------------+----------------------| | - | -K[EY_MAX_SIZE]=key_max_size | Use only with | | | | -FILEHEADER; decimal | |-------------+-----------------------------------+----------------------| | - | -M[ACHINE_NAM]=value | | |-------------+-----------------------------------+----------------------| | - | -N[ULL_SUBSCRIPTS]=value | Use only with | | | | -FILEHEADER | |-------------+-----------------------------------+----------------------| | - | -NO[CRIT] | | |-------------+-----------------------------------+----------------------| | - | -OV[ERRIDE] | | |-------------+-----------------------------------+----------------------| | - | -RC_SRV_COUNT | | |-------------+-----------------------------------+----------------------| | - | -RE_READ_TRIGGER=read trigger | | |-------------+-----------------------------------+----------------------| | - | -Q[UANTUM_INTERVAL] [=delta time] | Use only with | | | | -FILEHEADER; decimal | |-------------+-----------------------------------+----------------------| | - | -REC[ORD_MAX_SIZE]=maximum record | Use only with | | | size | -FILEHEADER; decimal | |-------------+-----------------------------------+----------------------| | - | -REF[ERENCE_COUNT]=reference | Use only with | | | count | -FILEHEADER; decimal | |-------------+-----------------------------------+----------------------| | - | -REG[_SEQNO]=sequence number | Use only with | | | | -FILEHEADER; hexa | |-------------+-----------------------------------+----------------------| | - | -RESERVED_BYTES=reserved bytes | Use only with | | | | -FILEHEADER;decimal | |-------------+-----------------------------------+----------------------| | - | -[NO] RES[PONSE_INTERVAL] [=delta | Use only with | | | time] | -FILEHEADER; decimal | |-------------+-----------------------------------+----------------------| | - | -SLEEP_SPIN_COUNT=mutex sleep | Use only with | | | spin count | -FILEHEADER; | |-------------+-----------------------------------+----------------------| | - | -SPIN_SLEEP_TIME=mutex sleep time | | |-------------+-----------------------------------+----------------------| | - | -[NO]S[TALENESS_TIMER] [=delta | Use only with | | | time] | -FILEHEADER; decimal | |-------------+-----------------------------------+----------------------| | - | -TIC[K_INTERVAL] [=delta time] | Use only with | | | | -FILEHEADER; decimal | |-------------+-----------------------------------+----------------------| | - | -TIM[ERS_PENDING]=timers pending | Use only with | | | | -FILEHEADER; decimal | |-------------+-----------------------------------+----------------------| | - | -TO[TAL_BLKS]=total_blocks | Use only with | | | | -FILEHEADER | |-------------+-----------------------------------+----------------------| | - | -TR[IGGER_FLUSH]=trigger flush | Use only with | | | | -FILEHEADER | |-------------+-----------------------------------+----------------------| | - | -W[RITES_PER_FLUSH]=writes per | Use only with | | | flush | -FILEHEADER; decimal | |-------------+-----------------------------------+----------------------| | - | -WAIT_DISK=wait disk | | |-------------+-----------------------------------+----------------------| | - | -Zqgblmod_S[EQNO] = sequence | Use only with | | | number | -FILEHEADER;hexa | |-------------+-----------------------------------+----------------------| | - | -Zqgblmod_T[rans]=sequence_number | Use only with | | | | -FILEHEADER;hexa | |-------------+-----------------------------------+----------------------| |-------------+-----------------------------------+----------------------| | CL[OSE] | - | - | |-------------+-----------------------------------+----------------------| | CR[ITICAL] | -I[NIT] | Use only with -RESET | |-------------+-----------------------------------+----------------------| | - | -O[WNER] | Use alone | |-------------+-----------------------------------+----------------------| | - | -REL[EASE] | Use alone | |-------------+-----------------------------------+----------------------| | - | -REM[OVE] | Use alone | |-------------+-----------------------------------+----------------------| | - | -RES[ET] | Use only with -INIT | |-------------+-----------------------------------+----------------------| | - | -S[EIZE] | Use alone | |-------------+-----------------------------------+----------------------| | D[UMP] | -B[LOCK]=block_number | Incompatible with | | | | -FILEHEADER | |-------------+-----------------------------------+----------------------| | - | -C[OUNT]=count | Incompatible with | | | | -FILEHEADER | |-------------+-----------------------------------+----------------------| | - | -F[ILEHEADER] | Use alone | |-------------+-----------------------------------+----------------------| | - | -G[LO] | Incompatible with | | | | -FILEHEADER, -HEADER | |-------------+-----------------------------------+----------------------| | - | -G[VSTATS] | Use only with | | | | -FILEHEADER | |-------------+-----------------------------------+----------------------| | - | -[NO]H[EADER] | Incompatible with | | | | -FILEHEADER, -GLO | |-------------+-----------------------------------+----------------------| | - | -O[FFSET]=offset | Incompatible with | | | | -FILEHEADER, -RECORD | |-------------+-----------------------------------+----------------------| | - | -R[ECORD]=record_number | Incompatible with | | | | -FILEHEADER, -OFFSET | |-------------+-----------------------------------+----------------------| | EV[ALUATE] | -D[ECIMAL] | Incompatible with | | | | -HEXADECIMAL | |-------------+-----------------------------------+----------------------| | - | -H[EXADECIMAL] | Incompatible with | | | | -DECIMAL | |-------------+-----------------------------------+----------------------| | - | -N[UMBER]=number | Required | |-------------+-----------------------------------+----------------------| | EX[IT] | | - | |-------------+-----------------------------------+----------------------| | F[IND] | -B[LOCK]=block_number | Incompatible with | | | | -KEY, -REGION | |-------------+-----------------------------------+----------------------| | | | Incompatible with | | - | -E[XHAUSTIVE] | -KEY, -REGION, | | | | -FREEBLOCK | |-------------+-----------------------------------+----------------------| | | | Required with -HINT; | | - | -F[REEBLOCK] | compatible with | | | | -BLOCK | |-------------+-----------------------------------+----------------------| | - | -H[INT]=block_number | Required with | | | | -FREEBLOCK | |-------------+-----------------------------------+----------------------| | - | -K[EY]=key | Use alone | |-------------+-----------------------------------+----------------------| | - | -R[EGION][=region] | Use alone | |-------------+-----------------------------------+----------------------| | | | Incompatible with | | - | -S[BLINGS] | -FREEBLOCK, -HINT, | | | | -KEY, -REGION | |-------------+-----------------------------------+----------------------| | H[ELP] | [help topic] | - | |-------------+-----------------------------------+----------------------| | I[NTEGRIT] | -B[LOCK]=block&_number | - | |-------------+-----------------------------------+----------------------| | M[APS] | -BL[OCK]=block_number | Incompatible with | | | | -RESTORE_ALL | |-------------+-----------------------------------+----------------------| | - | -BU[SY] | Compatible only with | | | | -BLOCK | |-------------+-----------------------------------+----------------------| | - | -F[REE] | - | |-------------+-----------------------------------+----------------------| | - | -M[ASTER] | - | |-------------+-----------------------------------+----------------------| | - | -R[ESTORE_ALL] | Use alone | |-------------+-----------------------------------+----------------------| | OP[EN] | -F[ILE]=file | - | |-------------+-----------------------------------+----------------------| | | -B[LOCK]=block_number | | | OV[ERWRITE] | | - | | | -D[ATA]=string | | |-------------+-----------------------------------+----------------------| | - | -O[FFSET]=offset | - | |-------------+-----------------------------------+----------------------| | P[AGE] | - | - | |-------------+-----------------------------------+----------------------| | RA[NGE] | -F[ROM]=block_number | - | |-------------+-----------------------------------+----------------------| | - | -T[O]=block_number | - | |-------------+-----------------------------------+----------------------| | | -I[NDEX]=block_number | | | | | | | | -L[OST]=block_number | | | | | | | - | -[NOT]BUSY=busy/free | - | | | | | | | -S[TAR]=block_number | | | | | | | | -L[OWER]=key | | |-------------+-----------------------------------+----------------------| | - | -U[PPER]=key | - | |-------------+-----------------------------------+----------------------| | REM[OVE] | -B[LOCK]=block-number | - | |-------------+-----------------------------------+----------------------| | - | -C[OUNT]=count | Incompatible with | | | | -VERSION | |-------------+-----------------------------------+----------------------| | - | -O[FFSET]=offset | Incompatible with | | | | -VERSION, -RECORD | |-------------+-----------------------------------+----------------------| | - | -R[ECORD]=record-number | Incompatible with | | | | -VERSION, -OFFSET | |-------------+-----------------------------------+----------------------| | - | -V[ERSION]=version-number | Use only with | | | | -BLOCK; decimal | |-------------+-----------------------------------+----------------------| | RES[TORE] | -B[LOCK]=block-number | - | |-------------+-----------------------------------+----------------------| | - | -F[ROM]=block-number | - | |-------------+-----------------------------------+----------------------| | - | -R[EGION]=region | - | |-------------+-----------------------------------+----------------------| | - | -V[ERSION]=version-number | Required; decimal | |-------------+-----------------------------------+----------------------| | SA[VE] | -B[LOCK]=block-number | - | |-------------+-----------------------------------+----------------------| | - | -C[OMMENT]=string | Incompatible with | | | | -LIST | |-------------+-----------------------------------+----------------------| | - | -L[IST] | Incompatible with | | | | -COMMENT | |-------------+-----------------------------------+----------------------| | SH[IFT] | -B[ACKWARD]=shift | Incompatible with | | | | -FORWARD | |-------------+-----------------------------------+----------------------| | - | -F[ORWARD]=shift | Incompatible with | | | | -BACKWARD | |-------------+-----------------------------------+----------------------| | - | -O[FFSET]=offset | - | |-------------+-----------------------------------+----------------------| | SP[AWN] | [CLI command] | - | |-------------+-----------------------------------+----------------------| | W[CINIT] | - | - | +------------------------------------------------------------------------+ * Use these qualifiers only with instructions from FIS. fis-gtm-V6.0-003/sr_port/dse_adrec.c0000644000032200000250000001656612201176155016125 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "gdscc.h" #include "cli.h" #include "copy.h" #include "filestruct.h" #include "jnl.h" #include "skan_offset.h" #include "skan_rnum.h" #include "dse.h" /* Include prototypes */ #include "t_qread.h" #include "t_write.h" #include "t_end.h" #include "t_begin_crit.h" #include "gvcst_blk_build.h" #include "util.h" #include "t_abort.h" GBLREF char *update_array, *update_array_ptr; GBLREF uint4 update_array_size; GBLREF srch_hist dummy_hist; GBLREF block_id patch_curr_blk; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF gd_addr *gd_header; GBLREF char patch_comp_key[MAX_KEY_SZ + 1]; GBLREF unsigned short patch_comp_count; GBLREF gd_region *gv_cur_region; GBLREF cw_set_element cw_set[]; void dse_adrec(void) { char data[MAX_LINE], key[MAX_KEY_SZ + 1]; unsigned short cc; int tmp_cmpc; sm_uc_ptr_t new_bp, lbp, b_top, rp, r_top, key_top; short int size, new_len, rsize; int data_len, key_len; int4 blk_seg_cnt, blk_size; block_id blk; blk_segment *bs1, *bs_ptr; srch_blk_status blkhist; error_def(ERR_CPBEYALLOC); error_def(ERR_DBRDONLY); error_def(ERR_DSEBLKRDFAIL); error_def(ERR_DSEFAIL); error_def(ERR_GVIS); error_def(ERR_REC2BIG); if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); CHECK_AND_RESET_UPDATE_ARRAY; /* reset update_array_ptr to update_array */ if (cli_present("BLOCK") == CLI_PRESENT) { if(!cli_get_hex("BLOCK", (uint4 *)&blk)) return; patch_curr_blk = blk; } if (patch_curr_blk < 0 || patch_curr_blk >= cs_addrs->ti->total_blks || !(patch_curr_blk % cs_addrs->hdr->bplmap)) { util_out_print("Error: invalid block number.", TRUE); return; } if (cli_present("KEY") != CLI_PRESENT) { util_out_print("Error: key must be specified.", TRUE); return; } if (!dse_getki(&key[0], &key_len, LIT_AND_LEN("KEY"))) return; t_begin_crit(ERR_DSEFAIL); blk_size = cs_addrs->hdr->blk_size; blkhist.blk_num = patch_curr_blk; if (!(blkhist.buffaddr = t_qread(blkhist.blk_num, &blkhist.cycle, &blkhist.cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); lbp = (uchar_ptr_t)malloc(blk_size); memcpy(lbp, blkhist.buffaddr, blk_size); if (((blk_hdr_ptr_t)lbp)->bsiz > blk_size) ((blk_hdr_ptr_t)lbp)->bsiz = blk_size; else if (((blk_hdr_ptr_t)lbp)->bsiz < SIZEOF(blk_hdr)) ((blk_hdr_ptr_t)lbp)->bsiz = SIZEOF(blk_hdr); b_top = lbp + ((blk_hdr_ptr_t)lbp)->bsiz; if (((blk_hdr_ptr_t)lbp)->levl) { if (cli_present("POINTER") != CLI_PRESENT) { util_out_print("Error: block pointer must be specified for this index block record.", TRUE); free(lbp); t_abort(gv_cur_region, cs_addrs); return; } if (!cli_get_hex("POINTER", (uint4 *)&blk)) { t_abort(gv_cur_region, cs_addrs); free(lbp); return; } if (blk < 0 || blk >= cs_addrs->ti->total_blks || !(blk % cs_addrs->hdr->bplmap)) { util_out_print("Error: pointer is an invalid block number.", TRUE); free(lbp); t_abort(gv_cur_region, cs_addrs); return; } MEMCP(&data[0], (char *)&blk, 0, SIZEOF(block_id), SIZEOF(block_id)); data_len = SIZEOF(block_id); } else { if (cli_present("DATA") != CLI_PRESENT) { util_out_print("Error: data must be specified for this data block record.", TRUE); free(lbp); t_abort(gv_cur_region, cs_addrs); return; } if (FALSE == dse_data(&data[0], &data_len)) { free(lbp); t_abort(gv_cur_region, cs_addrs); return; } if (key_len + data_len > cs_addrs->hdr->max_rec_size) { rts_error(VARLSTCNT(10) ERR_REC2BIG, 4, key_len + data_len, (int4)cs_addrs->hdr->max_rec_size, REG_LEN_STR(gv_cur_region), ERR_GVIS, 2, LEN_AND_STR(key)); } } if (cli_present("RECORD") == CLI_PRESENT) { if (!(rp = skan_rnum(lbp, TRUE))) { free(lbp); t_abort(gv_cur_region, cs_addrs); return; } } else if (cli_present("OFFSET") == CLI_PRESENT) { if (!(rp = skan_offset(lbp, TRUE))) { free(lbp); t_abort(gv_cur_region, cs_addrs); return; } } else { util_out_print("Error: must specify a record number or offset for the record to be added.", TRUE); free(lbp); t_abort(gv_cur_region, cs_addrs); return; } new_bp = (uchar_ptr_t)malloc(blk_size); size = (key_len < patch_comp_count) ? key_len : patch_comp_count; for (cc = 0; cc < size && patch_comp_key[cc] == key[cc]; cc++) ; SET_CMPC((rec_hdr_ptr_t)new_bp, cc); new_len = key_len - cc + data_len + SIZEOF(rec_hdr); PUT_SHORT(&((rec_hdr_ptr_t)new_bp)->rsiz, new_len); MEMCP(new_bp, &key[cc], SIZEOF(rec_hdr), key_len - cc, blk_size); MEMCP(new_bp, &data[0], SIZEOF(rec_hdr) + key_len - cc, data_len, blk_size); if (rp < b_top) { GET_SHORT(rsize, &((rec_hdr_ptr_t)rp)->rsiz); if (rsize < SIZEOF(rec_hdr)) r_top = rp + SIZEOF(rec_hdr); else r_top = rp + rsize; if (r_top >= b_top) r_top = b_top; if (((blk_hdr_ptr_t)lbp)->levl) key_top = r_top - SIZEOF(block_id); else { for (key_top = rp + SIZEOF(rec_hdr); key_top < r_top; ) if (!*key_top++ && !*key_top++) break; } if (EVAL_CMPC((rec_hdr_ptr_t)rp) > patch_comp_count) cc = patch_comp_count; else cc = EVAL_CMPC((rec_hdr_ptr_t)rp); size = key_top - rp - SIZEOF(rec_hdr); if (size > SIZEOF(patch_comp_key) - 2 - cc) size = SIZEOF(patch_comp_key) - 2 - cc; if (size < 0) size = 0; memcpy(&patch_comp_key[cc], rp + SIZEOF(rec_hdr), size); patch_comp_count = cc + size; size = (key_len < patch_comp_count) ? key_len : patch_comp_count; for (cc = 0; cc < size && patch_comp_key[cc] == key[cc]; cc++) ; SET_CMPC((rec_hdr_ptr_t)(new_bp + new_len), cc); rsize = patch_comp_count - cc + r_top - key_top + SIZEOF(rec_hdr); PUT_SHORT(&((rec_hdr_ptr_t)(new_bp + new_len))->rsiz, rsize); MEMCP(new_bp, &patch_comp_key[cc], new_len + SIZEOF(rec_hdr), patch_comp_count - cc, blk_size); MEMCP(new_bp, key_top, new_len + SIZEOF(rec_hdr) + patch_comp_count - cc, b_top - key_top, blk_size); new_len += patch_comp_count - cc + SIZEOF(rec_hdr) + b_top - key_top; } if (rp - lbp + new_len > blk_size) { util_out_print("Error: record too large for remaining space in block.", TRUE); free(lbp); free(new_bp); t_abort(gv_cur_region, cs_addrs); return; } memcpy(rp, new_bp, new_len); free(new_bp); ((blk_hdr_ptr_t)lbp)->bsiz += new_len + (unsigned int)(rp - b_top); BLK_INIT(bs_ptr, bs1); BLK_SEG(bs_ptr, (uchar_ptr_t)lbp + SIZEOF(blk_hdr), (int)((blk_hdr_ptr_t)lbp)->bsiz - SIZEOF(blk_hdr)); if (!BLK_FINI(bs_ptr, bs1)) { util_out_print("Error: bad blk build.", TRUE); free(lbp); t_abort(gv_cur_region, cs_addrs); return; } t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); free(lbp); return; } fis-gtm-V6.0-003/sr_port/dse_adstar.c0000644000032200000250000000756012201176155016317 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "gdscc.h" #include "cli.h" #include "copy.h" #include "filestruct.h" #include "jnl.h" #include "dse.h" /* Include prototypes */ #include "t_qread.h" #include "t_write.h" #include "t_end.h" #include "t_begin_crit.h" #include "gvcst_blk_build.h" #include "util.h" #include "t_abort.h" GBLREF char *update_array, *update_array_ptr; GBLREF gd_region *gv_cur_region; GBLREF uint4 update_array_size; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF srch_hist dummy_hist; GBLREF gd_addr *gd_header; GBLREF block_id patch_curr_blk; GBLREF cw_set_element cw_set[]; void dse_adstar(void) { uchar_ptr_t lbp, b_top; block_id blk; blk_segment *bs1, *bs_ptr; int4 blk_seg_cnt, blk_size; short rsize; int tmp_cmpc; srch_blk_status blkhist; error_def(ERR_DBRDONLY); error_def(ERR_DSEBLKRDFAIL); error_def(ERR_DSEFAIL); if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); CHECK_AND_RESET_UPDATE_ARRAY; /* reset update_array_ptr to update_array */ if (cli_present("BLOCK") == CLI_PRESENT) { if (!cli_get_hex("BLOCK", (uint4 *)&blk)) return; patch_curr_blk = blk; } if (patch_curr_blk < 0 || patch_curr_blk >= cs_addrs->ti->total_blks || !(patch_curr_blk % cs_addrs->hdr->bplmap)) { util_out_print("Error: invalid block number.", TRUE); return; } if (cli_present("POINTER") != CLI_PRESENT) { util_out_print("Error: block pointer must be specified.", TRUE); return; } if (!cli_get_hex("POINTER", (uint4 *)&blk)) return; t_begin_crit(ERR_DSEFAIL); blk_size = cs_addrs->hdr->blk_size; blkhist.blk_num = patch_curr_blk; if (!(blkhist.buffaddr = t_qread(blkhist.blk_num, &blkhist.cycle, &blkhist.cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); lbp = (uchar_ptr_t)malloc(blk_size); memcpy(lbp, blkhist.buffaddr, blk_size); if (!((blk_hdr_ptr_t)lbp)->levl) { util_out_print("Error: cannot add a star record to a data block.", TRUE); free(lbp); t_abort(gv_cur_region, cs_addrs); return; } if (((blk_hdr_ptr_t) lbp)->bsiz > blk_size) b_top = lbp + blk_size; else if (((blk_hdr_ptr_t) lbp)->bsiz < SIZEOF(blk_hdr)) b_top = lbp + SIZEOF(blk_hdr); else b_top = lbp + ((blk_hdr_ptr_t) lbp)->bsiz; if (b_top - lbp > blk_size - SIZEOF(rec_hdr) - SIZEOF(block_id)) { util_out_print("Error: not enough free space in block for a star record.", TRUE); free(lbp); t_abort(gv_cur_region, cs_addrs); return; } rsize = SIZEOF(rec_hdr) + SIZEOF(block_id); PUT_SHORT(&((rec_hdr_ptr_t)b_top)->rsiz, rsize); SET_CMPC((rec_hdr_ptr_t)b_top, 0); PUT_LONG((block_id_ptr_t)(b_top + SIZEOF(rec_hdr)), blk); ((blk_hdr_ptr_t)lbp)->bsiz += (unsigned int)(SIZEOF(rec_hdr) + SIZEOF(block_id)); BLK_INIT(bs_ptr, bs1); BLK_SEG(bs_ptr, (uchar_ptr_t)lbp + SIZEOF(blk_hdr), (int)((blk_hdr_ptr_t)lbp)->bsiz - SIZEOF(blk_hdr)); if (!BLK_FINI(bs_ptr, bs1)) { util_out_print("Error: bad blk build.", TRUE); free(lbp); t_abort(gv_cur_region, cs_addrs); return; } t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); free(lbp); return; } fis-gtm-V6.0-003/sr_port/dse_all.c0000644000032200000250000001565412201176155015614 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_stdio.h" #include "util.h" #include "cli.h" #include "gdsroot.h" #include "gt_timer.h" #include "gtmmsg.h" #if defined(UNIX) #include "gtm_ipc.h" #endif #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "gdskill.h" #include "gdscc.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "min_max.h" /* needed for init_root_gv.h */ #include "init_root_gv.h" #include "dse.h" #ifdef UNIX # include "mutex.h" #endif #include "wcs_flu.h" #include /* for VSIG_ATOMIC_T */ GBLREF VSIG_ATOMIC_T util_interrupt; GBLREF block_id patch_curr_blk; GBLREF gd_addr *gd_header; GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF short crash_count; GBLREF uint4 process_id; GBLREF gd_addr *original_header; GBLREF boolean_t dse_all_dump; /* TRUE if DSE ALL -DUMP is specified */ error_def(ERR_DBRDONLY); error_def(ERR_DSEWCINITCON); error_def(ERR_FREEZE); error_def(ERR_FREEZECTRL); void dse_all(void) { gd_region *ptr; tp_region *region_list, *rg, *rg_last, *rg_new; /* A handy structure for maintaining a list of regions */ int i, j; sgmnt_addrs *old_addrs, *csa; gd_region *old_region; block_id old_block; int4 stat; boolean_t ref = FALSE; boolean_t crit = FALSE; boolean_t wc = FALSE; boolean_t flush = FALSE; boolean_t freeze = FALSE; boolean_t nofreeze = FALSE; boolean_t seize = FALSE; boolean_t release = FALSE; boolean_t dump = FALSE; boolean_t override = FALSE; boolean_t was_crit; gd_addr *temp_gdaddr; gd_binding *map; UNIX_ONLY(char *fgets_res;) old_addrs = cs_addrs; old_region = gv_cur_region; old_block = patch_curr_blk; temp_gdaddr = gd_header; gd_header = original_header; if (cli_present("RENEW") == CLI_PRESENT) { crit = ref = wc = nofreeze = TRUE; GET_CONFIRM_AND_HANDLE_NEG_RESPONSE; } else { if (cli_present("CRITINIT") == CLI_PRESENT) crit = TRUE; if (cli_present("REFERENCE") == CLI_PRESENT) ref = TRUE; if (cli_present("WCINIT") == CLI_PRESENT) { GET_CONFIRM_AND_HANDLE_NEG_RESPONSE; wc = TRUE; } if (cli_present("BUFFER_FLUSH") == CLI_PRESENT) flush = TRUE; if (cli_present("SEIZE") == CLI_PRESENT) seize = TRUE; if (cli_present("RELEASE") == CLI_PRESENT) release = TRUE; stat = cli_present("FREEZE"); if (stat == CLI_NEGATED) nofreeze = TRUE; else if (stat == CLI_PRESENT) { freeze = TRUE; nofreeze = FALSE; } if (cli_present("OVERRIDE") == CLI_PRESENT) override = TRUE; if (cli_present("DUMP") == CLI_PRESENT) dump = TRUE; } if (!dump && gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); region_list = NULL; for (i = 0, ptr = gd_header->regions; i < gd_header->n_regions; i++, ptr++) { if (ptr->dyn.addr->acc_meth != dba_bg && ptr->dyn.addr->acc_meth != dba_mm) { util_out_print("Skipping region !AD: not BG or MM access",TRUE,ptr->rname_len,&ptr->rname[0]); continue; } if (!ptr->open) { util_out_print("Skipping region !AD as it is not bound to any namespace.", TRUE, ptr->rname_len, &ptr->rname[0]); continue; } if (dump) { gv_cur_region = ptr; cs_addrs = &FILE_INFO(gv_cur_region)->s_addrs; dse_all_dump = TRUE; dse_dmp_fhead(); assert(!dse_all_dump); /* should have been reset by "dse_dmp_fhead" */ } else { /* put on region list in order of ftok value so processed in same order that crits are obtained */ csa = &FILE_INFO(ptr)->s_addrs; insert_region(ptr, &(region_list), NULL, SIZEOF(tp_region)); } } if (!dump) { /* Now run the list of regions in the sorted ftok order to execute the desired commands */ for (rg = region_list; NULL != rg; rg = rg->fPtr) { gv_cur_region = rg->reg; switch(gv_cur_region->dyn.addr->acc_meth) { case dba_mm: case dba_bg: cs_addrs = &FILE_INFO(gv_cur_region)->s_addrs; break; default: GTMASSERT; } patch_curr_blk = get_dir_root(); if (crit) { UNIX_ONLY(gtm_mutex_init(gv_cur_region, NUM_CRIT_ENTRY(cs_addrs->hdr), TRUE)); VMS_ONLY(mutex_init(cs_addrs->critical, NUM_CRIT_ENTRY(cs_addrs->hdr), TRUE)); cs_addrs->nl->in_crit = 0; cs_addrs->hold_onto_crit = FALSE; /* reset this just before cs_addrs->now_crit is reset */ cs_addrs->now_crit = FALSE; } if (cs_addrs->critical) crash_count = cs_addrs->critical->crashcnt; if (freeze) { while (REG_ALREADY_FROZEN == region_freeze(gv_cur_region, TRUE, override, FALSE)) { hiber_start(1000); if (util_interrupt) { gtm_putmsg(VARLSTCNT(1) ERR_FREEZECTRL); break; } } if (freeze != !(cs_addrs->hdr->freeze)) util_out_print("Region !AD is now FROZEN", TRUE, REG_LEN_STR(gv_cur_region)); } was_crit = cs_addrs->now_crit; if (seize) { if (!was_crit) grab_crit(gv_cur_region); /* no point seizing crit if WE already have it held */ cs_addrs->hold_onto_crit = TRUE; /* need to do this AFTER grab_crit */ cs_addrs->dse_crit_seize_done = TRUE; } if (wc) { if (!was_crit && !seize) grab_crit(gv_cur_region); DSE_WCREINIT(cs_addrs); if (!was_crit && (!seize || release)) rel_crit(gv_cur_region); } if (flush) wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SYNC_EPOCH); if (release) { /* user wants crit to be released unconditionally so "was_crit" not checked like everywhere else */ if (cs_addrs->now_crit) { cs_addrs->dse_crit_seize_done = FALSE; cs_addrs->hold_onto_crit = FALSE; /* need to do this BEFORE rel_crit */ rel_crit(gv_cur_region); } else { assert(!cs_addrs->hold_onto_crit && !cs_addrs->dse_crit_seize_done); util_out_print("Current process does not own the Region: !AD.", TRUE, REG_LEN_STR(gv_cur_region)); } } if (nofreeze) { if (REG_ALREADY_FROZEN == region_freeze(gv_cur_region,FALSE, override, FALSE)) util_out_print("Region: !AD is frozen by another user, not releasing freeze",TRUE, REG_LEN_STR(gv_cur_region)); else util_out_print("Region !AD is now UNFROZEN", TRUE, REG_LEN_STR(gv_cur_region)); } if (ref) cs_addrs->nl->ref_cnt = 1; } } cs_addrs = old_addrs; gv_cur_region = old_region; patch_curr_blk = old_block; GET_SAVED_GDADDR(gd_header, temp_gdaddr, map, gv_cur_region); return; } fis-gtm-V6.0-003/sr_port/dse_b_dmp.c0000644000032200000250000002061612201176155016117 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "gdsbml.h" #include "cli.h" #include "dse.h" #include "util.h" /* Include prototypes */ #include "t_qread.h" #define REUSABLE_CHAR ":" #define FREE_CHAR "." #define BUSY_CHAR "X" #define CORRUPT_CHAR "?" #define MAX_UTIL_LEN 80 GBLREF VSIG_ATOMIC_T util_interrupt; GBLREF block_id patch_curr_blk; GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF int patch_is_fdmp; GBLREF int patch_fdmp_recs; GBLREF int patch_rec_counter; LITREF char *gtm_dbversion_table[]; error_def(ERR_BITMAPSBAD); error_def(ERR_CTRLC); error_def(ERR_DSEBLKRDFAIL); boolean_t dse_b_dmp(void) { int4 util_len, head, lmap_num, iter1, iter2, mapsize, bplmap, nocrit_present, dummy_int, len, count; unsigned char util_buff[MAX_UTIL_LEN], mask; boolean_t free, was_crit, was_hold_onto_crit, invalid_bitmap = FALSE, is_mm; block_id blk; sm_uc_ptr_t bp, b_top, rp, mb, dump_record(sm_uc_ptr_t rp, block_id blk, sm_uc_ptr_t bp, sm_uc_ptr_t b_top); cache_rec_ptr_t cr; enum db_ver ondsk_blkver; head = cli_present("HEADER"); if (CLI_PRESENT == cli_present("BLOCK")) { if (!cli_get_hex("BLOCK", (uint4 *)&blk)) return FALSE; if (blk < 0 || blk >= cs_addrs->ti->total_blks) { util_out_print("Error: invalid block number.", TRUE); return FALSE; } patch_curr_blk = blk; } else blk = patch_curr_blk; if (CLI_PRESENT == cli_present("COUNT")) { if (!cli_get_hex("COUNT", (uint4 *)&count)) return FALSE; if (count < 1) return FALSE; } else count = 1; util_out_print(0, TRUE); bplmap = cs_addrs->hdr->bplmap; is_mm = (dba_mm == cs_addrs->hdr->acc_meth); mapsize = BM_SIZE(bplmap); patch_rec_counter = 1; was_crit = cs_addrs->now_crit; nocrit_present = (CLI_NEGATED == cli_present("CRIT")); DSE_GRAB_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); for ( ; ; ) { if (blk / bplmap * bplmap != blk) { if (!(bp = t_qread(blk, &dummy_int, &cr))) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); } if (((blk_hdr_ptr_t) bp)->levl && patch_is_fdmp) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); util_out_print("Error: cannot perform GLO/ZWR dump on index block.", TRUE); return FALSE; } if (((blk_hdr_ptr_t) bp)->bsiz > cs_addrs->hdr->blk_size) b_top = bp + cs_addrs->hdr->blk_size; else if (((blk_hdr_ptr_t) bp)->bsiz < SIZEOF(blk_hdr)) b_top = bp + SIZEOF(blk_hdr); else b_top = bp + ((blk_hdr_ptr_t) bp)->bsiz; if (CLI_NEGATED != head && !patch_is_fdmp) { memcpy(util_buff, "Block ", 6); util_len = 6; util_len += i2hex_nofill(blk, &util_buff[util_len], 8); memcpy(&util_buff[util_len], " Size ", 8); util_len += 8; util_len += i2hex_nofill(((blk_hdr_ptr_t)bp)->bsiz, &util_buff[util_len], 8); memcpy(&util_buff[util_len], " Level !UL TN ", 18); util_len += 18; util_len += i2hexl_nofill(((blk_hdr_ptr_t)bp)->tn, &util_buff[util_len], 16); memcpy(&util_buff[util_len], " ", 1); util_len++; ondsk_blkver = (!is_mm ? cr->ondsk_blkver : GDSV6); len = STRLEN(gtm_dbversion_table[ondsk_blkver]); memcpy(&util_buff[util_len], gtm_dbversion_table[ondsk_blkver], len); util_len += len; memcpy(&util_buff[util_len], "!/", 2); util_len += 2; util_buff[util_len] = 0; util_out_print((caddr_t)util_buff, TRUE, ((blk_hdr_ptr_t) bp)->levl ); } rp = bp + SIZEOF(blk_hdr); if (CLI_PRESENT != head && (!patch_is_fdmp || ((blk_hdr_ptr_t) bp)->levl == 0)) { while (!util_interrupt && (rp = dump_record(rp, blk, bp, b_top))) patch_rec_counter += 1; } if (util_interrupt) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); rts_error(VARLSTCNT(1) ERR_CTRLC); break; } if (CLI_NEGATED == head) util_out_print(0, TRUE); } else if (!patch_is_fdmp) { if (!(bp = t_qread(blk, &dummy_int, &cr))) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); } if (CLI_NEGATED != head) { if (bplmap == 0) { memcpy(util_buff, "Block ", 6); util_len = 6; util_len += i2hex_nofill(blk, &util_buff[util_len], 8); memcpy(&util_buff[util_len], " Size ", 8); util_len += 8; util_len += i2hex_nofill(mapsize, &util_buff[util_len], 4); memcpy(&util_buff[util_len], " Master Status: Cannot Determine (bplmap == 0)!/", 50); util_len += 50; util_buff[util_len] = 0; util_out_print((caddr_t)util_buff, TRUE ); } else { mb = cs_addrs->bmm + blk / (8 * bplmap); lmap_num = blk / bplmap; mask = 1 << ( lmap_num - lmap_num / 8 * 8); free = mask & *mb; memcpy(util_buff, "Block ", 6); util_len = 6; util_len += i2hex_nofill(blk, &util_buff[util_len], 8); memcpy(&util_buff[util_len], " Size ", 7); util_len += 7; util_len += i2hex_nofill(((blk_hdr_ptr_t)bp)->bsiz, &util_buff[util_len], 8); memcpy(&util_buff[util_len], " Level !SB TN ", 16); util_len += 16; util_len += i2hexl_nofill(((blk_hdr_ptr_t)bp)->tn, &util_buff[util_len], 16); memcpy(&util_buff[util_len], " ", 1); util_len++; ondsk_blkver = (!is_mm ? cr->ondsk_blkver : GDSV6); len = STRLEN(gtm_dbversion_table[ondsk_blkver]); memcpy(&util_buff[util_len], gtm_dbversion_table[ondsk_blkver], len); util_len += len; util_buff[util_len] = 0; util_out_print((caddr_t)util_buff, FALSE, ((blk_hdr_ptr_t) bp)->levl ); util_len = 0; memcpy(&util_buff[util_len], " Master Status: !AD!/",23); util_len = 23; util_buff[util_len] = 0; util_out_print((caddr_t)util_buff, TRUE, free ? 10 : 4, free ? "Free Space" : "Full"); } } if (CLI_PRESENT != head) { util_out_print(" !_Low order High order", TRUE); lmap_num = 0; while (lmap_num < bplmap) { memcpy(util_buff, "Block ", 6); util_len = 6; i2hex_blkfill(blk + lmap_num, &util_buff[util_len], 8); util_len += 8; memcpy(&util_buff[util_len], ":!_| ", 6); util_len += 6; util_buff[util_len] = 0; util_out_print((caddr_t)util_buff, FALSE); for (iter1 = 0; iter1 < 4; iter1++) { for (iter2 = 0; iter2 < 8; iter2++) { mask = dse_lm_blk_free(lmap_num * BML_BITS_PER_BLK, bp + SIZEOF(blk_hdr)); if (!mask) util_out_print("!AD", FALSE, 1, BUSY_CHAR); else if (BLK_FREE == mask) util_out_print("!AD", FALSE, 1, FREE_CHAR); else if (BLK_RECYCLED == mask) util_out_print("!AD", FALSE, 1, REUSABLE_CHAR); else { invalid_bitmap = TRUE; util_out_print("!AD", FALSE, 1, CORRUPT_CHAR); } if (++lmap_num >= bplmap) break; } util_out_print(" ", FALSE); if (lmap_num >= bplmap) break; } util_out_print("|", TRUE); if (util_interrupt) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); rts_error(VARLSTCNT(1) ERR_CTRLC); } } util_out_print("!/'!AD' == BUSY '!AD' == FREE '!AD' == REUSABLE '!AD' == CORRUPT!/", TRUE,1, BUSY_CHAR, 1, FREE_CHAR, 1, REUSABLE_CHAR, 1, CORRUPT_CHAR); if (invalid_bitmap) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); rts_error(VARLSTCNT(1) ERR_BITMAPSBAD); } } } count--; if (count <= 0 || util_interrupt) break; blk++; if (blk >= cs_addrs->ti->total_blks) blk = 0; } patch_curr_blk = blk; DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); return TRUE; } fis-gtm-V6.0-003/sr_port/dse_cache.c0000644000032200000250000002435012201176155016100 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "cli.h" #include "gdsblk.h" #include "util.h" #include "dse.h" #include "stringpool.h" /* for GET_CURR_TIME_IN_DOLLARH_AND_ZDATE macro */ #include "op.h" /* for op_fnzdate and op_horolog prototype */ #include "wcs_recover.h" /* for wcs_recover prototype */ #include "wcs_phase2_commit_wait.h" #include "sleep_cnt.h" /* for SIGNAL_WRITERS_TO_STOP/RESUME and WAIT_FOR_WRITERS_TO_STOP macro */ #include "memcoherency.h" /* for SIGNAL_WRITERS_TO_STOP/RESUME and WAIT_FOR_WRITERS_TO_STOP macro */ #include "wcs_sleep.h" /* for SIGNAL_WRITERS_TO_STOP/RESUME and WAIT_FOR_WRITERS_TO_STOP macro */ GBLREF gd_region *gv_cur_region; GBLREF gd_addr *original_header; error_def(ERR_SIZENOTVALID4); #define DB_ABS2REL(X) ((sm_uc_ptr_t)(X) - (sm_uc_ptr_t)csa->nl) #define MAX_UTIL_LEN 40 #define CLEAN_VERIFY "verification is clean" #define UNCLEAN_VERIFY "verification is NOT clean (see operator log for details)" #define RECOVER_DONE "recovery complete (see operator log for details)" #define RECOVER_NOT_APPLIC "recovery not applicable with MM access method" error_def(ERR_SIZENOTVALID4); void dse_cache(void) { boolean_t all_present, change_present, recover_present, show_present, verify_present, was_crit, is_clean; boolean_t nocrit_present, offset_present, size_present, value_present; gd_region *reg, *r_top; sgmnt_addrs *csa; mval dollarh_mval, zdate_mval; int4 size; uint4 offset, value, old_value, lcnt; char dollarh_buffer[MAXNUMLEN], zdate_buffer[SIZEOF(DSE_DMP_TIME_FMT)]; char temp_str[256], temp_str1[256]; sm_uc_ptr_t chng_ptr; cache_rec_ptr_t cr_que_lo; boolean_t is_mm, was_hold_onto_crit, wc_blocked_ok; all_present = (CLI_PRESENT == cli_present("ALL")); recover_present = (CLI_PRESENT == cli_present("RECOVER")); verify_present = (CLI_PRESENT == cli_present("VERIFY")); change_present = (CLI_PRESENT == cli_present("CHANGE")); show_present = (CLI_PRESENT == cli_present("SHOW")); offset_present = (CLI_PRESENT == cli_present("OFFSET")); size_present = (CLI_PRESENT == cli_present("SIZE")); value_present = (CLI_PRESENT == cli_present("VALUE")); nocrit_present = (CLI_NEGATED == cli_present("CRIT")); assert(!nocrit_present || show_present); /* NOCRIT is only applicable for SHOW */ if (offset_present && !cli_get_hex("OFFSET", &offset)) return; if (size_present) { if (!cli_get_int("SIZE", &size)) return; if (!((SIZEOF(char) == size) || (SIZEOF(short) == size) || (SIZEOF(int4) == size))) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_SIZENOTVALID4); } if (value_present && !cli_get_hex("VALUE", &value)) return; assert(change_present || recover_present || show_present || verify_present); for (reg = original_header->regions, r_top = reg + original_header->n_regions; reg < r_top; reg++) { if (!all_present && (reg != gv_cur_region)) continue; if (!reg->open || reg->was_open) continue; is_mm = (dba_mm == reg->dyn.addr->acc_meth); csa = &FILE_INFO(reg)->s_addrs; assert(is_mm || (csa->db_addrs[0] == (sm_uc_ptr_t)csa->nl)); was_crit = csa->now_crit; DSE_GRAB_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, csa, reg); if (verify_present || recover_present) { GET_CURR_TIME_IN_DOLLARH_AND_ZDATE(dollarh_mval, dollarh_buffer, zdate_mval, zdate_buffer); if (verify_present) { /* Before invoking wcs_verify, wait for any pending phase2 commits to finish. Need to wait as * otherwise ongoing phase2 commits can result in cache verification returning FALSE (e.g. due to * DBCRERR message indicating that cr->in_tend is non-zero). * Also, need to wait for concurrent writers to stop to avoid wcs_verify from incorrectly concluding * that there is a problem with the active queue. */ wc_blocked_ok = UNIX_ONLY(TRUE) VMS_ONLY(!is_mm); /* MM on VMS doesn't support wcs_recvoer */ if (wc_blocked_ok) SIGNAL_WRITERS_TO_STOP(csa->nl); /* done sooner to avoid any new writers starting up */ if (csa->nl->wcs_phase2_commit_pidcnt && !is_mm) { /* No need to check return value since even if it fails, we want to do cache verification */ wcs_phase2_commit_wait(csa, NULL); } if (wc_blocked_ok) WAIT_FOR_WRITERS_TO_STOP(csa->nl, lcnt, MAXWTSTARTWAIT / 4); /* reduced wait time for DSE */ is_clean = wcs_verify(reg, FALSE, FALSE); /* expect_damage is FALSE, caller_is_wcs_recover is * FALSE */ if (wc_blocked_ok) SIGNAL_WRITERS_TO_RESUME(csa->nl); } else { if (UNIX_ONLY(TRUE)VMS_ONLY(!is_mm)) { SET_TRACEABLE_VAR(csa->nl->wc_blocked, TRUE); /* No need to invoke function "wcs_phase2_commit_wait" as "wcs_recover" does that anyways */ wcs_recover(reg); assert(FALSE == csa->nl->wc_blocked); /* wcs_recover() should have cleared this */ } } assert(20 == STR_LIT_LEN(DSE_DMP_TIME_FMT)); /* if they are not the same, the !20AD below should change */ util_out_print("Time !20AD : Region !12AD : Cache !AZ", TRUE, zdate_mval.str.len, zdate_mval.str.addr, REG_LEN_STR(reg), verify_present ? (is_clean ? CLEAN_VERIFY : UNCLEAN_VERIFY) : UNIX_ONLY(RECOVER_DONE) VMS_ONLY(is_mm ? RECOVER_NOT_APPLIC : RECOVER_DONE)); } else if (offset_present) { if ((csa->nl->sec_size VMS_ONLY(* OS_PAGELET_SIZE)) < (offset + size)) util_out_print("Region !12AD : Error: offset + size is greater than region's max_offset = 0x!XL", TRUE, REG_LEN_STR(reg), (csa->nl->sec_size VMS_ONLY(* OS_PAGELET_SIZE))); else { chng_ptr = (sm_uc_ptr_t)csa->nl + offset; if (SIZEOF(char) == size) { SPRINTF(temp_str, "!UB [0x!XB]"); old_value = *(sm_uc_ptr_t)chng_ptr; } else if (SIZEOF(short) == size) { SPRINTF(temp_str, "!UW [0x!XW]"); old_value = *(sm_ushort_ptr_t)chng_ptr; } else if (SIZEOF(int4) == size) { SPRINTF(temp_str, "!UL [0x!XL]"); old_value = *(sm_uint_ptr_t)chng_ptr; } if (value_present) { if (SIZEOF(char) == size) *(sm_uc_ptr_t)chng_ptr = value; else if (SIZEOF(short) == size) *(sm_ushort_ptr_t)chng_ptr = value; else if (SIZEOF(int4) == size) *(sm_uint_ptr_t)chng_ptr = value; } else value = old_value; if (show_present) { SPRINTF(temp_str1, "Region !12AD : Location !UL [0x!XL] : Value = %s :" " Size = !UB [0x!XB]", temp_str); util_out_print(temp_str1, TRUE, REG_LEN_STR(reg), offset, offset, value, value, size, size); } else { SPRINTF(temp_str1, "Region !12AD : Location !UL [0x!XL] : Old Value = %s : " "New Value = %s : Size = !UB [0x!XB]", temp_str, temp_str); util_out_print(temp_str1, TRUE, REG_LEN_STR(reg), offset, offset, old_value, old_value, value, value, size, size); } } } else { assert(show_present); /* this should be a DSE CACHE -SHOW command with no other qualifiers */ util_out_print("Region !AD : Shared_memory = 0x!XJ", TRUE, REG_LEN_STR(reg), csa->nl); util_out_print("Region !AD : node_local = 0x!XJ", TRUE, REG_LEN_STR(reg), DB_ABS2REL(csa->nl)); util_out_print("Region !AD : critical = 0x!XJ", TRUE, REG_LEN_STR(reg), DB_ABS2REL(csa->critical)); if (JNL_ALLOWED(csa)) { util_out_print("Region !AD : jnl_buffer_struct = 0x!XJ", TRUE, REG_LEN_STR(reg), DB_ABS2REL(csa->jnl->jnl_buff)); util_out_print("Region !AD : jnl_buffer_data = 0x!XJ", TRUE, REG_LEN_STR(reg), DB_ABS2REL(&csa->jnl->jnl_buff->buff[csa->jnl->jnl_buff->buff_off])); } util_out_print("Region !AD : shmpool_buffer = 0x!XJ", TRUE, REG_LEN_STR(reg), DB_ABS2REL(csa->shmpool_buffer)); util_out_print("Region !AD : lock_space = 0x!XJ", TRUE, REG_LEN_STR(reg), DB_ABS2REL(csa->lock_addrs[0])); if (!is_mm) { util_out_print("Region !AD : cache_queues_state = 0x!XJ", TRUE, REG_LEN_STR(reg), DB_ABS2REL(csa->acc_meth.bg.cache_state)); cr_que_lo = &csa->acc_meth.bg.cache_state->cache_array[0]; util_out_print("Region !AD : cache_que_header = 0x!XJ : Numelems = 0x!XL : Elemsize = 0x!XL", TRUE, REG_LEN_STR(reg), DB_ABS2REL(cr_que_lo), csa->hdr->bt_buckets, SIZEOF(cache_rec)); util_out_print("Region !AD : cache_record = 0x!XJ : Numelems = 0x!XL : Elemsize = 0x!XL", TRUE, REG_LEN_STR(reg), DB_ABS2REL(cr_que_lo + csa->hdr->bt_buckets), csa->hdr->n_bts, SIZEOF(cache_rec)); util_out_print("Region !AD : global_buffer = 0x!XJ : Numelems = 0x!XL : Elemsize = 0x!XL", TRUE, REG_LEN_STR(reg), ROUND_UP2(DB_ABS2REL(cr_que_lo + csa->hdr->bt_buckets + csa->hdr->n_bts), OS_PAGE_SIZE), csa->hdr->n_bts, csa->hdr->blk_size); util_out_print("Region !AD : db_file_header = 0x!XJ", TRUE, REG_LEN_STR(reg), DB_ABS2REL(csa->hdr)); util_out_print("Region !AD : bt_que_header = 0x!XJ : Numelems = 0x!XL : Elemsize = 0x!XL", TRUE, REG_LEN_STR(reg), DB_ABS2REL(csa->bt_header), csa->hdr->bt_buckets, SIZEOF(bt_rec)); util_out_print("Region !AD : th_base = 0x!XJ", TRUE, REG_LEN_STR(reg), DB_ABS2REL(csa->th_base)); util_out_print("Region !AD : bt_record = 0x!XJ : Numelems = 0x!XL : Elemsize = 0x!XL", TRUE, REG_LEN_STR(reg), DB_ABS2REL(csa->bt_base), csa->hdr->n_bts, SIZEOF(bt_rec)); util_out_print("Region !AD : shared_memory_size = 0x!XL", TRUE, REG_LEN_STR(reg), csa->nl->sec_size VMS_ONLY(* OS_PAGELET_SIZE)); } else { util_out_print("Region !AD : shared_memory_size = 0x!XL", TRUE, REG_LEN_STR(reg), csa->nl->sec_size VMS_ONLY(* OS_PAGELET_SIZE)); util_out_print("Region !AD : db_file_header = 0x!XJ", TRUE, REG_LEN_STR(reg), csa->hdr); } } DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, csa, reg); } return; } fis-gtm-V6.0-003/sr_port/dse_chng_bhead.c0000644000032200000250000002176112201176155017102 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_time.h" #include "gdsroot.h" #include "gdskill.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "gdsbml.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "gdscc.h" #include "filestruct.h" #include "jnl.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "cli.h" #include "send_msg.h" #include "dse.h" /* Include prototypes */ #include "t_qread.h" #include "t_write.h" #include "t_end.h" #include "t_begin_crit.h" #include "process_deferred_stale.h" #include "util.h" #include "t_abort.h" #include "gvcst_blk_build.h" /* for the BUILD_AIMG_IF_JNL_ENABLED macro */ #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif GBLREF char *update_array, *update_array_ptr; GBLREF uint4 update_array_size; GBLREF srch_hist dummy_hist; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF block_id patch_curr_blk; GBLREF gd_region *gv_cur_region; GBLREF gd_addr *gd_header; GBLREF cache_rec *cr_array[((MAX_BT_DEPTH * 2) - 1) * 2]; /* Maximum number of blocks that can be in transaction */ GBLREF boolean_t unhandled_stale_timer_pop; GBLREF cw_set_element cw_set[]; error_def(ERR_DSEBLKRDFAIL); error_def(ERR_DSEFAIL); error_def(ERR_DBRDONLY); void dse_chng_bhead(void) { block_id blk; int4 x; trans_num tn; cache_rec_ptr_t cr; blk_hdr new_hdr; blk_segment *bs1, *bs_ptr; int4 blk_seg_cnt, blk_size; /* needed for BLK_INIT,BLK_SEG and BLK_FINI macros */ boolean_t ismap; boolean_t chng_blk; boolean_t was_crit; boolean_t was_hold_onto_crit; uint4 mapsize; srch_blk_status blkhist; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; # ifdef GTM_CRYPT int req_enc_blk_size; int gtmcrypt_errno; blk_hdr_ptr_t bp, save_bp, save_old_block; gd_segment *seg; # endif if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); CHECK_AND_RESET_UPDATE_ARRAY; /* reset update_array_ptr to update_array */ chng_blk = FALSE; csa = cs_addrs; if (cli_present("BLOCK") == CLI_PRESENT) { if (!cli_get_hex("BLOCK", (uint4 *)&blk)) return; if (blk < 0 || blk > csa->ti->total_blks) { util_out_print("Error: invalid block number.", TRUE); return; } patch_curr_blk = blk; } csd = csa->hdr; assert(csd == cs_data); blk_size = csd->blk_size; ismap = (patch_curr_blk / csd->bplmap * csd->bplmap == patch_curr_blk); mapsize = BM_SIZE(csd->bplmap); t_begin_crit(ERR_DSEFAIL); blkhist.blk_num = patch_curr_blk; if (!(blkhist.buffaddr = t_qread(blkhist.blk_num, &blkhist.cycle, &blkhist.cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); new_hdr = *(blk_hdr_ptr_t)blkhist.buffaddr; if (cli_present("LEVEL") == CLI_PRESENT) { if (!cli_get_hex("LEVEL", (uint4 *)&x)) { t_abort(gv_cur_region, csa); return; } if (ismap && (unsigned char)x != LCL_MAP_LEVL) { util_out_print("Error: invalid level for a bit map block.", TRUE); t_abort(gv_cur_region, csa); return; } if (!ismap && (x < 0 || x > MAX_BT_DEPTH + 1)) { util_out_print("Error: invalid level.", TRUE); t_abort(gv_cur_region, csa); return; } new_hdr.levl = (unsigned char)x; chng_blk = TRUE; if (new_hdr.bsiz < SIZEOF(blk_hdr)) new_hdr.bsiz = SIZEOF(blk_hdr); if (new_hdr.bsiz > blk_size) new_hdr.bsiz = blk_size; } if (cli_present("BSIZ") == CLI_PRESENT) { if (!cli_get_hex("BSIZ", (uint4 *)&x)) { t_abort(gv_cur_region, csa); return; } if (ismap && x != mapsize) { util_out_print("Error: invalid bsiz.", TRUE); t_abort(gv_cur_region, csa); return; } else if (x < SIZEOF(blk_hdr) || x > blk_size) { util_out_print("Error: invalid bsiz.", TRUE); t_abort(gv_cur_region, csa); return; } chng_blk = TRUE; new_hdr.bsiz = x; } if (!chng_blk) t_abort(gv_cur_region, csa); else { BLK_INIT(bs_ptr, bs1); BLK_SEG(bs_ptr, blkhist.buffaddr + SIZEOF(new_hdr), new_hdr.bsiz - SIZEOF(new_hdr)); if (!BLK_FINI(bs_ptr, bs1)) { util_out_print("Error: bad block build.", TRUE); t_abort(gv_cur_region, csa); return; } t_write(&blkhist, (unsigned char *)bs1, 0, 0, new_hdr.levl, TRUE, FALSE, GDS_WRITE_KILLTN); BUILD_AIMG_IF_JNL_ENABLED(csd, csa->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); } if (cli_present("TN") == CLI_PRESENT) { if (!cli_get_hex64("TN", &tn)) return; was_crit = csa->now_crit; t_begin_crit(ERR_DSEFAIL); CHECK_TN(csa, csd, csd->trans_hist.curr_tn); /* can issue rts_error TNTOOLARGE */ assert(csa->ti->early_tn == csa->ti->curr_tn); if (NULL == (blkhist.buffaddr = t_qread(blkhist.blk_num, &blkhist.cycle, &blkhist.cr))) { util_out_print("Error: Unable to read buffer.", TRUE); t_abort(gv_cur_region, csa); return; } if (new_hdr.bsiz < SIZEOF(blk_hdr)) new_hdr.bsiz = SIZEOF(blk_hdr); if (new_hdr.bsiz > blk_size) new_hdr.bsiz = blk_size; BLK_INIT(bs_ptr, bs1); BLK_SEG(bs_ptr, blkhist.buffaddr + SIZEOF(new_hdr), new_hdr.bsiz - SIZEOF(new_hdr)); BLK_FINI(bs_ptr, bs1); t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)blkhist.buffaddr)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); /* Pass the desired tn as argument to bg_update/mm_update below */ BUILD_AIMG_IF_JNL_ENABLED(csd, tn); was_hold_onto_crit = csa->hold_onto_crit; csa->hold_onto_crit = TRUE; /* need this so t_end doesn't release crit (see below comment for why) */ t_end(&dummy_hist, NULL, tn); # ifdef GTM_CRYPT if (csd->is_encrypted && (tn < csa->ti->curr_tn)) { /* BG and db encryption is enabled and the DSE update caused the block-header to potentially have a tn * that is LESS than what it had before. At this point, the global buffer (corresponding to blkhist.blk_num) * reflects the contents of the block AFTER the dse update (bg_update would have touched this) whereas * the corresponding encryption global buffer reflects the contents of the block BEFORE the update. * Normally wcs_wtstart takes care of propagating the tn update from the regular global buffer to the * corresponding encryption buffer. But if before it gets a chance, let us say a process goes to t_end * as part of a subsequent transaction and updates this same block. Since the blk-hdr-tn potentially * decreased, it is possible that the PBLK writing check (comparing blk-hdr-tn with the epoch_tn) decides * to write a PBLK for this block (even though a PBLK was already written for this block as part of a * previous DSE CHANGE -BL -TN in the same epoch). In this case, since the db is encrypted, the logic * will assume there were no updates to this block since the last time wcs_wtstart updated the encryption * buffer and therefore use that to write the pblk, which is incorrect since it does not yet contain the * tn update. The consequence of this is would be writing an older before-image PBLK) record to the * journal file. To prevent this situation, we update the encryption buffer here (before releasing crit) * using logic like that in wcs_wtstart to ensure it is in sync with the regular global buffer. To ensure * that t_end doesn't release crit, we set csa->hold_onto_crit to TRUE * Note: * Although we use cw_set[0] to access the global buffer corresponding to the block number being updated, * cw_set_depth at this point is 0 because t_end resets it. This is considered safe since cw_set is a * static array (as opposed to malloc'ed memory) and hence is always available and valid until it gets * overwritten by subsequent updates. */ bp = (blk_hdr_ptr_t)GDS_ANY_REL2ABS(csa, cw_set[0].cr->buffaddr); DBG_ENSURE_PTR_IS_VALID_GLOBUFF(csa, csd, (sm_uc_ptr_t)bp); save_bp = (blk_hdr_ptr_t)GDS_ANY_ENCRYPTGLOBUF(bp, csa); DBG_ENSURE_PTR_IS_VALID_ENCTWINGLOBUFF(csa, csd, (sm_uc_ptr_t)save_bp); assert((bp->bsiz <= csd->blk_size) && (bp->bsiz >= SIZEOF(*bp))); req_enc_blk_size = MIN(csd->blk_size, bp->bsiz) - SIZEOF(*bp); if (BLK_NEEDS_ENCRYPTION(bp->levl, req_enc_blk_size)) { ASSERT_ENCRYPTION_INITIALIZED; memcpy(save_bp, bp, SIZEOF(blk_hdr)); GTMCRYPT_ENCRYPT(csa, csa->encr_key_handle, (char *)(bp + 1), req_enc_blk_size, (char *)(save_bp + 1), gtmcrypt_errno); if (0 != gtmcrypt_errno) { seg = gv_cur_region->dyn.addr; GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, seg->fname_len, seg->fname); } } else memcpy(save_bp, bp, bp->bsiz); } # endif csa->hold_onto_crit = was_hold_onto_crit; if (!was_crit) rel_crit(gv_cur_region); if (unhandled_stale_timer_pop) process_deferred_stale(); } return; } fis-gtm-V6.0-003/sr_port/dse_chng_fhead.c0000644000032200000250000006352112201176155017106 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /******************************************************************************* * * MODULE NAME: CHANGE_FHEAD * * CALLING SEQUENCE: void change_fhead() * * DESCRIPTION: This module changes values of certain fields * of the file header. The only range-checking * takes place on input, not in this routine, allowing * the user maximum control. * * HISTORY: * *******************************************************************************/ #include "gtm_string.h" #include "mdef.h" #include "gtm_stdlib.h" #include "gtm_unistd.h" #include "gtm_stdio.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "cli.h" #include "timersp.h" #include "jnl.h" #include "util.h" #include "gtm_caseconv.h" #include "gt_timer.h" #include "timers.h" #include "send_msg.h" #include "dse.h" #include "gtmmsg.h" #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif GBLREF VSIG_ATOMIC_T util_interrupt; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data *cs_data; GBLREF gd_region *gv_cur_region; GBLREF uint4 process_id; GBLREF uint4 image_count; LITREF char *gtm_dbversion_table[]; error_def(ERR_FREEZE); error_def(ERR_BLKSIZ512); error_def(ERR_DBRDONLY); error_def(ERR_SIZENOTVALID8); error_def(ERR_FREEZECTRL); void dse_chng_fhead(void) { int4 x, index_x, save_x, fname_len; unsigned short buf_len; boolean_t was_crit, was_hold_onto_crit, corrupt_file_present; boolean_t override = FALSE; int4 nocrit_present; int4 location_present, value_present, size_present, size; uint4 location; boolean_t max_tn_present, max_tn_warn_present, curr_tn_present, change_tn; gtm_uint64_t value, old_value; seq_num seq_no; trans_num tn, prev_tn, max_tn_old, max_tn_warn_old, curr_tn_old, max_tn_new, max_tn_warn_new, curr_tn_new; char temp_str[256], temp_str1[256], buf[MAX_LINE], *fname_ptr; int gethostname_res; sm_uc_ptr_t chng_ptr; const char *freeze_msg[] = { "UNFROZEN", "FROZEN" } ; # ifdef GTM_CRYPT char hash_buff[GTMCRYPT_HASH_LEN]; int gtmcrypt_errno; # endif DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); memset(temp_str, 0, 256); memset(temp_str1, 0, 256); memset(buf, 0, MAX_LINE); was_crit = cs_addrs->now_crit; /* If the user requested DSE CHANGE -FILE -CORRUPT, then skip the check in grab_crit, which triggers an rts_error, as this * is one of the ways of turning off the file_corrupt flag in the file header */ TREF(skip_file_corrupt_check) = corrupt_file_present = (CLI_PRESENT == cli_present("CORRUPT_FILE")); nocrit_present = (CLI_NEGATED == cli_present("CRIT")); DSE_GRAB_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); TREF(skip_file_corrupt_check) = FALSE; /* Now that grab_crit is done, reset the global variable */ if (CLI_PRESENT == cli_present("OVERRIDE")) override = TRUE; # ifdef VMS if (cs_data->freeze && (cs_data->freeze != process_id || cs_data->image_count != image_count) && !override) # endif # ifdef UNIX if (cs_data->freeze && (cs_data->image_count != process_id) && !override) # endif { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); util_out_print("Region: !AD is frozen by another user, not releasing freeze.", TRUE, REG_LEN_STR(gv_cur_region)); rts_error(VARLSTCNT(4) ERR_FREEZE, 2, REG_LEN_STR(gv_cur_region)); return; } prev_tn = cs_addrs->ti->curr_tn; location_present = FALSE; if (CLI_PRESENT == cli_present("LOCATION")) { location_present = TRUE; if (!cli_get_hex("LOCATION", &location)) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); return; } } if (CLI_PRESENT == cli_present("HEXLOCATION")) { location_present = TRUE; if (!cli_get_hex("HEXLOCATION", &location)) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); return; } } if (CLI_PRESENT == cli_present("DECLOCATION")) { location_present = TRUE; if (!cli_get_int("DECLOCATION", (int4 *)&location)) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); return; } } size_present = FALSE; if (CLI_PRESENT == cli_present("SIZE")) { size_present = TRUE; if (!cli_get_int("SIZE", &size)) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); return; } } value_present = FALSE; if (CLI_PRESENT == cli_present("VALUE")) { value_present = TRUE; if (!cli_get_hex64("VALUE", (gtm_uint64_t *)&value)) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); return; } } if (CLI_PRESENT == cli_present("HEXVALUE")) { value_present = TRUE; if (!cli_get_hex64("HEXVALUE", &value)) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); return; } } if (CLI_PRESENT == cli_present("DECVALUE")) { value_present = TRUE; if (!cli_get_uint64("DECVALUE", (gtm_uint64_t *)&value)) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); return; } } if (TRUE == location_present) { if (FALSE == size_present) size = SIZEOF(int4); if (!((SIZEOF(char) == size) || (SIZEOF(short) == size) || (SIZEOF(int4) == size) || (SIZEOF(gtm_int64_t) == size))) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); rts_error(VARLSTCNT(1) ERR_SIZENOTVALID8); } if ((0 > (int4)size) || ((uint4)SGMNT_HDR_LEN < (uint4)location) || ((uint4)SGMNT_HDR_LEN < ((uint4)location + (uint4)size))) util_out_print("Error: Cannot modify any location outside the file-header", TRUE); else if (0 != location % size) util_out_print("Error: Location !UL [0x!XL] should be a multiple of Size !UL", TRUE, location, location, size, size); else { chng_ptr = (sm_uc_ptr_t)cs_data + location; if (SIZEOF(char) == size) { SPRINTF(temp_str, "!UB [0x!XB]"); old_value = *(sm_uc_ptr_t)chng_ptr; } else if (SIZEOF(short) == size) { SPRINTF(temp_str, "!UW [0x!XW]"); old_value = *(sm_ushort_ptr_t)chng_ptr; } else if (SIZEOF(int4) == size) { SPRINTF(temp_str, "!UL [0x!XL]"); old_value = *(sm_uint_ptr_t)chng_ptr; } else if (SIZEOF(gtm_int64_t) == size) { SPRINTF(temp_str, "!@UQ [0x!@XQ]"); old_value = *(qw_num_ptr_t)chng_ptr; } if (value_present) { if (SIZEOF(char) == size) *(sm_uc_ptr_t)chng_ptr = (unsigned char) value; else if (SIZEOF(short) == size) *(sm_ushort_ptr_t)chng_ptr = (unsigned short) value; else if (SIZEOF(int4) == size) *(sm_uint_ptr_t)chng_ptr = (unsigned int) value; else if (SIZEOF(gtm_int64_t) == size) *(qw_num_ptr_t)chng_ptr = value; } else value = old_value; SPRINTF(temp_str1, "Location !UL [0x!XL] : Old Value = %s : New Value = %s : Size = !UB [0x!XB]", temp_str, temp_str); if (SIZEOF(int4) >= size) util_out_print(temp_str1, TRUE, location, location, (uint4)old_value, (uint4)old_value, (uint4)value, (uint4)value, size, size); else util_out_print(temp_str1, TRUE, location, location, &old_value, &old_value, &value, &value, size, size); } } if ((CLI_PRESENT == cli_present("TOTAL_BLKS")) && (cli_get_hex("TOTAL_BLKS", (uint4 *)&x))) cs_addrs->ti->total_blks = x; if ((CLI_PRESENT == cli_present("BLOCKS_FREE")) && (cli_get_hex("BLOCKS_FREE", (uint4 *)&x))) cs_addrs->ti->free_blocks = x; if ((CLI_PRESENT == cli_present("BLK_SIZE")) && (cli_get_int("BLK_SIZE", &x))) { if (!(x % DISK_BLOCK_SIZE) && (0 != x)) cs_data->blk_size = x; else { cs_data->blk_size = ((x/DISK_BLOCK_SIZE) + 1) * DISK_BLOCK_SIZE; gtm_putmsg(VARLSTCNT(4) ERR_BLKSIZ512, 2, x, cs_data->blk_size); } } if ((CLI_PRESENT == cli_present("RECORD_MAX_SIZE")) && (cli_get_int("RECORD_MAX_SIZE", &x))) { cs_data->max_rec_size = x; gv_cur_region->max_rec_size = x; } if ((CLI_PRESENT == cli_present("KEY_MAX_SIZE")) && (cli_get_int("KEY_MAX_SIZE", &x))) { if (cs_data->max_key_size > x) cs_data->maxkeysz_assured = FALSE; cs_data->max_key_size = x; gv_cur_region->max_key_size = x; } if ((CLI_PRESENT == cli_present("INHIBIT_KILLS")) && (cli_get_int("INHIBIT_KILLS", &x))) { cs_addrs->nl->inhibit_kills = x; } if (CLI_PRESENT == cli_present("INTERRUPTED_RECOV")) { x = cli_t_f_n("INTERRUPTED_RECOV"); if (1 == x) cs_data->recov_interrupted = TRUE; else if (0 == x) cs_data->recov_interrupted = FALSE; } if ((CLI_PRESENT == cli_present("REFERENCE_COUNT")) && (cli_get_int("REFERENCE_COUNT", &x))) cs_addrs->nl->ref_cnt = x; if ((CLI_PRESENT == cli_present("RESERVED_BYTES")) && (cli_get_int("RESERVED_BYTES", &x))) cs_data->reserved_bytes = x; if ((CLI_PRESENT == cli_present("DEF_COLLATION")) && (cli_get_int("DEF_COLLATION", &x))) cs_data->def_coll = x; if (CLI_PRESENT == cli_present("NULL_SUBSCRIPTS")) { x = cli_n_a_e("NULL_SUBSCRIPTS"); if (-1 != x) gv_cur_region->null_subs = cs_data->null_subs = (unsigned char)x; } if (CLI_PRESENT == cli_present("CERT_DB_VER")) { buf_len = SIZEOF(buf); if (cli_get_str("CERT_DB_VER", buf, &buf_len)) { lower_to_upper((uchar_ptr_t)buf, (uchar_ptr_t)buf, buf_len); for (index_x=0; index_x < GDSVLAST ; index_x++) if (0 == STRCMP(buf, gtm_dbversion_table[index_x])) { cs_data->certified_for_upgrade_to = (enum db_ver)index_x; break; } if (GDSVLAST <= index_x) util_out_print("Invalid value for CERT_DB_VER qualifier", TRUE); } } if (CLI_PRESENT == cli_present("DB_WRITE_FMT")) { buf_len = SIZEOF(buf); if (cli_get_str("DB_WRITE_FMT", buf, &buf_len)) { lower_to_upper((uchar_ptr_t)buf, (uchar_ptr_t)buf, buf_len); for (index_x=0; index_x < GDSVLAST ; index_x++) if (0 == STRCMP(buf, gtm_dbversion_table[index_x])) { cs_data->desired_db_format = (enum db_ver)index_x; cs_data->fully_upgraded = FALSE; break; } if (GDSVLAST <= index_x) util_out_print("Invalid value for DB_WRITE_FMT qualifier", TRUE); } } /* ---------- Begin ------ CURRENT_TN/MAX_TN/WARN_MAX_TN processing -------- */ max_tn_old = cs_data->max_tn; if ((CLI_PRESENT == cli_present("MAX_TN")) && (cli_get_hex64("MAX_TN", &max_tn_new))) max_tn_present = TRUE; else { max_tn_present = FALSE; max_tn_new = max_tn_old; } max_tn_warn_old = cs_data->max_tn_warn; if ((CLI_PRESENT == cli_present("WARN_MAX_TN")) && (cli_get_hex64("WARN_MAX_TN", &max_tn_warn_new))) max_tn_warn_present = TRUE; else { max_tn_warn_present = FALSE; max_tn_warn_new = max_tn_warn_old; } curr_tn_old = cs_addrs->ti->curr_tn; if ((CLI_PRESENT == cli_present("CURRENT_TN")) && (cli_get_hex64("CURRENT_TN", &curr_tn_new))) curr_tn_present = TRUE; else { curr_tn_present = FALSE; curr_tn_new = curr_tn_old; } change_tn = TRUE; if (max_tn_present) { if (max_tn_new < max_tn_warn_new) { change_tn = FALSE; util_out_print("MAX_TN value cannot be less than the current/specified value of WARN_MAX_TN", TRUE); } } if (max_tn_warn_present) { if (!max_tn_present && (max_tn_warn_new > max_tn_new)) { change_tn = FALSE; util_out_print("WARN_MAX_TN value cannot be greater than the current/specified value of MAX_TN", TRUE); } if (max_tn_warn_new < curr_tn_new) { change_tn = FALSE; util_out_print("WARN_MAX_TN value cannot be less than the current/specified value of CURRENT_TN", TRUE); } } if (curr_tn_present) { if (!max_tn_warn_present && (curr_tn_new > max_tn_warn_new)) { change_tn = FALSE; util_out_print("CURRENT_TN value cannot be greater than the current/specified value of WARN_MAX_TN", TRUE); } } if (change_tn) { if (max_tn_present) cs_data->max_tn = max_tn_new; if (max_tn_warn_present) cs_data->max_tn_warn = max_tn_warn_new; if (curr_tn_present) cs_addrs->ti->curr_tn = cs_addrs->ti->early_tn = curr_tn_new; assert(max_tn_new == cs_data->max_tn); assert(max_tn_warn_new == cs_data->max_tn_warn); assert(curr_tn_new == cs_addrs->ti->curr_tn); assert(max_tn_new >= max_tn_warn_new); assert(max_tn_warn_new >= curr_tn_new); } else { /* if (max_tn_present) util_out_print("MAX_TN value not changed", TRUE); if (max_tn_warn_present) util_out_print("WARN_MAX_TN value not changed", TRUE); if (curr_tn_present) util_out_print("CURRENT_TN value not changed", TRUE); */ assert(max_tn_old == cs_data->max_tn); assert(max_tn_warn_old == cs_data->max_tn_warn); assert(curr_tn_old == cs_addrs->ti->curr_tn); } /* ---------- End ------ CURRENT_TN/MAX_TN/WARN_MAX_TN processing -------- */ if (CLI_PRESENT == cli_present("REG_SEQNO") && cli_get_hex64("REG_SEQNO", (gtm_uint64_t *)&seq_no)) cs_data->reg_seqno = seq_no; UNIX_ONLY( if (CLI_PRESENT == cli_present("STRM_NUM")) { assert(CLI_PRESENT == cli_present("STRM_REG_SEQNO")); if (cli_get_int("STRM_NUM", &x) && (0 <= x) && (MAX_SUPPL_STRMS > x) && (CLI_PRESENT == cli_present("STRM_REG_SEQNO")) && cli_get_hex64("STRM_REG_SEQNO", (gtm_uint64_t *)&seq_no)) cs_data->strm_reg_seqno[x] = seq_no; } ) VMS_ONLY( if (CLI_PRESENT == cli_present("RESYNC_SEQNO") && cli_get_hex64("RESYNC_SEQNO", (gtm_uint64_t *)&seq_no)) cs_data->resync_seqno = seq_no; if (CLI_PRESENT == cli_present("RESYNC_TN") && cli_get_hex64("RESYNC_TN", &tn)) cs_data->resync_tn = tn; ) UNIX_ONLY( if (CLI_PRESENT == cli_present("ZQGBLMOD_SEQNO") && cli_get_hex64("ZQGBLMOD_SEQNO", (gtm_uint64_t *)&seq_no)) cs_data->zqgblmod_seqno = seq_no; if (CLI_PRESENT == cli_present("ZQGBLMOD_TN") && cli_get_hex64("ZQGBLMOD_TN", &tn)) cs_data->zqgblmod_tn = tn; ) if (CLI_PRESENT == cli_present("STDNULLCOLL")) { if ( -1 != (x = cli_t_f_n("STDNULLCOLL"))) gv_cur_region->std_null_coll = cs_data->std_null_coll = x; } if (corrupt_file_present) { x = cli_t_f_n("CORRUPT_FILE"); if (1 == x) cs_data->file_corrupt = TRUE; else if (0 == x) cs_data->file_corrupt = FALSE; } if ((CLI_PRESENT == cli_present("TIMERS_PENDING")) && (cli_get_int("TIMERS_PENDING", &x))) cs_addrs->nl->wcs_timers = x - 1; change_fhead_timer("FLUSH_TIME", cs_data->flush_time, (dba_bg == cs_data->acc_meth ? TIM_FLU_MOD_BG : TIM_FLU_MOD_MM), FALSE); if ((CLI_PRESENT == cli_present("WRITES_PER_FLUSH")) && (cli_get_int("WRITES_PER_FLUSH", &x))) cs_data->n_wrt_per_flu = x; if ((CLI_PRESENT == cli_present("TRIGGER_FLUSH")) && (cli_get_int("TRIGGER_FLUSH", &x))) cs_data->flush_trigger = x; if ((CLI_PRESENT == cli_present("GOT2V5ONCE")) && (cli_get_int("GOT2V5ONCE", &x))) cs_data->db_got_to_v5_once = (boolean_t)x; change_fhead_timer("STALENESS_TIMER", cs_data->staleness, 5000, TRUE); change_fhead_timer("TICK_INTERVAL", cs_data->ccp_tick_interval, 100, TRUE); change_fhead_timer("QUANTUM_INTERVAL", cs_data->ccp_quantum_interval, 1000, FALSE); change_fhead_timer("RESPONSE_INTERVAL", cs_data->ccp_response_interval, 60000, FALSE); if ((CLI_PRESENT == cli_present("B_BYTESTREAM")) && (cli_get_hex64("B_BYTESTREAM", &tn))) cs_data->last_inc_backup = tn; if ((CLI_PRESENT == cli_present("B_COMPREHENSIVE")) && (cli_get_hex64("B_COMPREHENSIVE", &tn))) cs_data->last_com_backup = tn; if ((CLI_PRESENT == cli_present("B_DATABASE")) && (cli_get_hex64("B_DATABASE", &tn))) cs_data->last_com_backup = tn; if ((CLI_PRESENT == cli_present("B_INCREMENTAL")) && (cli_get_hex64("B_INCREMENTAL", &tn))) cs_data->last_inc_backup = tn; if ((CLI_PRESENT == cli_present("WAIT_DISK")) && (cli_get_int("WAIT_DISK", &x))) cs_data->wait_disk_space = (x >= 0 ? x : 0); if (((CLI_PRESENT == cli_present("HARD_SPIN_COUNT")) && cli_get_int("HARD_SPIN_COUNT", &x)) UNIX_ONLY( || ((CLI_PRESENT == cli_present("MUTEX_HARD_SPIN_COUNT")) && cli_get_int("MUTEX_HARD_SPIN_COUNT", &x))) ) /* Unix should be backward compatible, accept MUTEX_ prefix qualifiers as well */ { if (0 < x) cs_data->mutex_spin_parms.mutex_hard_spin_count = x; else util_out_print("Error: HARD SPIN COUNT should be a non zero positive number", TRUE); } if (((CLI_PRESENT == cli_present("SLEEP_SPIN_COUNT")) && cli_get_int("SLEEP_SPIN_COUNT", &x)) UNIX_ONLY( || ((CLI_PRESENT == cli_present("MUTEX_SLEEP_SPIN_COUNT")) && cli_get_int("MUTEX_SLEEP_SPIN_COUNT", &x))) ) /* Unix should be backward compatible, accept MUTEX_ prefix qualifiers as well */ { if (0 < x) cs_data->mutex_spin_parms.mutex_sleep_spin_count = x; else util_out_print("Error: SLEEP SPIN COUNT should be a non zero positive number", TRUE); } if (((CLI_PRESENT == cli_present("SPIN_SLEEP_TIME")) && cli_get_int("SPIN_SLEEP_TIME", &x)) UNIX_ONLY( || ((CLI_PRESENT == cli_present("MUTEX_SPIN_SLEEP_TIME")) && cli_get_int("MUTEX_SPIN_SLEEP_TIME", &x))) ) /* Unix should be backward compatible, accept MUTEX_ prefix qualifiers as well */ { if (x < 0) util_out_print("Error: SPIN SLEEP TIME should be non negative", TRUE); else { save_x = x; for (index_x = 0; 0 != x; x >>= 1, index_x++); if (index_x <= 1) x = index_x; else if ((1 << (index_x - 1)) == save_x) x = save_x - 1; else x = (1 << index_x) - 1; if (x > 999999) util_out_print("Error: SPIN SLEEP TIME should be less than one million micro seconds", TRUE); else cs_data->mutex_spin_parms.mutex_spin_sleep_mask = x; } } UNIX_ONLY( if ((CLI_PRESENT == cli_present("COMMITWAIT_SPIN_COUNT")) && cli_get_int("COMMITWAIT_SPIN_COUNT", &x)) { if (0 <= x) cs_data->wcs_phase2_commit_wait_spincnt = x; else util_out_print("Error: COMMITWAIT SPIN COUNT should be a positive number", TRUE); } ) if ((CLI_PRESENT == cli_present("B_RECORD")) && (cli_get_hex64("B_RECORD", &tn))) cs_data->last_rec_backup = tn; if ((CLI_PRESENT == cli_present("BLKS_TO_UPGRADE")) && (cli_get_hex("BLKS_TO_UPGRADE", (uint4 *)&x))) { cs_data->blks_to_upgrd = x; cs_data->fully_upgraded = FALSE; } if ((CLI_PRESENT == cli_present("MBM_SIZE")) && (cli_get_int("MBM_SIZE", &x))) cs_data->master_map_len = x * DISK_BLOCK_SIZE; if (cs_data->clustered) { if (cs_addrs->ti->curr_tn == prev_tn) { CHECK_TN(cs_addrs, cs_data, cs_addrs->ti->curr_tn);/* can issue rts_error TNTOOLARGE */ cs_addrs->ti->early_tn++; INCREMENT_CURR_TN(cs_data); } } if ((CLI_PRESENT == cli_present("RC_SRV_COUNT")) && (cli_get_int("RC_SRV_COUNT", &x))) cs_data->rc_srv_cnt = x; if (CLI_PRESENT == cli_present("FREEZE")) { x = cli_t_f_n("FREEZE"); if (1 == x) { while (REG_ALREADY_FROZEN == region_freeze(gv_cur_region, TRUE, override, FALSE)) { hiber_start(1000); if (util_interrupt) { gtm_putmsg(VARLSTCNT(1) ERR_FREEZECTRL); break; } } } else if (0 == x) { if (REG_ALREADY_FROZEN == region_freeze(gv_cur_region, FALSE, override, FALSE)) { util_out_print("Region: !AD is frozen by another user, not releasing freeze.", TRUE, REG_LEN_STR(gv_cur_region)); } } if (x != !(cs_data->freeze)) util_out_print("Region !AD is now !AD", TRUE, REG_LEN_STR(gv_cur_region), LEN_AND_STR(freeze_msg[x])); cs_addrs->persistent_freeze = x; /* secshr_db_clnup() shouldn't clear the freeze up */ } if (CLI_PRESENT == cli_present("FULLY_UPGRADED") && cli_get_int("FULLY_UPGRADED", &x)) { cs_data->fully_upgraded = (boolean_t)x; if (x) cs_data->db_got_to_v5_once = TRUE; } if (CLI_PRESENT == cli_present("GVSTATSRESET")) { /* Clear statistics in NODE-LOCAL first */ # define TAB_GVSTATS_REC(COUNTER,TEXT1,TEXT2) cs_addrs->nl->gvstats_rec.COUNTER = 0; # include "tab_gvstats_rec.h" # undef TAB_GVSTATS_REC /* Do it in the file-header next */ gvstats_rec_cnl2csd(cs_addrs); } if (CLI_PRESENT == cli_present("ONLINE_NBB")) { buf_len = SIZEOF(buf); if (cli_get_str("ONLINE_NBB", buf, &buf_len)) { lower_to_upper((uchar_ptr_t)buf, (uchar_ptr_t)buf, buf_len); if (0 == STRCMP(buf, "NOT_IN_PROGRESS")) cs_addrs->nl->nbb = BACKUP_NOT_IN_PROGRESS; else { if (('0' == buf[0]) && ('\0' == buf[1])) x = 0; else { x = ATOI(buf); if (0 == x) x = -2; } if (x < -1) util_out_print("Invalid value for online_nbb qualifier", TRUE); else cs_addrs->nl->nbb = x; } } } if (CLI_PRESENT == cli_present("ABANDONED_KILLS")) { buf_len = SIZEOF(buf); if (cli_get_str("ABANDONED_KILLS", buf, &buf_len)) { lower_to_upper((uchar_ptr_t)buf, (uchar_ptr_t)buf, buf_len); if (0 == STRCMP(buf, "NONE")) cs_data->abandoned_kills = 0; else { if (('0' == buf[0]) && ('\0' == buf[1])) x = 0; else { x = ATOI(buf); if (0 == x) x = -1; } if (0 > x) util_out_print("Invalid value for abandoned_kills qualifier", TRUE); else cs_data->abandoned_kills = x; } } } if (CLI_PRESENT == cli_present("KILL_IN_PROG")) { buf_len = SIZEOF(buf); if (cli_get_str("KILL_IN_PROG", buf, &buf_len)) { lower_to_upper((uchar_ptr_t)buf, (uchar_ptr_t)buf, buf_len); if (0 == STRCMP(buf, "NONE")) cs_data->kill_in_prog = 0; else { if (('0' == buf[0]) && ('\0' == buf[1])) x = 0; else { x = ATOI(buf); if (0 == x) x = -1; } if (0 > x) util_out_print("Invalid value for kill_in_prog qualifier", TRUE); else cs_data->kill_in_prog = x; } } } if (CLI_PRESENT == cli_present("MACHINE_NAME")) { buf_len = SIZEOF(buf); if (cli_get_str("MACHINE_NAME", buf, &buf_len)) { lower_to_upper((uchar_ptr_t)buf, (uchar_ptr_t)buf, buf_len); if (0 == STRCMP(buf, "CURRENT")) { memset(cs_data->machine_name, 0, MAX_MCNAMELEN); GETHOSTNAME(cs_data->machine_name, MAX_MCNAMELEN, gethostname_res); } else if (0 == STRCMP(buf, "CLEAR")) memset(cs_data->machine_name, 0, MAX_MCNAMELEN); else util_out_print("Invalid value for the machine_name qualifier", TRUE); } else util_out_print("Error: cannot get value for !AD.", TRUE, LEN_AND_LIT("MACHINE_NAME")); } # ifdef GTM_CRYPT if (CLI_PRESENT == cli_present("ENCRYPTION_HASH")) { if (1 < cs_addrs->nl->ref_cnt) { util_out_print("Cannot reset encryption hash in file header while !XL other processes are " "accessing the database.", TRUE, cs_addrs->nl->ref_cnt - 1); return; } fname_ptr = (char *)gv_cur_region->dyn.addr->fname; fname_len = gv_cur_region->dyn.addr->fname_len; ASSERT_ENCRYPTION_INITIALIZED; /* Now generate the new hash to be placed in the database file header. */ GTMCRYPT_HASH_GEN(cs_addrs, fname_ptr, fname_len, hash_buff, gtmcrypt_errno); if (0 != gtmcrypt_errno) GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, fname_len, fname_ptr); memcpy(cs_data->encryption_hash, hash_buff, GTMCRYPT_HASH_LEN); DEBUG_ONLY(GTMCRYPT_HASH_CHK(cs_addrs, cs_data->encryption_hash, gtmcrypt_errno)); assert(0 == gtmcrypt_errno); } # endif # ifdef UNIX if (CLI_PRESENT == cli_present("JNL_YIELD_LIMIT") && cli_get_int("JNL_YIELD_LIMIT", &x)) { if (0 > x) util_out_print("YIELD_LIMIT cannot be NEGATIVE", TRUE); else if (MAX_YIELD_LIMIT < x) util_out_print("YIELD_LIMIT cannot be greater than !UL", TRUE, MAX_YIELD_LIMIT); else cs_data->yield_lmt = x; } if (CLI_PRESENT == cli_present("QDBRUNDOWN")) { cs_data->mumps_can_bypass = TRUE; util_out_print("Database file !AD now has quick database rundown flag set to TRUE", TRUE, DB_LEN_STR(gv_cur_region)); } else if (CLI_NEGATED == cli_present("QDBRUNDOWN")) { cs_data->mumps_can_bypass = FALSE; util_out_print("Database file !AD now has quick database rundown flag set to FALSE", TRUE, DB_LEN_STR(gv_cur_region)); } # endif if (CLI_PRESENT == cli_present(UNIX_ONLY("JNL_SYNCIO") VMS_ONLY("JNL_CACHE"))) { x = cli_t_f_n(UNIX_ONLY("JNL_SYNCIO") VMS_ONLY("JNL_CACHE")); if (1 == x) cs_data->jnl_sync_io = UNIX_ONLY(TRUE) VMS_ONLY(FALSE); else if (0 == x) cs_data->jnl_sync_io = UNIX_ONLY(FALSE) VMS_ONLY(TRUE); } if ((CLI_PRESENT == cli_present("AVG_BLKS_READ")) && (cli_get_int("AVG_BLKS_READ", &x))) { if (x <= 0) util_out_print("Invalid value for AVG_BLKS_READ qualifier", TRUE); else cs_data->avg_blks_per_100gbl = x; } if ((CLI_PRESENT == cli_present("PRE_READ_TRIGGER_FACTOR")) && (cli_get_int("PRE_READ_TRIGGER_FACTOR", &x))) { if ((x < 0) || (x > 100)) util_out_print("Invalid value for PRE_READ_TRIGGER_FACTOR qualifier", TRUE); else cs_data->pre_read_trigger_factor = x; } if ((CLI_PRESENT == cli_present("UPD_RESERVED_AREA")) && (cli_get_int("UPD_RESERVED_AREA", &x))) { if ((x < 0) || (x > 100)) util_out_print("Invalid value for UPD_RESERVED_AREA qualifier", TRUE); else cs_data->reserved_for_upd = x; } if ((CLI_PRESENT == cli_present("UPD_WRITER_TRIGGER_FACTOR")) && (cli_get_int("UPD_WRITER_TRIGGER_FACTOR", &x))) { if ((x < 0) || (x > 100)) util_out_print("Invalid value for UPD_WRITER_TRIGGER_FACTOR qualifier", TRUE); else cs_data->writer_trigger_factor = x; } DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); return; } fis-gtm-V6.0-003/sr_port/dse_chng_rhead.c0000644000032200000250000001045212201176155017115 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "gdscc.h" #include "cli.h" #include "copy.h" #include "filestruct.h" #include "jnl.h" #include "skan_offset.h" #include "skan_rnum.h" #include "dse.h" /* Include prototypes */ #include "t_qread.h" #include "t_write.h" #include "t_end.h" #include "t_begin_crit.h" #include "gvcst_blk_build.h" #include "util.h" #include "t_abort.h" GBLREF char *update_array, *update_array_ptr; GBLREF gd_region *gv_cur_region; GBLREF uint4 update_array_size; GBLREF srch_hist dummy_hist; GBLREF block_id patch_curr_blk; GBLREF unsigned short patch_comp_count; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF gd_addr *gd_header; GBLREF cw_set_element cw_set[]; void dse_chng_rhead(void) { block_id blk; sm_uc_ptr_t bp, b_top, cp, rp; boolean_t chng_rec; rec_hdr new_rec; uint4 x; blk_segment *bs1, *bs_ptr; int4 blk_seg_cnt, blk_size; int tmp_cmpc; srch_blk_status blkhist; error_def(ERR_DBRDONLY); error_def(ERR_DSEBLKRDFAIL); error_def(ERR_DSEFAIL); if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); CHECK_AND_RESET_UPDATE_ARRAY; /* reset update_array_ptr to update_array */ if (cli_present("BLOCK") == CLI_PRESENT) { if(!cli_get_hex("BLOCK", (uint4 *)&blk)) return; patch_curr_blk = blk; } if (patch_curr_blk < 0 || patch_curr_blk >= cs_addrs->ti->total_blks || !(patch_curr_blk % cs_addrs->hdr->bplmap)) { util_out_print("Error: invalid block number.", TRUE); return; } t_begin_crit(ERR_DSEFAIL); blkhist.blk_num = patch_curr_blk; if (!(blkhist.buffaddr = t_qread(blkhist.blk_num, &blkhist.cycle, &blkhist.cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); bp = blkhist.buffaddr; blk_size = cs_addrs->hdr->blk_size; chng_rec = FALSE; b_top = bp + ((blk_hdr_ptr_t)bp)->bsiz; if (((blk_hdr_ptr_t)bp)->bsiz > blk_size || ((blk_hdr_ptr_t)bp)->bsiz < SIZEOF(blk_hdr)) chng_rec = TRUE; /* force rewrite to correct size */ if (cli_present("RECORD") == CLI_PRESENT) { if (!(rp = skan_rnum(bp, FALSE))) { t_abort(gv_cur_region, cs_addrs); return; } } else if (!(rp = skan_offset(bp, FALSE))) { t_abort(gv_cur_region, cs_addrs); return; } GET_SHORT(new_rec.rsiz, &((rec_hdr_ptr_t)rp)->rsiz); SET_CMPC(&new_rec, EVAL_CMPC((rec_hdr_ptr_t)rp)); if (cli_present("CMPC") == CLI_PRESENT) { if (!cli_get_hex("CMPC", &x)) { t_abort(gv_cur_region, cs_addrs); return; } if (x >= MAX_KEY_SZ) { util_out_print("Error: invalid cmpc.",TRUE); t_abort(gv_cur_region, cs_addrs); return; } if (x > patch_comp_count) util_out_print("Warning: specified compression count is larger than the current expanded key size.", TRUE); SET_CMPC(&new_rec, x); chng_rec = TRUE; } if (cli_present("RSIZ") == CLI_PRESENT) { if (!cli_get_hex("RSIZ", &x)) { t_abort(gv_cur_region, cs_addrs); return; } if (x < SIZEOF(rec_hdr) || x > blk_size) { util_out_print("Error: invalid rsiz.", TRUE); t_abort(gv_cur_region, cs_addrs); return; } new_rec.rsiz = x; chng_rec = TRUE; } if (chng_rec) { BLK_INIT(bs_ptr, bs1); cp = bp; cp += SIZEOF(blk_hdr); if (chng_rec) { BLK_SEG(bs_ptr, cp, rp - cp); BLK_SEG(bs_ptr, (uchar_ptr_t)&new_rec, SIZEOF(rec_hdr)); cp = rp + SIZEOF(rec_hdr); } if (b_top - cp) BLK_SEG(bs_ptr, cp, b_top - cp); if (!BLK_FINI(bs_ptr, bs1)) { util_out_print("Error: bad blk build.", TRUE); t_abort(gv_cur_region, cs_addrs); return; } t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)bp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); } return; } fis-gtm-V6.0-003/sr_port/dse_crit.c0000644000032200000250000001505012201176155015773 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gdsbt.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsfhead.h" #include "cli.h" #include "lockconst.h" #include "wcs_recover.h" #include "dse.h" #include "tp_change_reg.h" /* for tp_change_reg() prototype */ #ifdef UNIX #include "mutex.h" #endif #include "util.h" GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF uint4 process_id; GBLREF short crash_count; GBLREF gd_addr *original_header; error_def(ERR_DBRDONLY); #define MAX_UTIL_LEN 80 void dse_crit(void) { int util_len, dse_crit_count; char util_buff[MAX_UTIL_LEN]; boolean_t crash = FALSE, cycle = FALSE, owner = FALSE; gd_region *save_region, *r_local, *r_top; crash = ((cli_present("CRASH") == CLI_PRESENT) || (cli_present("RESET") == CLI_PRESENT)); cycle = (CLI_PRESENT == cli_present("CYCLE")); if (cli_present("SEIZE") == CLI_PRESENT || cycle) { if (gv_cur_region->read_only && !cycle) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); if (cs_addrs->now_crit) { util_out_print("!/Write critical section already seized.!/", TRUE); return; } crash_count = cs_addrs->critical->crashcnt; grab_crit(gv_cur_region); cs_addrs->hold_onto_crit = TRUE; /* need to do this AFTER grab_crit */ cs_addrs->dse_crit_seize_done = TRUE; util_out_print("!/Seized write critical section.!/", TRUE); if (!cycle) return; } if (cli_present("RELEASE") == CLI_PRESENT || cycle) { if (gv_cur_region->read_only && !cycle) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); if (!cs_addrs->now_crit) { util_out_print("!/Critical section already released.!/", TRUE); return; } crash_count = cs_addrs->critical->crashcnt; if (cs_addrs->now_crit) { /* user wants crit to be released unconditionally so "was_crit" not checked like everywhere else */ assert(cs_addrs->hold_onto_crit && cs_addrs->dse_crit_seize_done); cs_addrs->dse_crit_seize_done = FALSE; cs_addrs->hold_onto_crit = FALSE; /* need to do this before the rel_crit */ rel_crit(gv_cur_region); util_out_print("!/Released write critical section.!/", TRUE); } # ifdef DEBUG else assert(!cs_addrs->hold_onto_crit && !cs_addrs->dse_crit_seize_done); # endif return; } if (cli_present("INIT") == CLI_PRESENT) { if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); cs_addrs->hdr->image_count = 0; UNIX_ONLY(gtm_mutex_init(gv_cur_region, NUM_CRIT_ENTRY(cs_addrs->hdr), crash)); VMS_ONLY(mutex_init(cs_addrs->critical, NUM_CRIT_ENTRY(cs_addrs->hdr), crash)); cs_addrs->nl->in_crit = 0; cs_addrs->now_crit = FALSE; util_out_print("!/Reinitialized critical section.!/", TRUE); return; } if (cli_present("REMOVE") == CLI_PRESENT) { if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); if (cs_addrs->nl->in_crit == 0) { util_out_print("!/The write critical section is unowned!/", TRUE); return; } UNIX_ONLY(assert(LOCK_AVAILABLE != cs_addrs->critical->semaphore.u.parts.latch_pid);) VMS_ONLY(assert(cs_addrs->critical->semaphore >= 0);) cs_addrs->now_crit = TRUE; cs_addrs->nl->in_crit = process_id; crash_count = cs_addrs->critical->crashcnt; /* user wants crit to be removed unconditionally so "was_crit" not checked (before rel_crit) like everywhere else */ if (dba_bg == cs_addrs->hdr->acc_meth) { wcs_recover(gv_cur_region); /* In case, this crit was obtained through a CRIT -SEIZE, csa->hold_onto_crit would have been set to * TRUE. Set that back to FALSE now that we are going to release control of crit. */ cs_addrs->hold_onto_crit = FALSE; /* need to do this before the rel_crit */ cs_addrs->dse_crit_seize_done = FALSE; rel_crit(gv_cur_region); util_out_print("!/Removed owner of write critical section!/", TRUE); } else { /* In case, this crit was obtained through a CRIT -SEIZE, csa->hold_onto_crit would have been set to * TRUE. Set that back to FALSE now that we are going to release control of crit. */ cs_addrs->hold_onto_crit = FALSE; /* need to do this before the rel_crit */ cs_addrs->dse_crit_seize_done = FALSE; rel_crit(gv_cur_region); util_out_print("!/Removed owner of write critical section!/", TRUE); util_out_print("!/WARNING: No recovery because database is MM.!/", TRUE); } return; } if (crash) { memcpy(util_buff, "!/Critical section crash count is ", 34); util_len = 34; util_len += i2hex_nofill(cs_addrs->critical->crashcnt, (uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len], "!/", 2); util_len += 2; util_buff[util_len] = 0; util_out_print(util_buff, TRUE); return; } if (cli_present("ALL") == CLI_PRESENT) { dse_crit_count = 0; save_region = gv_cur_region; for (r_local = original_header->regions, r_top = r_local + original_header->n_regions; r_local < r_top; r_local++) { if (!r_local->open || r_local->was_open) continue; gv_cur_region = r_local; tp_change_reg(); if (cs_addrs->nl->in_crit) { dse_crit_count++; UNIX_ONLY(util_out_print("Database !AD : CRIT Owned by pid [!UL]", TRUE, DB_LEN_STR(gv_cur_region), cs_addrs->nl->in_crit);) VMS_ONLY(util_out_print("Database !AD : CRIT owned by pid [0x!XL]", TRUE, DB_LEN_STR(gv_cur_region), cs_addrs->nl->in_crit);) } } if (0 == dse_crit_count) util_out_print("CRIT is currently unowned on all regions", TRUE); gv_cur_region = save_region; tp_change_reg(); return; } if (cs_addrs->nl->in_crit) { # if defined(UNIX) util_out_print("!/Write critical section owner is process id !UL", TRUE, cs_addrs->nl->in_crit); if (cs_addrs->now_crit) util_out_print("DSE (process id: !UL) owns the write critical section", TRUE, process_id); # elif defined(VMS) util_out_print("!/Write critical section owner is process id !XL", TRUE, cs_addrs->nl->in_crit); if (cs_addrs->now_crit) util_out_print("DSE (process id: !XL) owns the write critical section", TRUE, process_id); # endif util_out_print(0, TRUE); } else util_out_print("!/Write critical section is currently unowned", TRUE); return; } fis-gtm-V6.0-003/sr_port/dse_data.c0000644000032200000250000000315012201176155015741 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "cli.h" #include "dse.h" int dse_data(char *dst, int *len) { unsigned short cli_len; char buf[MAX_LINE],*src,*bot,*top; cli_len = SIZEOF(buf); if (!cli_get_str("DATA",buf,&cli_len)) return FALSE; bot = dst; top = &buf[cli_len - 1]; src = &buf[0]; #ifdef VMS if (buf[0] == '"') src = &buf[1]; #endif for (; src <= top ;src++) { #ifdef VMS if (src == top && *src == '"') break; #endif if (*src == '\\') { src++; if (*src == '\\') { *dst++ = '\\'; continue; } if (*src >= '0' && *src <= '9') *dst = *src - '0'; else if (*src >= 'a' && *src <= 'f') *dst = *src - 'a' + 10; else if (*src >= 'A' && *src <= 'F') *dst = *src - 'A' +10; else continue; src++; if (*src >= '0' && *src <= '9') *dst = (*dst << 4) + *src - '0'; else if (*src >= 'a' && *src <= 'f') *dst = (*dst << 4) + *src - 'a' + 10; else if (*src >= 'A' && *src <= 'F') *dst = (*dst << 4) + *src - 'A' +10; dst++; } else *dst++ = *src; } *len = (int)(dst - bot); return TRUE; } fis-gtm-V6.0-003/sr_port/dse_dmp.c0000644000032200000250000000505712201176155015620 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "cli.h" #include "dse.h" #include "error.h" #include "util.h" GBLDEF enum dse_fmt dse_dmp_format = CLOSED_FMT; GBLREF boolean_t patch_is_fdmp; GBLREF int patch_fdmp_recs; #define MESS_OFF SIZEOF("; ") - 1 CONDITION_HANDLER(dse_dmp_handler) { START_CH; PRN_ERROR; util_out_print("!/DSE is not able to complete the dump to file due to the above reason.!/", TRUE); UNWIND(NULL,NULL); } static char *format_label[] = {"; BAD", "; GLO", "; ZWR"}; /* CLOSE_FMT == 0, GLO_FMT == 1 and ZWR_FMT == 2 */ void dse_dmp(void) { boolean_t dmp_res, glo_present, zwr_present; patch_fdmp_recs = 0; glo_present = (CLI_PRESENT == cli_present("GLO")); zwr_present = (CLI_PRESENT == cli_present("ZWR")); if (glo_present || zwr_present) { if (CLOSED_FMT == dse_dmp_format) { util_out_print("Error: must open an output file before dump.", TRUE); return; } if (gtm_utf8_mode && (GLO_FMT == glo_present)) { util_out_print("Error: GLO format is not supported in UTF-8 mode. Use ZWR format.", TRUE); return; } if (OPEN_FMT == dse_dmp_format) { dse_dmp_format = (glo_present ? GLO_FMT : ZWR_FMT); if (!gtm_utf8_mode) dse_fdmp_output(LIT_AND_LEN("; DSE EXTRACT")); else dse_fdmp_output(LIT_AND_LEN("; DSE EXTRACT UTF-8")); dse_fdmp_output(STR_AND_LEN(format_label[dse_dmp_format])); } else if ((glo_present ? GLO_FMT : ZWR_FMT) != dse_dmp_format) { util_out_print("Error: current output file already contains !AD records.", TRUE, LEN_AND_STR(&format_label[dse_dmp_format][MESS_OFF])); return; } patch_is_fdmp = TRUE; ESTABLISH(dse_dmp_handler); } else patch_is_fdmp = FALSE; if (CLI_PRESENT == cli_present("RECORD") || CLI_PRESENT == cli_present("OFFSET")) dmp_res = dse_r_dmp(); else dmp_res = dse_b_dmp(); if (patch_is_fdmp) { REVERT; if (dmp_res) util_out_print("!UL !AD records written.!/", TRUE, patch_fdmp_recs, LEN_AND_STR(&format_label[dse_dmp_format][MESS_OFF])); } return; } fis-gtm-V6.0-003/sr_port/dse_dmp_fhead.c0000644000032200000250000006463612201176155016757 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /******************************************************************************* * * MODULE NAME: DSE_DMP_FHEAD * * CALLING SEQUENCE: void dse_dmp_fhead () * * DESCRIPTION: This module dumps certain fields of current file * header. * * HISTORY: * *******************************************************************************/ #include "mdef.h" #include "gtm_string.h" #include /* needed for handling of epoch_interval (EPOCH_SECOND2SECOND macro uses ceil) */ #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "cli.h" #include "util.h" #include "dse.h" #include "dse_puttime.h" #include "gtmmsg.h" #include "stringpool.h" /* for GET_CURR_TIME_IN_DOLLARH_AND_ZDATE macro */ #include "op.h" #include "shmpool.h" /* Needed for the shmpool structures */ #ifdef GTM_SNAPSHOT #include "db_snapshot.h" #endif #define MAX_UTIL_LEN 64 #define NEXT_EPOCH_TIME_SPACES " " /* 19 spaces, we have 19 character field width to output Next Epoch Time */ GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF boolean_t dse_all_dump; /* TRUE if DSE ALL -DUMP is specified */ GBLDEF mval dse_dmp_time_fmt = DEFINE_MVAL_STRING(MV_STR, 0, 0, STR_LIT_LEN(DSE_DMP_TIME_FMT), DSE_DMP_TIME_FMT, 0, 0); LITREF char *jrt_label[JRT_RECTYPES]; LITREF char *gtm_dbversion_table[]; #define SHOW_STAT(TEXT, VARIABLE) if (0 != csd->VARIABLE##_cntr) \ util_out_print(TEXT" 0x!XL Transaction = 0x!16@XQ", TRUE, (csd->VARIABLE##_cntr), \ (&csd->VARIABLE##_tn)); #define SHOW_DB_CSH_STAT(csd, COUNTER, TEXT1, TEXT2) \ if (csd->COUNTER.curr_count || csd->COUNTER.cumul_count) \ { \ util_out_print(TEXT1" 0x!XL "TEXT2" 0x!XL", TRUE, (csd->COUNTER.curr_count), \ (csd->COUNTER.cumul_count + csd->COUNTER.curr_count)); \ } #define SHOW_GVSTATS_STAT(cnl, COUNTER, TEXT1, TEXT2) \ { \ if (cnl->gvstats_rec.COUNTER) \ util_out_print(" " TEXT1 " : " TEXT2" 0x!16@XQ", TRUE, (&cnl->gvstats_rec.COUNTER)); \ } /* NEED_TO_DUMP is only for the qualifiers other than "BASIC" and "ALL". file_header is not dumped only if "NOBASIC" is explicitly specified */ #define NEED_TO_DUMP(string) \ (is_dse_all ? (CLI_PRESENT == cli_present("ALL")) \ : (CLI_PRESENT == cli_present(string) || CLI_PRESENT == cli_present("ALL") && CLI_NEGATED != cli_present(string))) void dse_dmp_fhead (void) { boolean_t jnl_buff_open; unsigned char util_buff[MAX_UTIL_LEN], buffer[MAXNUMLEN]; int util_len, rectype, time_len, index; uint4 jnl_status; enum jnl_state_codes jnl_state; gds_file_id zero_fid; mval dollarh_mval, zdate_mval; char dollarh_buffer[MAXNUMLEN], zdate_buffer[SIZEOF(DSE_DMP_TIME_FMT)]; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; node_local_ptr_t cnl; jnl_private_control *jpc; jnl_buffer_ptr_t jb; shmpool_buff_hdr_ptr_t bptr; boolean_t is_dse_all; uint4 pid; boolean_t new_line; unsigned char outbuf[GTMCRYPT_HASH_HEX_LEN + 1]; GTM_SNAPSHOT_ONLY( shm_snapshot_t *ss_shm_ptr;) is_dse_all = dse_all_dump; dse_all_dump = FALSE; csa = cs_addrs; csd = csa->hdr; cnl = csa->nl; jnl_state = (enum jnl_state_codes)csd->jnl_state; VMS_ONLY( memset(&zero_fid, 0, SIZEOF(zero_fid)); jnl_buff_open = (0 != memcmp(cnl->jnl_file.jnl_file_id.fid, zero_fid.fid, SIZEOF(zero_fid.fid))); ) UNIX_ONLY( jnl_buff_open = (0 != cnl->jnl_file.u.inode); ) if (is_dse_all || (CLI_NEGATED != cli_present("BASIC"))) { util_out_print("!/File !AD", TRUE, gv_cur_region->dyn.addr->fname_len, &gv_cur_region->dyn.addr->fname[0]); util_out_print("Region !AD", TRUE, gv_cur_region->rname_len, &gv_cur_region->rname[0]); GET_CURR_TIME_IN_DOLLARH_AND_ZDATE(dollarh_mval, dollarh_buffer, zdate_mval, zdate_buffer); util_out_print("Date/Time !AD [$H = !AD]", TRUE, zdate_mval.str.len, zdate_mval.str.addr, dollarh_mval.str.len, dollarh_mval.str.addr); util_out_print(" Access method !AD", FALSE, 2, (csd->acc_meth == dba_mm) ? "MM" : "BG"); util_out_print(" Global Buffers !12UL", TRUE, csd->n_bts); util_out_print(" Reserved Bytes !19UL", FALSE, csd->reserved_bytes); util_out_print(" Block size (in bytes) !12UL", TRUE, csd->blk_size); util_out_print(" Maximum record size !19UL", FALSE, csd->max_rec_size); util_out_print(" Starting VBN !12UL", TRUE, csd->start_vbn); util_out_print(" Maximum key size !19UL", FALSE, csd->max_key_size); util_out_print(" Total blocks 0x!XL", TRUE, csa->ti->total_blks); util_out_print(" Null subscripts !AD", FALSE, 12, (csd->null_subs == ALWAYS) ? " ALWAYS" : (csd->null_subs == ALLOWEXISTING) ? " EXISTING" : " NEVER" ); util_out_print(" Free blocks 0x!XL", TRUE, csa->ti->free_blocks); /* NOTE: Currently Std Null Collation is the only entry in one line, For 64bit TN project, when some other fields will be added, this can be adjusted then - MM Oct 04 */ util_out_print(" Standard Null Collation !AD", FALSE, 11, (csd->std_null_coll) ? " TRUE" : " FALSE"); util_out_print(" Free space 0x!XL", TRUE, csd->free_space); util_out_print(" Last Record Backup 0x!16@XQ", FALSE, &csd->last_rec_backup); util_out_print (" Extension Count !12UL", TRUE, csd->extension_size); util_out_print(" Last Database Backup 0x!16@XQ", FALSE, &csd->last_com_backup); if (csd->bplmap > 0) util_out_print(" Number of local maps !12UL", TRUE, (csa->ti->total_blks + csd->bplmap - 1) / csd->bplmap); else util_out_print(" Number of local maps ??", TRUE); util_out_print(" Last Bytestream Backup 0x!16@XQ", FALSE, &csd->last_inc_backup); util_out_print(" Lock space 0x!XL", TRUE, csd->lock_space_size/OS_PAGELET_SIZE); util_out_print(" In critical section 0x!XL", FALSE, cnl->in_crit); util_out_print(" Timers pending !12UL", TRUE, cnl->wcs_timers + 1); if (FROZEN_BY_ROOT == csd->freeze) util_out_print(" Cache freeze id FROZEN BY ROOT", FALSE); else util_out_print(" Cache freeze id 0x!XL", FALSE, (csd->freeze)? csd->freeze : 0); dse_puttime(csd->flush_time, " Flush timer !AD", TRUE); util_out_print(" Freeze match 0x!XL", FALSE, csd->image_count ? csd->image_count : 0); util_out_print(" Flush trigger !12UL", TRUE, csd->flush_trigger); util_out_print(" Current transaction 0x!16@XQ", FALSE, &csa->ti->curr_tn); util_out_print(" No. of writes/flush !12UL", TRUE, csd->n_wrt_per_flu); util_out_print(" Maximum TN 0x!16@XQ", FALSE, &csd->max_tn); if (GDSVLAST > csd->certified_for_upgrade_to) util_out_print(" Certified for Upgrade to !AD", TRUE, LEN_AND_STR(gtm_dbversion_table[csd->certified_for_upgrade_to])); else /* out of range so print hex */ util_out_print(" Certified for Upgrade to 0x!XL", TRUE, csd->certified_for_upgrade_to); util_out_print(" Maximum TN Warn 0x!16@XQ", FALSE, &csd->max_tn_warn); if (GDSVLAST > csd->desired_db_format) util_out_print(" Desired DB Format !AD", TRUE, LEN_AND_STR(gtm_dbversion_table[csd->desired_db_format])); else /* out of range so print hex */ util_out_print(" Desired DB Format 0x!XL", TRUE, csd->desired_db_format); util_out_print(" Master Bitmap Size !12UL", FALSE, csd->master_map_len / DISK_BLOCK_SIZE); util_out_print(" Blocks to Upgrade 0x!XL", TRUE, csd->blks_to_upgrd); if (csd->def_coll) { util_out_print(" Default Collation !19UL", FALSE, csd->def_coll); util_out_print(" Collation Version !12UL", TRUE, csd->def_coll_ver); } util_out_print(" Create in progress !AD", FALSE, 12, (csd->createinprogress) ? " TRUE" : " FALSE"); # ifdef CNTR_WORD_32 util_out_print(" Modified cache blocks !12UL", TRUE, cnl->wcs_active_lvl); # else util_out_print(" Modified cache blocks !12UW", TRUE, cnl->wcs_active_lvl); # endif util_out_print(" Reference count !19UL", FALSE, cnl->ref_cnt); util_out_print(" Wait Disk !12UL", TRUE, csd->wait_disk_space); util_out_print(" Journal State !AD", (jnl_notallowed == jnl_state), 13, (jnl_notallowed != jnl_state) ? ((jnl_state == jnl_closed) ? " OFF" : (jnl_buff_open ? " ON" : "[inactive] ON")) : " DISABLED"); if (jnl_notallowed != jnl_state) { util_out_print(" Journal Before imaging !AD", TRUE, 5, (csd->jnl_before_image) ? " TRUE" : "FALSE"); util_out_print(" Journal Allocation !19UL", FALSE, csd->jnl_alq); util_out_print(" Journal Extension !12UL", TRUE, csd->jnl_deq); util_out_print(" Journal Buffer Size !19UL", FALSE, csd->jnl_buffer_size); util_out_print(" Journal Alignsize !12UL", TRUE, csd->alignsize / DISK_BLOCK_SIZE); util_out_print(" Journal AutoSwitchLimit !17UL", FALSE, csd->autoswitchlimit); util_out_print(" Journal Epoch Interval!12UL", TRUE, EPOCH_SECOND2SECOND(csd->epoch_interval)); # ifdef UNIX util_out_print(" Journal Yield Limit !19UL", FALSE, csd->yield_lmt); util_out_print(" Journal Sync IO !AD", TRUE, 5, (csd->jnl_sync_io ? " TRUE" : "FALSE")); # elif VMS util_out_print(" Journal NOCACHE IO !AD", TRUE, 12, (csd->jnl_sync_io ? " TRUE" : " FALSE")); # endif util_out_print(" Journal File: !AD", TRUE, JNL_LEN_STR(csd)); } if (BACKUP_NOT_IN_PROGRESS != cnl->nbb) util_out_print(" Online Backup NBB !19UL", TRUE, cnl->nbb); /* Mutex Stuff */ util_out_print(" Mutex Hard Spin Count !19UL", FALSE, csd->mutex_spin_parms.mutex_hard_spin_count); util_out_print(" Mutex Sleep Spin Count!12UL", TRUE, csd->mutex_spin_parms.mutex_sleep_spin_count); util_out_print(" Mutex Queue Slots !19UL", FALSE, NUM_CRIT_ENTRY(csd)); util_out_print(" KILLs in progress !12UL", TRUE, (csd->kill_in_prog + csd->abandoned_kills)); util_out_print(" Replication State !AD", FALSE, 13, (csd->repl_state == repl_closed ? " OFF" : (csd->repl_state == repl_open ? " ON" : " [WAS_ON] OFF"))); util_out_print(" Region Seqno 0x!16@XQ", TRUE, &csd->reg_seqno); VMS_ONLY( util_out_print(" Resync Seqno 0x!16@XQ", FALSE, &csd->resync_seqno); util_out_print(" Resync trans 0x!16@XQ", TRUE, &csd->resync_tn); ) UNIX_ONLY( util_out_print(" Zqgblmod Seqno 0x!16@XQ", FALSE, &csd->zqgblmod_seqno); util_out_print(" Zqgblmod Trans 0x!16@XQ", TRUE, &csd->zqgblmod_tn); ) util_out_print(" Endian Format !6AZ", UNIX_ONLY(FALSE) VMS_ONLY(TRUE), ENDIANTHISJUSTIFY); UNIX_ONLY( util_out_print(" Commit Wait Spin Count!12UL", TRUE, csd->wcs_phase2_commit_wait_spincnt); ) util_out_print(" Database file encrypted !AD", UNIX_ONLY(FALSE) VMS_ONLY(TRUE), 5, csd->is_encrypted ? " TRUE" : "FALSE"); UNIX_ONLY( util_out_print(" Inst Freeze on Error !AD", TRUE, 5, csd->freeze_on_fail ? " TRUE" : "FALSE"); ) UNIX_ONLY( util_out_print(" Spanning Node Absent !AD", FALSE, 5, csd->span_node_absent ? " TRUE" : "FALSE"); ) UNIX_ONLY( util_out_print(" Maximum Key Size Assured !AD", TRUE, 5, csd->maxkeysz_assured ? " TRUE" : "FALSE"); ) } if (CLI_PRESENT == cli_present("ALL")) { /* Only dump if -/ALL as if part of above display */ util_out_print(0, TRUE); util_out_print(" ", FALSE); util_out_print(" DB Current Minor Version !4UL", TRUE, csd->minor_dbver); util_out_print(" Blks Last Record Backup 0x!XL", FALSE, csd->last_rec_bkup_last_blk); util_out_print(" Last GT.M Minor Version !4UL", TRUE, csd->last_mdb_ver); util_out_print(" Blks Last Stream Backup 0x!XL", FALSE, csd->last_inc_bkup_last_blk); util_out_print(" DB Creation Version !AD", TRUE, LEN_AND_STR(gtm_dbversion_table[csd->creation_db_ver])); util_out_print(" Blks Last Comprehensive Backup 0x!XL", FALSE, csd->last_com_bkup_last_blk); util_out_print(" DB Creation Minor Version !4UL", TRUE, csd->creation_mdb_ver); util_out_print(0, TRUE); util_out_print(" Total Global Buffers 0x!XL", FALSE, csd->n_bts); util_out_print(" Phase2 commit pid count 0x!XL", TRUE, cnl->wcs_phase2_commit_pidcnt); util_out_print(" Dirty Global Buffers 0x!XL", FALSE, cnl->wcs_active_lvl); util_out_print(" Write cache timer count 0x!XL", TRUE, cnl->wcs_timers); util_out_print(" Free Global Buffers 0x!XL", FALSE, cnl->wc_in_free); util_out_print(" wcs_wtstart pid count 0x!XL", TRUE, cnl->in_wtstart); util_out_print(" Write Cache is Blocked !AD", FALSE, 5, (cnl->wc_blocked ? " TRUE" : "FALSE")); util_out_print(" wcs_wtstart intent cnt 0x!XL", TRUE, cnl->intent_wtstart); # ifdef UNIX util_out_print(0, TRUE); util_out_print(" Quick database rundown is active !AD", TRUE, 5, (csd->mumps_can_bypass ? " TRUE" : "FALSE")); util_out_print(" Access control rundown bypasses !9UL", FALSE, cnl->dbrndwn_access_skip); util_out_print(" FTOK rundown bypasses !10UL", TRUE, cnl->dbrndwn_ftok_skip); # endif new_line = FALSE; for (index = 0; MAX_WTSTART_PID_SLOTS > index; index++) { pid = cnl->wtstart_pid[index]; if (0 != pid) { util_out_print(" wcs_wtstart pid [!2UL] !AD !12UL", new_line, index, new_line ? 0 : 7, new_line ? "" : " ", pid); new_line = !new_line; } } /* Additional information regarding kills that are in progress, abandoned and inhibited */ util_out_print(0, TRUE); util_out_print(" Actual kills in progress !12UL", FALSE, csd->kill_in_prog); util_out_print(" Abandoned Kills !12UL", TRUE, csd->abandoned_kills); util_out_print(" Process(es) inhibiting KILLs !5UL", TRUE, cnl->inhibit_kills); util_out_print(0, TRUE); util_out_print(" DB Trigger cycle of ^#t !12UL", TRUE, csd->db_trigger_cycle); util_out_print(0, TRUE); util_out_print(" MM defer_time !5SL", TRUE, csd->defer_time); /* Print the database encryption hash information */ GET_HASH_IN_HEX(csd->encryption_hash, outbuf, GTMCRYPT_HASH_HEX_LEN); util_out_print(" Database file encryption hash !AD", TRUE, GTMCRYPT_HASH_HEX_LEN, outbuf); } # ifdef UNIX if (NEED_TO_DUMP("SUPPLEMENTARY")) { util_out_print(0, TRUE); assert(MAX_SUPPL_STRMS == ARRAYSIZE(csd->strm_reg_seqno)); for (index = 0; index < MAX_SUPPL_STRMS; index++) { if (csd->strm_reg_seqno[index]) util_out_print(" Stream !2UL: Reg Seqno 0x!16@XQ", TRUE, index, &csd->strm_reg_seqno[index]); } } # endif if (NEED_TO_DUMP("ENVIRONMENT")) { util_out_print(0, TRUE); util_out_print(" Full Block Writes !AD", FALSE, 6, (csa->do_fullblockwrites) ? " ON" : " OFF"); util_out_print(" Full Block Write Len !12UL", TRUE, csa->fullblockwrite_len); } if (NEED_TO_DUMP("DB_CSH")) { util_out_print(0, TRUE); # define TAB_DB_CSH_ACCT_REC(COUNTER,TEXT1,TEXT2) SHOW_DB_CSH_STAT(csd, COUNTER, TEXT1, TEXT2) # include "tab_db_csh_acct_rec.h" # undef TAB_DB_CSH_ACCT_REC } if (NEED_TO_DUMP("GVSTATS")) { util_out_print(0, TRUE); # define TAB_GVSTATS_REC(COUNTER,TEXT1,TEXT2) SHOW_GVSTATS_STAT(cnl, COUNTER, TEXT1, TEXT2) # include "tab_gvstats_rec.h" # undef TAB_GVSTATS_REC } if (NEED_TO_DUMP("TPBLKMOD")) { util_out_print(0, TRUE); assert(n_tp_blkmod_types < ARRAYSIZE(csd->tp_cdb_sc_blkmod)); util_out_print(" TP blkmod nomod !12UL", TRUE, csd->tp_cdb_sc_blkmod[tp_blkmod_nomod]); util_out_print(" TP blkmod gvcst_srch !12UL", TRUE, csd->tp_cdb_sc_blkmod[tp_blkmod_gvcst_srch]); util_out_print(" TP blkmod t_qread !12UL", TRUE, csd->tp_cdb_sc_blkmod[tp_blkmod_t_qread]); util_out_print(" TP blkmod tp_tend !12UL", TRUE, csd->tp_cdb_sc_blkmod[tp_blkmod_tp_tend]); util_out_print(" TP blkmod tp_hist !12UL", TRUE, csd->tp_cdb_sc_blkmod[tp_blkmod_tp_hist]); } if (NEED_TO_DUMP("BG_TRC")) { util_out_print(0, TRUE); /* print out all the BG_TRACE accounting fields */ # define TAB_BG_TRC_REC(A,B) SHOW_STAT(A,B); # include "tab_bg_trc_rec.h" # undef TAB_BG_TRC_REC } jpc = csa->jnl; if (NEED_TO_DUMP("JOURNAL") && (JNL_ENABLED(csd) && (NULL != jpc) && (NULL != jpc->jnl_buff))) { jb = jpc->jnl_buff; util_out_print(0, TRUE); /* --------------------------- journal buffer --------------------------------- */ util_out_print(" Jnl Buffer Size 0x!XL", FALSE, jb->size); util_out_print(" ", FALSE); util_out_print(" Dskaddr 0x!XL", TRUE, jb->dskaddr); util_out_print(" Free 0x!XL", FALSE, jb->free); util_out_print(" ", FALSE); util_out_print(" Freeaddr 0x!XL", TRUE, jb->freeaddr); util_out_print(" Dsk 0x!XL", FALSE, jb->dsk); util_out_print(" ", FALSE); util_out_print(" Wrtsize 0x!XL", TRUE, jb->wrtsize); util_out_print(" Journal checksum seed 0x!XL", FALSE, csd->jnl_checksum); util_out_print(" ", FALSE); util_out_print(" Min_write_size 0x!XL", TRUE, jb->min_write_size); util_out_print(" bytcnt 0x!XL", FALSE, jb->bytcnt); util_out_print(" ", FALSE); util_out_print(" Max_write_size 0x!XL", TRUE, jb->max_write_size); util_out_print(" Before image !AD", FALSE, 5, (jb->before_images ? " TRUE" : "FALSE")); util_out_print(" ", FALSE); util_out_print(" Filesize !12UL", TRUE, jb->filesize); util_out_print(" Iosb.cond !12UW", FALSE, jb->iosb.cond); util_out_print(" ", FALSE); util_out_print(" qiocnt !12UL", TRUE, jb->qiocnt); util_out_print(" Iosb.length 0x!4XW", FALSE, jb->iosb.length); util_out_print(" ", FALSE); util_out_print(" errcnt !12UL", TRUE, jb->errcnt); util_out_print(" Iosb.dev_specific !12UL", FALSE, jb->iosb.dev_specific); util_out_print(" ", FALSE); time_len = exttime(jb->next_epoch_time, (char *)buffer, 0); assert(STR_LIT_LEN(NEXT_EPOCH_TIME_SPACES) >= time_len); util_out_print(" Next Epoch_Time!AD!AD", TRUE, STR_LIT_LEN(NEXT_EPOCH_TIME_SPACES) - time_len + 1, NEXT_EPOCH_TIME_SPACES, time_len - 1, buffer); /* -1 to avoid printing \ at end of $H * format time returned by exttime */ util_out_print(" Blocked Process !12UL", FALSE, jb->blocked); util_out_print(" ", FALSE); util_out_print(" Epoch_tn 0x!16@XQ", TRUE, &jb->epoch_tn); util_out_print(" Io_in_progress !AD", FALSE, 5, (jb->UNIX_ONLY(io_in_prog_latch.u.parts.latch_pid)VMS_ONLY(io_in_prog) ? " TRUE" : "FALSE")); util_out_print(" ", FALSE); util_out_print(" Epoch_Interval !12UL", TRUE, EPOCH_SECOND2SECOND(jb->epoch_interval)); util_out_print(" Now_writer !12UL", FALSE, (jb->UNIX_ONLY(io_in_prog_latch.u.parts.latch_pid)VMS_ONLY(now_writer))); util_out_print(" ", FALSE); util_out_print(" Image_count !12UL", TRUE, jb->image_count); util_out_print(" fsync_in_prog !AD", FALSE, 5, (jb->fsync_in_prog_latch.u.parts.latch_pid ? " TRUE" : "FALSE")); util_out_print(" ", FALSE); util_out_print(" fsync pid !12SL", TRUE, (jb->fsync_in_prog_latch.u.parts.latch_pid)); util_out_print(" fsync addrs 0x!XL", FALSE, jb->fsync_dskaddr); util_out_print(" ", FALSE); util_out_print(" Need_db_fsync !AD", TRUE, 5, (jb->need_db_fsync ? " TRUE" : "FALSE")); util_out_print(" Filesystem block size 0x!XL", FALSE, jb->fs_block_size); util_out_print(" ", FALSE); util_out_print(" jnl solid tn 0x!16@XQ", TRUE, &csd->jnl_eovtn); for (rectype = JRT_BAD + 1; rectype < JRT_RECTYPES - 1; rectype++) { util_out_print(" Jnl Rec Type !5AZ 0x!XL ", FALSE, jrt_label[rectype], jb->reccnt[rectype]); rectype++; util_out_print(" Jnl Rec Type !5AZ 0x!XL", TRUE, jrt_label[rectype], jb->reccnt[rectype]); } if (rectype != JRT_RECTYPES) util_out_print(" Jnl Rec Type !5AZ 0x!XL", TRUE, jrt_label[rectype], jb->reccnt[rectype]); util_out_print(0, TRUE); util_out_print(" Recover interrupted !AD", FALSE, 5, (csd->recov_interrupted ? " TRUE" : "FALSE")); util_out_print(" ", FALSE); util_out_print(" INTRPT resolve time !12UL", TRUE, csd->intrpt_recov_tp_resolve_time); util_out_print(" INTRPT jnl_state !12UL", FALSE, csd->intrpt_recov_jnl_state); util_out_print(" ", FALSE); util_out_print(" INTRPT repl_state !12UL", TRUE, csd->intrpt_recov_repl_state); util_out_print(" INTRPT seqno 0x!16@XQ", TRUE, &csd->intrpt_recov_resync_seqno); UNIX_ONLY( for (index = 0; index < MAX_SUPPL_STRMS; index++) { if (csd->intrpt_recov_resync_strm_seqno[index]) util_out_print(" INTRPT strm_seqno : Stream # !2UL Stream Seqno 0x!16@XQ", TRUE, index, &csd->intrpt_recov_resync_strm_seqno[index]); } for (index = 0; index < MAX_SUPPL_STRMS; index++) { if (csd->intrpt_recov_resync_strm_seqno[index]) util_out_print(" SAVE strm_seqno : Stream # !2UL Region Seqno 0x!16@XQ", TRUE, index, &csd->save_strm_reg_seqno[index]); } ) } if (NEED_TO_DUMP("BACKUP")) { bptr = csa->shmpool_buffer; /* --------------------------- online backup buffer ---------------------------------- */ util_out_print(0, TRUE); util_out_print(" Free blocks !12UL", FALSE, bptr->free_cnt); util_out_print(" ", FALSE); util_out_print(" Backup blocks !12UL", TRUE, bptr->backup_cnt); util_out_print(" Reformat blocks !12UL", FALSE, bptr->reformat_cnt); util_out_print(" ", FALSE); util_out_print(" Total blocks !12UL", TRUE, bptr->total_blks); util_out_print(" Shmpool blocked !AD", FALSE, 5, (bptr->shmpool_blocked ? " TRUE" : "FALSE")); util_out_print(" ", FALSE); util_out_print(" File Offset 0x!16@XQ", TRUE, &bptr->dskaddr); util_out_print(" Shmpool crit holder !12UL", FALSE, bptr->shmpool_crit_latch.u.parts.latch_pid); util_out_print(" ", FALSE); util_out_print(" Backup_errno !12UL", TRUE, bptr->backup_errno); # ifdef VMS util_out_print(" Shmpool crit imgcnt !12UL", TRUE, bptr->shmpool_crit_latch.u.parts.latch_image_count); # endif util_out_print(" Backup Process ID !12UL", FALSE, bptr->backup_pid); util_out_print(" ", FALSE); util_out_print(" Backup TN 0x!16@XQ", TRUE, &bptr->backup_tn); util_out_print(" Inc Backup TN 0x!16@XQ", FALSE, &bptr->inc_backup_tn); util_out_print(" ", FALSE); util_out_print(" Process Failed !12UL", TRUE, bptr->failed); util_out_print(" Allocs since check !12UL", FALSE, bptr->allocs_since_chk); util_out_print(" ", FALSE); util_out_print(" Backup Image Count !12UL", TRUE, bptr->backup_image_count); util_out_print(" Temp File: !AD", TRUE, LEN_AND_STR(&bptr->tempfilename[0])); } if (NEED_TO_DUMP("MIXEDMODE")) { util_out_print(0, TRUE); util_out_print(" Database is Fully Upgraded : !AD", TRUE, 5, (csd->fully_upgraded ? " TRUE" : "FALSE")); util_out_print(" Database WAS ONCE Fully Upgraded from V4 : !AD", TRUE, 5, (csd->db_got_to_v5_once ? " TRUE" : "FALSE")); util_out_print(" Blocks to Upgrade subzero(negative) error : 0x!XL", TRUE, csd->blks_to_upgrd_subzero_error); util_out_print(" TN when Blocks to Upgrade last became 0 : 0x!16@XQ", TRUE, &csd->tn_upgrd_blks_0); util_out_print(" TN when Desired DB Format last changed : 0x!16@XQ", TRUE, &csd->desired_db_format_tn); util_out_print(" TN when REORG upgrd/dwngrd changed dbfmt : 0x!16@XQ", TRUE, &csd->reorg_db_fmt_start_tn); util_out_print(0, TRUE); util_out_print(" Block Number REORG upgrd/dwngrd will restart from : 0x!XL", TRUE, csd->reorg_upgrd_dwngrd_restart_block); } if (NEED_TO_DUMP("UPDPROC")) { util_out_print(0, TRUE); util_out_print(" Upd reserved area [% global buffers] !3UL", FALSE, csd->reserved_for_upd); util_out_print(" Avg blks read per 100 records !4UL", TRUE, csd->avg_blks_per_100gbl); util_out_print(" Pre read trigger factor [% upd rsrvd] !3UL", FALSE, csd->pre_read_trigger_factor); util_out_print(" Upd writer trigger [%flshTrgr] !3UL", TRUE, csd->writer_trigger_factor); } # ifdef GTM_SNAPSHOT if (NEED_TO_DUMP("SNAPSHOT")) { util_out_print(0, TRUE); util_out_print(" Snapshot in progress !AD", FALSE, 5, (cnl->snapshot_in_prog ? " TRUE" : "FALSE")); util_out_print(" Number of active snapshots !12UL", TRUE, cnl->num_snapshots_in_effect); util_out_print(" Snapshot cycle !12UL", FALSE, cnl->ss_shmcycle); /* SS_MULTI: Note that if we have multiple snapshots, then we have to run through each active * snapshot region and dump their informations respectively */ ss_shm_ptr = (shm_snapshot_ptr_t)(SS_GETSTARTPTR(csa)); util_out_print(" Active snapshot PID !12UL", TRUE, ss_shm_ptr->ss_info.ss_pid); util_out_print(" Snapshot TN !12UL", FALSE, ss_shm_ptr->ss_info.snapshot_tn); util_out_print(" Total blocks !12UL", TRUE, ss_shm_ptr->ss_info.total_blks); util_out_print(" Free blocks !12UL", FALSE, ss_shm_ptr->ss_info.free_blks); util_out_print(" Process failed !12UL", TRUE, ss_shm_ptr->failed_pid); util_out_print(" Failure errno !12UL", FALSE, ss_shm_ptr->failure_errno); util_out_print(" Snapshot shared memory identifier !12SL", TRUE, ss_shm_ptr->ss_info.ss_shmid); util_out_print(" Snapshot file name !AD", TRUE, LEN_AND_STR(ss_shm_ptr->ss_info.shadow_file)); } # endif return; } fis-gtm-V6.0-003/sr_port/dse_eval.c0000644000032200000250000000235512201176155015765 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2008 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "cli.h" #include "util.h" #include "dse.h" #define MAX_UTIL_LEN 56 void dse_eval(void) { int4 util_len; gtm_uint64_t num; char util_buff[MAX_UTIL_LEN]; if (cli_present("NUMBER") != CLI_PRESENT) return; if (cli_present("DECIMAL") == CLI_PRESENT) { if (!cli_get_uint64("NUMBER", (gtm_uint64_t *)&num)) return; } else if (!cli_get_hex64("NUMBER", &num)) return; memcpy(util_buff, "Hex: ", 6); util_len = 6; util_len += i2hexl_nofill(num, (uchar_ptr_t)&util_buff[util_len], 16); memcpy(&util_buff[util_len]," Dec: !@UQ", 13); util_len += 13; util_buff[util_len] = 0; util_out_print(util_buff, TRUE, &num); return; } fis-gtm-V6.0-003/sr_port/dse_exhaus.c0000644000032200000250000001271712201176155016336 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "dsefind.h" #include "copy.h" #include "util.h" #include "dse.h" /* Include prototypes */ #include "t_qread.h" #define MAX_UTIL_LEN 32 GBLDEF short int patch_path_count; GBLREF block_id patch_find_blk, patch_left_sib, patch_path[MAX_BT_DEPTH + 1], patch_right_sib; GBLREF bool patch_exh_found; GBLREF bool patch_find_sibs; GBLREF bool patch_find_root_search; GBLREF global_root_list *global_roots_head; GBLREF int4 patch_offset[MAX_BT_DEPTH + 1]; GBLREF sgmnt_addrs *cs_addrs; GBLREF VSIG_ATOMIC_T util_interrupt; error_def(ERR_DSEBLKRDFAIL); error_def(ERR_CTRLC); void dse_exhaus(int4 pp, int4 op) { block_id last; cache_rec_ptr_t dummy_cr; char util_buff[MAX_UTIL_LEN]; int count, util_len; int4 dummy_int; global_dir_path *d_ptr, *temp; short temp_short; sm_uc_ptr_t bp, b_top, np, nrp, nr_top, ptr, rp, r_top; last = 0; patch_path_count++; if(!(bp = t_qread(patch_path[pp - 1], &dummy_int, &dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); if (((blk_hdr_ptr_t) bp)->bsiz > cs_addrs->hdr->blk_size) b_top = bp + cs_addrs->hdr->blk_size; else if (SIZEOF(blk_hdr) > ((blk_hdr_ptr_t) bp)->bsiz) b_top = bp + SIZEOF(blk_hdr); else b_top = bp + ((blk_hdr_ptr_t)bp)->bsiz; for (rp = bp + SIZEOF(blk_hdr); rp < b_top; rp = r_top) { if (util_interrupt) { rts_error(VARLSTCNT(1) ERR_CTRLC); break; } if (!(np = t_qread(patch_path[pp - 1], &dummy_int, &dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); if (np != bp) { b_top = np + (b_top - bp); rp = np + (rp - bp); r_top = np + (r_top - bp); bp = np; } GET_SHORT(temp_short, &((rec_hdr_ptr_t)rp)->rsiz); r_top = rp + temp_short; if (r_top > b_top) r_top = b_top; if (SIZEOF(block_id) > (r_top - rp)) break; if (((blk_hdr_ptr_t)bp)->levl) GET_LONG(patch_path[pp], (r_top - SIZEOF(block_id))); else { for (ptr = rp + SIZEOF(rec_hdr); (*ptr++ || *ptr++) && (ptr <= r_top);) ; GET_LONG(patch_path[pp], ptr); } patch_offset[op] = (int4)(rp - bp); if (patch_path[pp] == patch_find_blk) { if (!patch_exh_found) { if (patch_find_sibs) util_out_print("!/!_Left sibling!_Current block!_Right sibling", TRUE); patch_exh_found = TRUE; } if (patch_find_sibs) { patch_left_sib = last; if (r_top < b_top) { nrp = r_top; GET_SHORT(temp_short, &((rec_hdr_ptr_t)rp)->rsiz); nr_top = nrp + temp_short; if (nr_top > b_top) nr_top = b_top; if (SIZEOF(block_id) <= (nr_top - nrp)) { if (((blk_hdr_ptr_t)bp)->levl) GET_LONG(patch_right_sib, (nr_top - SIZEOF(block_id))); else { for (ptr = rp + SIZEOF(rec_hdr); (*ptr++ || *ptr++) && (ptr <= nr_top);) ; GET_LONG(patch_right_sib, ptr); } } } else patch_right_sib = 0; if (patch_left_sib) util_out_print("!_0x!XL", FALSE, patch_left_sib); else util_out_print("!_none!_", FALSE); util_out_print("!_0x!XL!_", FALSE, patch_find_blk); if (patch_right_sib) util_out_print("0x!XL!/", TRUE, patch_right_sib); else util_out_print("none!/", TRUE); } else /* !patch_find_sibs */ { patch_path_count--; util_out_print(" Directory path!/ Path--blk:off", TRUE); if (!patch_find_root_search) { d_ptr = global_roots_head->link->dir_path; while (d_ptr) { memcpy(util_buff, " ", 1); util_len = 1; util_len += i2hex_nofill(d_ptr->block, (uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len], ":", 1); util_len += 1; util_len += i2hex_nofill(d_ptr->offset, (uchar_ptr_t)&util_buff[util_len], 4); util_buff[util_len] = 0; util_out_print(util_buff, FALSE); temp = d_ptr; d_ptr = d_ptr->next; free(temp); } global_roots_head->link->dir_path = 0; util_out_print("!/!/ Global paths!/ Path--blk:off", TRUE); } for (count = 0; count < patch_path_count; count++) { memcpy(util_buff, " ", 1); util_len = 1; util_len += i2hex_nofill(patch_path[count], (uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len], ":", 1); util_len += 1; util_len += i2hex_nofill(patch_offset[count], (uchar_ptr_t)&util_buff[util_len], 4); util_buff[util_len] = 0; util_out_print(util_buff,FALSE); } memcpy(util_buff, " ", 1); util_len = 1; util_len += i2hex_nofill(patch_path[count], (uchar_ptr_t)&util_buff[util_len], 8); util_buff[util_len] = 0; util_out_print(util_buff, TRUE); patch_path_count++; } } if ((0 < patch_path[pp]) && (patch_path[pp] < cs_addrs->ti->total_blks) && (patch_path[pp] % cs_addrs->hdr->bplmap)) { if (1 < ((blk_hdr_ptr_t)bp)->levl) dse_exhaus(pp + 1, op + 1); else if ((1 == ((blk_hdr_ptr_t)bp)->levl) && patch_find_root_search) dse_find_roots(patch_path[pp]); } last = patch_path[pp]; } patch_path_count--; return; } fis-gtm-V6.0-003/sr_port/dse_exit.c0000644000032200000250000000211112201176155015775 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdlib.h" /* for exit() */ #ifdef DEBUG #include "gdsroot.h" #include "gdsbt.h" #include "gtm_facility.h" #include "gdsfhead.h" #endif #include "error.h" #include "iosp.h" #include "util.h" #include "dse_exit.h" GBLREF unsigned int t_tries; #ifdef DEBUG GBLREF sgmnt_addrs *cs_addrs; #endif void dse_exit(void) { /* reset t_tries (from CDB_STAGNATE to 0) as we are exiting and no longer going to be running transactions * and an assert in wcs_recover relies on this */ t_tries = 0; assert((NULL == cs_addrs) || !cs_addrs->now_crit || cs_addrs->hold_onto_crit); util_out_close(); EXIT(SS_NORMAL); } fis-gtm-V6.0-003/sr_port/dse_exit.h0000644000032200000250000000101212201176155016001 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __DSE_EXIT_H__ #define __DSE_EXIT_H__ void dse_exit(void); #endif fis-gtm-V6.0-003/sr_port/dse_f_blk.c0000644000032200000250000004012512201176155016110 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include #include "error.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "dsefind.h" #include "cli.h" #include "copy.h" #include "util.h" #include "dse.h" /* Include prototypes*/ #include "t_qread.h" GBLDEF bool patch_exh_found, patch_find_root_search, patch_find_sibs; GBLDEF block_id patch_find_blk, patch_left_sib, patch_right_sib; GBLDEF block_id patch_path[MAX_BT_DEPTH + 1], patch_path1[MAX_BT_DEPTH + 1]; GBLDEF global_root_list *global_roots_head, *global_roots_tail; GBLDEF int4 patch_offset[MAX_BT_DEPTH + 1], patch_offset1[MAX_BT_DEPTH + 1]; GBLDEF short int patch_dir_path_count; GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF block_id patch_curr_blk; GBLREF short int patch_path_count; #define MAX_UTIL_LEN 33 static boolean_t was_crit, was_hold_onto_crit, nocrit_present; error_def(ERR_DSEBLKRDFAIL); error_def(ERR_CTRLC); void dse_f_blk(void) { block_id blk, last, look; boolean_t exhaust; cache_rec_ptr_t dummy_cr; char targ_key[MAX_KEY_SZ + 1], util_buff[MAX_UTIL_LEN]; global_root_list *temp; global_dir_path *d_ptr, *dtemp; int util_len; int4 dummy_int; sm_uc_ptr_t blk_id, bp, b_top, key_top, rp, r_top, sp, srp, s_top; short int count, rsize, size; char lvl; if (CLI_PRESENT == cli_present("BLOCK")) { if (!cli_get_hex("BLOCK", (uint4 *)&blk)) return; if ((0 > blk) || (blk >= cs_addrs->ti->total_blks) || !(blk % cs_addrs->hdr->bplmap)) { util_out_print("Error: invalid block number.", TRUE); return; } patch_curr_blk = blk; } patch_find_sibs = (CLI_PRESENT == cli_present("SIBLINGS")); patch_find_blk = patch_curr_blk; was_crit = cs_addrs->now_crit; nocrit_present = (CLI_NEGATED == cli_present("CRIT")); DSE_GRAB_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); /* ESTABLISH is done here because dse_f_blk_ch() assumes we already have crit. */ ESTABLISH(dse_f_blk_ch); if (!(bp = t_qread(patch_find_blk, &dummy_int, &dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); if (((blk_hdr_ptr_t) bp)->bsiz > cs_addrs->hdr->blk_size) b_top = bp + cs_addrs->hdr->blk_size; else if (SIZEOF(blk_hdr) > ((blk_hdr_ptr_t) bp)->bsiz) b_top = bp + SIZEOF(blk_hdr); else b_top = bp + ((blk_hdr_ptr_t)bp)->bsiz; rp = bp + SIZEOF(blk_hdr); GET_SHORT(rsize, &((rec_hdr_ptr_t) rp)->rsiz); if (SIZEOF(rec_hdr) > rsize) r_top = rp + SIZEOF(rec_hdr); else r_top = rp + rsize; if (r_top > b_top) r_top = b_top; for (key_top = rp + SIZEOF(rec_hdr); (key_top < r_top) && *key_top++; ) ; if (((blk_hdr_ptr_t)bp)->levl && key_top > (blk_id = r_top - SIZEOF(block_id))) /* NOTE assignment */ key_top = blk_id; patch_path_count = 1; patch_path[0] = get_dir_root(); patch_left_sib = patch_right_sib = 0; size = key_top - rp - SIZEOF(rec_hdr); if (SIZEOF(targ_key) < size) size = SIZEOF(targ_key); patch_find_root_search = TRUE; if ((exhaust = (cli_present("EXHAUSTIVE") == CLI_PRESENT)) || (0 >= size)) /* NOTE assignment */ { if (size < 0) { util_out_print("No keys in block, cannot perform ordered search.", TRUE); DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); REVERT; return; } if (patch_exh_found = (patch_find_blk == patch_path[0])) /* NOTE assignment */ { if (patch_find_sibs) { util_out_print("!/!_Left sibling!_Current block!_Right sibling", TRUE); util_out_print("!_none!_!_0x!XL!_none",TRUE, patch_find_blk); } else { assert(1 == patch_path[0]); /* OK to assert because pro prints */ util_out_print("!/ Directory path!/ Path--blk:off!/!_1", TRUE); } } else { global_roots_head = (global_root_list *)malloc(SIZEOF(global_root_list)); global_roots_tail = global_roots_head; global_roots_head->link = NULL; global_roots_head->dir_path = NULL; dse_exhaus(1, 0); patch_find_root_search = FALSE; while (!patch_exh_found && global_roots_head->link) { patch_path[0] = global_roots_head->link->root; patch_path_count = 1; patch_left_sib = patch_right_sib = 0; if (patch_exh_found = (patch_find_blk == patch_path[0])) /* NOTE assignment */ { if (patch_find_sibs) { util_out_print("!/!_Left sibling!_Current block!_Right sibling", TRUE); util_out_print("!_none!_!_0x!XL!_none",TRUE, patch_find_blk); } else { patch_path_count--; util_out_print("!/ Directory path!/ Path--blk:off", TRUE); if (!patch_find_root_search) { d_ptr = global_roots_head->link->dir_path; while (d_ptr) { memcpy(util_buff, " ", 1); util_len = 1; util_len += i2hex_nofill(d_ptr->block, (uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len], ":", 1); util_len += 1; util_len += i2hex_nofill(d_ptr->offset, (uchar_ptr_t)&util_buff[util_len], 4); memcpy(&util_buff[util_len], ",", 1); util_len += 1; util_buff[util_len] = 0; util_out_print(util_buff, FALSE); temp = (global_root_list *)d_ptr; d_ptr = d_ptr->next; free(temp); } global_roots_head->link->dir_path = 0; util_out_print("!/ Global tree path!/ Path--blk:off", TRUE); } for (count = 0; count < patch_path_count; count++) { memcpy(util_buff, " ", 1); util_len = 1; util_len += i2hex_nofill(patch_path[count], (uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len], ":", 1); util_len += 1; util_len += i2hex_nofill(patch_offset[count], (uchar_ptr_t)&util_buff[util_len], 4); memcpy(&util_buff[util_len], ",", 1); util_len += 1; util_buff[util_len] = 0; util_out_print(util_buff, FALSE); } memcpy(util_buff, " ", 1); util_len = 1; util_len += i2hex_nofill(patch_path[count], (uchar_ptr_t)&util_buff[util_len], 8); util_buff[util_len] = 0; util_out_print(util_buff, TRUE); } } else dse_exhaus(1, 0); temp = global_roots_head; d_ptr = global_roots_head->link->dir_path; while (d_ptr) { dtemp = d_ptr; d_ptr = d_ptr->next; free(dtemp); } global_roots_head = global_roots_head->link; free(temp); } while (global_roots_head->link) { temp = global_roots_head; d_ptr = global_roots_head->link->dir_path; while (d_ptr) { dtemp = d_ptr; d_ptr = d_ptr->next; free(dtemp); } global_roots_head = global_roots_head->link; free(temp); } } if (!patch_exh_found) { if (exhaust) util_out_print("Error: exhaustive search fail.", TRUE); else util_out_print("Error: ordered search fail.", TRUE); } else util_out_print(0, TRUE); DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); REVERT; return; } else /* !exhaust && size > 0 */ { if (!dse_is_blk_in(rp, r_top, size)) { util_out_print("Error: ordered search fail.", TRUE); DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); REVERT; return; } } if (patch_find_sibs) { /* the cross-branch sib action could logically go in dse_order but is here 'cause it only gets used when needed */ util_out_print("!/!_Left sibling!_Current block!_Right sibling", TRUE); if (!patch_left_sib) { for (last = 0, lvl = (patch_find_root_search ? patch_dir_path_count : patch_path_count) - 1; 0 <= --lvl;) { if (!(sp = t_qread(patch_find_root_search ? patch_path[lvl] : patch_path1[lvl], &dummy_int, &dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); if (((blk_hdr_ptr_t)sp)->bsiz > cs_addrs->hdr->blk_size) s_top = sp + cs_addrs->hdr->blk_size; else if (SIZEOF(blk_hdr) > ((blk_hdr_ptr_t)sp)->bsiz) { util_out_print("Error: sibling search hit problem blk 0x!XL", TRUE, patch_find_root_search ? patch_path[lvl] : patch_path1[lvl]); lvl = -1; break; } else s_top = sp + ((blk_hdr_ptr_t)sp)->bsiz; srp = sp + SIZEOF(blk_hdr); GET_SHORT(rsize, &((rec_hdr_ptr_t)srp)->rsiz); srp += rsize; GET_LONG(look, srp - SIZEOF(block_id)); if ((patch_find_root_search ? patch_path[lvl + 1] : patch_path1[lvl + 1]) != look) break; } if (0 <= lvl) { for (lvl++; (srp < s_top) && ((patch_find_root_search ? patch_path[lvl] : patch_path1[lvl]) != look);) { last = look; GET_SHORT(rsize, &((rec_hdr_ptr_t)srp)->rsiz); srp += rsize; if (srp > s_top) break; GET_LONG(look, srp - SIZEOF(block_id)); } if ((patch_find_root_search ? patch_path[lvl] : patch_path1[lvl]) != look) { util_out_print("Error: sibling search hit problem blk 0x!XL", TRUE, patch_find_root_search ? patch_path[lvl] : patch_path1[lvl]); last = 0; lvl = (patch_find_root_search ? patch_dir_path_count : patch_path_count); } else if (last >= cs_addrs->ti->total_blks) { /* should never come here as block was previously OK, but this is dse so be careful */ util_out_print("Error: sibling search got 0x!XL which exceeds total blocks 0x!XL", TRUE, last, cs_addrs->ti->total_blks); last = 0; lvl = (patch_find_root_search ? patch_dir_path_count : patch_path_count); } for (lvl++; lvl < (patch_find_root_search ? patch_dir_path_count : patch_path_count); lvl++) { if (!(sp = t_qread(last, &dummy_int, &dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); if (((blk_hdr_ptr_t)sp)->bsiz > cs_addrs->hdr->blk_size) s_top = sp + cs_addrs->hdr->blk_size; else if (SIZEOF(blk_hdr) > ((blk_hdr_ptr_t)sp)->bsiz) { util_out_print("Error: sibling search hit problem blk 0x!XL", TRUE, last); last = 0; break; } else s_top = sp + ((blk_hdr_ptr_t)sp)->bsiz; if (0 >= (signed char)(((blk_hdr_ptr_t)sp)->levl)) { util_out_print("Error: sibling search reached level 0", TRUE); last = 0; break; } GET_LONG(last, s_top - SIZEOF(block_id)); if (last >= cs_addrs->ti->total_blks) { util_out_print("Error: sibling search got 0x!XL which exceeds total blocks 0x!XL", TRUE, last, cs_addrs->ti->total_blks); break; } } } patch_left_sib = last; } if (patch_left_sib) util_out_print("!_0x!XL", FALSE, patch_left_sib); else util_out_print("!_none!_", FALSE); util_out_print("!_0x!XL!_", FALSE, patch_find_blk); if (!patch_right_sib) { for (lvl = (patch_find_root_search ? patch_dir_path_count : patch_path_count) - 1; 0 <= --lvl;) { if (!(sp = t_qread(patch_find_root_search ? patch_path[lvl] : patch_path1[lvl], &dummy_int, &dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); if (((blk_hdr_ptr_t)sp)->bsiz > cs_addrs->hdr->blk_size) s_top = sp + cs_addrs->hdr->blk_size; else if (SIZEOF(blk_hdr) > ((blk_hdr_ptr_t)sp)->bsiz) { util_out_print("Error: sibling search hit problem blk 0x!XL", TRUE, patch_find_root_search ? patch_path[lvl] : patch_path1[lvl]); lvl = -1; break; } else s_top = sp + ((blk_hdr_ptr_t)sp)->bsiz; GET_LONG(look, s_top - SIZEOF(block_id)); if (look >= cs_addrs->ti->total_blks) { util_out_print("Error: sibling search got 0x!XL which exceeds total blocks 0x!XL", TRUE, look, cs_addrs->ti->total_blks); lvl = -1; break; } if ((patch_find_root_search ? patch_path[lvl + 1] : patch_path1[lvl + 1]) != look) break; } if (0 <= lvl) { srp = sp + SIZEOF(blk_hdr); for (lvl++; (srp < s_top) && ((patch_find_root_search ? patch_path[lvl] : patch_path1[lvl]) != last);) { last = look; GET_SHORT(rsize, &((rec_hdr_ptr_t)srp)->rsiz); srp += rsize; if (srp > s_top) break; GET_LONG(look, srp - SIZEOF(block_id)); if (look >= cs_addrs->ti->total_blks) { util_out_print("Error: sibling search got 0x!XL which exceeds total blocks 0x!XL", TRUE, look, cs_addrs->ti->total_blks); break; } } if ((patch_find_root_search ? patch_path[lvl] : patch_path1[lvl]) != last) { util_out_print("Error: sibling search hit problem blk 0x!XL", TRUE, patch_find_root_search ? patch_path[lvl] : patch_path1[lvl]); look = 0; lvl = (patch_find_root_search ? patch_dir_path_count : patch_path_count); } for (lvl++; lvl < (patch_find_root_search ? patch_dir_path_count : patch_path_count); lvl++) { if (!(sp = t_qread(look, &dummy_int, &dummy_cr))) /* NOTE assignment */ rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); if (((blk_hdr_ptr_t)sp)->bsiz > cs_addrs->hdr->blk_size) s_top = sp + cs_addrs->hdr->blk_size; else if (SIZEOF(blk_hdr) > ((blk_hdr_ptr_t)sp)->bsiz) { util_out_print("Error: sibling search hit problem blk 0x!XL", TRUE, look); look = 0; break; } else s_top = sp + ((blk_hdr_ptr_t)sp)->bsiz; if (0 >= (signed char)(((blk_hdr_ptr_t)sp)->levl)) { util_out_print("Error: sibling search reached level 0", TRUE); look = 0; break; } srp = sp + SIZEOF(blk_hdr); GET_SHORT(rsize, &((rec_hdr_ptr_t)srp)->rsiz); srp += rsize; GET_LONG(look, srp - SIZEOF(block_id)); if (look >= cs_addrs->ti->total_blks) { util_out_print("Error: sibling search got 0x!XL which exceeds total blocks 0x!XL", TRUE, look, cs_addrs->ti->total_blks); look = 0; break; } } } else look = 0; patch_right_sib = look; } if (patch_right_sib) util_out_print("0x!XL!/", TRUE, patch_right_sib); else util_out_print("none!/", TRUE); DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); REVERT; return; } util_out_print("!/ Directory path!/ Path--blk:off", TRUE); patch_dir_path_count--; for (count = 0; count < patch_dir_path_count; count++) { memcpy(util_buff, " ", 1); util_len = 1; util_len += i2hex_nofill(patch_path[count], (uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len], ":", 1); util_len += 1; util_len += i2hex_nofill(patch_offset[count], (uchar_ptr_t)&util_buff[util_len], 4); memcpy(&util_buff[util_len], ",", 1); util_len += 1; util_buff[util_len] = 0; util_out_print(util_buff, FALSE); } if (!patch_find_root_search) { assert(patch_path_count); /* OK to assert since pro works as desired */ util_out_print("!/ Global tree path!/ Path--blk:off", TRUE); } if (patch_path_count) { patch_path_count--; for (count = 0; count < patch_path_count; count++) { memcpy(util_buff, " ", 1); util_len = 1; util_len += i2hex_nofill(patch_path1[count], (uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len], ":", 1); util_len += 1; util_len += i2hex_nofill(patch_offset1[count], (uchar_ptr_t)&util_buff[util_len], 4); memcpy(&util_buff[util_len], ",", 1); util_len += 1; util_buff[util_len] = 0; util_out_print(util_buff, FALSE); } } else assert(patch_find_root_search); /* OK to assert since pro works as desired */ memcpy(util_buff, " ", 1); util_len = 1; util_len += i2hex_nofill(patch_find_root_search ? patch_path[count] : patch_path1[count], (uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len], "!/", 2); util_len += 2; util_buff[util_len] = 0; util_out_print(util_buff, TRUE); DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); REVERT; return; } /* Control-C condition handler */ CONDITION_HANDLER(dse_f_blk_ch) { START_CH; if (ERR_CTRLC == SIGNAL) DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); NEXTCH; } fis-gtm-V6.0-003/sr_port/dse_f_free.c0000644000032200000250000000643212201176155016264 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "cli.h" #include "util.h" #include "gdsbml.h" #include "bmm_find_free.h" #include "dse.h" /* Include prototypes */ #include "t_qread.h" GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; error_def(ERR_DSEBLKRDFAIL); #define MAX_UTIL_LEN 80 void dse_f_free(void) { block_id blk; bool in_last_bmap; char util_buff[MAX_UTIL_LEN]; sm_uc_ptr_t lmap_base; int4 bplmap, total_blks; int4 util_len, master_bit, lmap_bit, hint_over_bplmap, hint_mod_bplmap; boolean_t was_crit, was_hold_onto_crit; int4 dummy_int, nocrit_present; cache_rec_ptr_t dummy_cr; if (cs_addrs->hdr->bplmap == 0) { util_out_print("Cannot perform free block search: bplmap field of file header is zero.", TRUE); return; } bplmap = cs_addrs->hdr->bplmap; if(!cli_get_hex("HINT", (uint4 *)&blk)) return; if (blk < 0 || blk >= cs_addrs->ti->total_blks || (blk / bplmap * bplmap == blk)) { util_out_print("Error: invalid block number.", TRUE); return; } hint_over_bplmap = blk / bplmap; master_bit = bmm_find_free(hint_over_bplmap, cs_addrs->bmm, (cs_addrs->ti->total_blks + bplmap - 1)/ bplmap); if (master_bit == -1) { util_out_print("Error: database full.", TRUE); return; } in_last_bmap = (master_bit == (cs_addrs->ti->total_blks / bplmap)); was_crit = cs_addrs->now_crit; nocrit_present = (CLI_NEGATED == cli_present("CRIT")); DSE_GRAB_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); if(!(lmap_base = t_qread(master_bit * bplmap, &dummy_int, &dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); if (master_bit == hint_over_bplmap) hint_mod_bplmap = blk - blk / bplmap * bplmap; else hint_mod_bplmap = 0; if (in_last_bmap) total_blks = (cs_addrs->ti->total_blks - master_bit); else total_blks = bplmap; lmap_bit = bml_find_free(hint_mod_bplmap, lmap_base + SIZEOF(blk_hdr), total_blks); if (lmap_bit == -1) { memcpy(util_buff, "Error: bit map in block ", 24); util_len = 24; util_len += i2hex_nofill(master_bit * bplmap, (uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len], " incorrectly marked free in master map.", 39); util_len += 39; util_buff[util_len] = 0; util_out_print(util_buff, TRUE); DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); return; } memcpy(util_buff, "!/Next free block is ", 21); util_len = 21; util_len += i2hex_nofill(master_bit * bplmap + lmap_bit, (uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len], ".!/", 3); util_len += 3; util_buff[util_len] = 0; util_out_print(util_buff, TRUE); DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); return; } fis-gtm-V6.0-003/sr_port/dse_f_key.c0000644000032200000250000001033412201176155016127 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "cli.h" #include "util.h" #include "dse.h" GBLREF short int patch_path_count; GBLREF block_id ksrch_root; GBLREF bool patch_find_root_search; GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; #define MAX_UTIL_LEN 64 void dse_f_key(void) { block_id path[MAX_BT_DEPTH + 1], root_path[MAX_BT_DEPTH + 1]; int4 offset[MAX_BT_DEPTH + 1], root_offset[MAX_BT_DEPTH + 1], nocrit_present; char targ_key[MAX_KEY_SZ + 1], targ_key_root[MAX_KEY_SZ + 1], *key_top, util_buff[MAX_UTIL_LEN]; int size, size_root, root_path_count, count, util_len; boolean_t found, was_crit, was_hold_onto_crit; if (!dse_getki(&targ_key[0], &size, LIT_AND_LEN("KEY"))) return; patch_path_count = 1; root_path[0] = get_dir_root(); for (key_top = &targ_key[0]; key_top < ARRAYTOP(targ_key); ) if (!*key_top++) break; size_root = (int)(key_top - &targ_key[0] + 1); memcpy(&targ_key_root[0],&targ_key[0],size_root); targ_key_root[size_root - 1] = targ_key_root[size_root] = 0; patch_find_root_search = TRUE; was_crit = cs_addrs->now_crit; nocrit_present = (CLI_NEGATED == cli_present("CRIT")); DSE_GRAB_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); if (!dse_key_srch(root_path[0], &root_path[1], &root_offset[0], &targ_key_root[0], size_root)) { util_out_print("!/Key not found, no root present.!/",TRUE); DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); return; } root_path_count = patch_path_count; patch_path_count = 1; path[0] = ksrch_root; patch_find_root_search = FALSE; if (!dse_key_srch(path[0], &path[1], &offset[0], &targ_key[0], size)) { memcpy(util_buff,"!/Key not found, would be in block ",36); util_len = 36; util_len += i2hex_nofill(path[patch_path_count - 2], (uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len], ".",1); util_len += 1; util_buff[util_len] = 0; util_out_print(util_buff,FALSE); patch_path_count -= 1; }else { memcpy(util_buff,"!/Key found in block ",22); util_len = 22; util_len += i2hex_nofill(path[patch_path_count - 1], (uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len], ".",1); util_len += 1; util_buff[util_len] = 0; util_out_print(util_buff,FALSE); } util_out_print("!/ Directory path!/ Path--blk:off",TRUE); for (count = 0; count < root_path_count ;count++) { memcpy(util_buff," ",1); util_len = 1; util_len += i2hex_nofill(root_path[count],(uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len],":",1); util_len += 1; util_len += i2hex_nofill(root_offset[count],(uchar_ptr_t)&util_buff[util_len], 4); memcpy(&util_buff[util_len],",",1); util_len += 1; util_buff[util_len] = 0; util_out_print(util_buff,FALSE); } util_out_print("!/ Global tree path!/ Path--blk:off",TRUE); if (patch_path_count) { for (count = 0; count < patch_path_count ;count++) { memcpy(util_buff," ",1); util_len = 1; util_len += i2hex_nofill(path[count],(uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len],":",1); util_len += 1; util_len += i2hex_nofill(offset[count],(uchar_ptr_t)&util_buff[util_len], 4); memcpy(&util_buff[util_len],",",1); util_len += 1; util_buff[util_len] = 0; util_out_print(util_buff,FALSE); } util_out_print(0,TRUE); } else { memcpy(util_buff," ",1); util_len = 1; util_len += i2hex_nofill(root_path[count],(uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len],"!/",2); util_len += 2; util_buff[util_len] = 0; util_out_print(util_buff,TRUE); } DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); return; } fis-gtm-V6.0-003/sr_port/dse_f_reg.c0000644000032200000250000000730512201176155016120 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "min_max.h" /* needed for init_root_gv.h */ #include "init_root_gv.h" #include "util.h" #include "cli.h" #include "dse.h" GBLREF block_id patch_curr_blk; GBLREF gd_region *gv_cur_region; GBLREF gd_addr *gd_header; GBLREF sgmnt_data_ptr_t cs_data; GBLREF sgmnt_addrs *cs_addrs; GBLREF short crash_count; GBLREF mval dollar_zgbldir; GBLREF gd_addr *original_header; GBLREF gv_namehead *gv_target; GBLREF gv_key *gv_currkey; void dse_f_reg(void) { char rn[MAX_RN_LEN]; unsigned short rnlen; int i; bool found; gd_region *ptr; gd_addr *temp_gdaddr; gd_binding *map; temp_gdaddr = gd_header; gd_header = original_header; rnlen = SIZEOF(rn); if (!cli_get_str("REGION",rn,&rnlen)) { gd_header = temp_gdaddr; return; } if (rn[0] == '*' && rnlen == 1) { util_out_print("List of global directory:!_!AD!/",TRUE,dollar_zgbldir.str.len,dollar_zgbldir.str.addr); for (i=0, ptr = gd_header->regions; i < gd_header->n_regions ;i++, ptr++) { util_out_print("!/File !_!AD",TRUE, ptr->dyn.addr->fname_len,&ptr->dyn.addr->fname[0]); util_out_print("Region!_!AD",TRUE, REG_LEN_STR(ptr)); } gd_header = temp_gdaddr; return; } assert(rn[0]); found = FALSE; for (i=0, ptr = gd_header->regions; i < gd_header->n_regions ;i++, ptr++) { if (found = !memcmp(&ptr->rname[0],&rn[0],MAX_RN_LEN)) break; } if (!found) { util_out_print("Error: region not found.",TRUE); gd_header = temp_gdaddr; return; } if (ptr == gv_cur_region) { util_out_print("Error: already in region: !AD",TRUE,REG_LEN_STR(gv_cur_region)); gd_header = temp_gdaddr; return; } if (ptr->dyn.addr->acc_meth == dba_cm) { util_out_print("Error: Cannot edit an GT.CM database file.",TRUE); gd_header = temp_gdaddr; return; } if (ptr->dyn.addr->acc_meth == dba_usr) { util_out_print("Error: Cannot edit a non-GDS format database file.",TRUE); gd_header = temp_gdaddr; return; } if (!ptr->open) { util_out_print("Error: that region was not opened because it is not bound to any namespace.",TRUE); gd_header = temp_gdaddr; return; } if (TRUE == cs_addrs->now_crit) { util_out_print("Warning: now leaving region in critical section: !AD",TRUE, gv_cur_region->rname_len, gv_cur_region->rname); } gv_cur_region = ptr; gv_target = NULL; /* to prevent out-of-sync situations between gv_target and cs_addrs */ gv_currkey->base[0] = '\0'; /* prevent fast-path from op_gvname from being taken as region has been switched * and gv_target has been reset to NULL. */ gv_currkey->end = 0; /* clear end so it is in sync with base[0] */ switch (gv_cur_region->dyn.addr->acc_meth) { case dba_mm: case dba_bg: cs_addrs = &FILE_INFO(gv_cur_region)->s_addrs; cs_data = cs_addrs->hdr; break; default: GTMASSERT; } if (cs_addrs && cs_addrs->critical) crash_count = cs_addrs->critical->crashcnt; util_out_print("!/File !_!AD",TRUE, DB_LEN_STR(gv_cur_region)); util_out_print("Region!_!AD!/",TRUE, REG_LEN_STR(gv_cur_region)); patch_curr_blk = get_dir_root(); gv_init_reg(gv_cur_region); GET_SAVED_GDADDR(gd_header, temp_gdaddr, map, gv_cur_region); return; } fis-gtm-V6.0-003/sr_port/dse_fdmp.c0000644000032200000250000001200312201176155015753 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "mlkdef.h" #include "gdsroot.h" #include "gdsbt.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsfhead.h" #include "gtmctype.h" #include "cli.h" #include "dse.h" #include "gvsub2str.h" #include "gdsblk.h" #include "zshow.h" #define COUNT_TRAILING_ZERO(NUM, WCP, TRAIL_ZERO) \ { \ if (0 == NUM) \ *WCP++ = '0'; \ for (TRAIL_ZERO = 0; (NUM > 0) && (0 == (NUM % 10)); TRAIL_ZERO++, NUM /= 10) \ ; \ } #define OUTPUT_NUMBER(NUM, WCP, TRAIL_ZERO) \ { \ for (rev_num = 0; NUM > 0; rev_num = (rev_num * 10 + NUM % 10), NUM /= 10) \ ; \ for (; rev_num > 0; *WCP++ = (rev_num % 10 + ASCII_0), rev_num /= 10) \ ; \ for (; TRAIL_ZERO > 0 ; *WCP++ = '0', TRAIL_ZERO--) \ ; \ } GBLREF enum dse_fmt dse_dmp_format; GBLREF gd_region *gv_cur_region; GBLREF char patch_comp_key[MAX_KEY_SZ + 1]; static unsigned char *work_buff; static unsigned int work_buff_length; boolean_t dse_fdmp(sm_uc_ptr_t data, int len) { unsigned char *key_char_ptr, *work_char_ptr; int dest_len; unsigned char *ret_addr; boolean_t is_snblk=FALSE; span_subs *ss_ptr; /*spanning node key pointer */ unsigned int snbid, offset, trail_zero, rev_num, num; unsigned short blk_sz; if (work_buff_length < ZWR_EXP_RATIO(gv_cur_region->max_rec_size)) { work_buff_length = ZWR_EXP_RATIO(gv_cur_region->max_rec_size); if (work_buff) free (work_buff); work_buff = (unsigned char *)malloc(work_buff_length); } work_char_ptr = work_buff; *work_char_ptr++ = '^'; for (key_char_ptr = (uchar_ptr_t)patch_comp_key; *key_char_ptr ; key_char_ptr++) { if (PRINTABLE(*key_char_ptr)) *work_char_ptr++ = *key_char_ptr; else return FALSE; } key_char_ptr++; if (SPAN_START_BYTE != *key_char_ptr) /*Global has subscript*/ { *work_char_ptr++ = '('; for (;;) { work_char_ptr = gvsub2str(key_char_ptr, work_char_ptr, TRUE); /* Removed unnecessary checks for printable characters (PRINTABLE()) here * since the data being written into files (OPENed files) would have been * passed through ZWR translation which would have taken care of converting * to $CHAR() or $ZCHAR() */ for (; *key_char_ptr ; key_char_ptr++) ; key_char_ptr++; /* Check if this is spanning node if yes break out of the loop */ if (SPAN_START_BYTE == *key_char_ptr && (int)*(key_char_ptr + 1) >= SPAN_BYTE_MIN && (int)*(key_char_ptr + 2) >= SPAN_BYTE_MIN) { is_snblk = TRUE; break; } if (*key_char_ptr) *work_char_ptr++ = ','; else break; } *work_char_ptr++ = ')'; } else /*Spanning node without subscript*/ is_snblk = TRUE; if (is_snblk) { ss_ptr = (span_subs *)key_char_ptr; snbid = SPAN_GVSUBS2INT(ss_ptr); key_char_ptr = key_char_ptr + SPAN_SUBS_LEN + 1; /* Move out of special subscript of spanning node */ blk_sz = gv_cur_region->dyn.addr->blk_size; /* Decide the offset of the content of a block inside the value of spanning node*/ offset = (snbid) ? (blk_sz - (SIZEOF(blk_hdr) + SIZEOF(rec_hdr) + gv_cur_region->dyn.addr->reserved_bytes + (key_char_ptr - (uchar_ptr_t)patch_comp_key + 1))) * (snbid - 1) : 0 ; ret_addr =(unsigned char *)memmove((void *)(work_buff+4), (void *)work_buff, (work_char_ptr - work_buff)); assert(*ret_addr == '^'); *work_buff = '$'; *(work_buff + 1) = 'z'; *(work_buff + 2) = 'e'; *(work_buff + 3) = '('; /* length of "$ze(" is 4, so move the work_char_ptr by 4*/ work_char_ptr = work_char_ptr + 4; *work_char_ptr++ = ','; /* Dump the offset of the content of a block inside the value of spanning node */ num = snbid ? offset : 0; COUNT_TRAILING_ZERO(num, work_char_ptr, trail_zero); num = offset; OUTPUT_NUMBER(num, work_char_ptr, trail_zero); *work_char_ptr++ = ','; /* Dump the length of the content of a block */ num = snbid ? len : 0; COUNT_TRAILING_ZERO(num, work_char_ptr, trail_zero); num = snbid ? len : 0; OUTPUT_NUMBER(num, work_char_ptr, trail_zero); *work_char_ptr++ = ')'; } assert(MAX_ZWR_KEY_SZ >= work_char_ptr - work_buff); if (GLO_FMT == dse_dmp_format) { if (!dse_fdmp_output(work_buff, (int4)(work_char_ptr - work_buff))) return FALSE; if (!dse_fdmp_output(data, len)) return FALSE; } else { assert(ZWR_FMT == dse_dmp_format); *work_char_ptr++ = '='; if(is_snblk && !snbid) { *work_char_ptr++ = '"'; *work_char_ptr++ = '"'; dest_len = 0; } else format2zwr(data, len, work_char_ptr, &dest_len); if (!dse_fdmp_output(work_buff, (int4)(work_char_ptr + dest_len - work_buff))) return FALSE; } return TRUE; } fis-gtm-V6.0-003/sr_port/dse_find_roots.c0000644000032200000250000000461512201176155017205 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "dsefind.h" #include "copy.h" #include "dse.h" /* Include prototypes */ #include "t_qread.h" GBLREF global_root_list *global_roots_tail; GBLREF sgmnt_addrs *cs_addrs; GBLREF block_id patch_path[MAX_BT_DEPTH + 1]; GBLREF int4 patch_offset[MAX_BT_DEPTH + 1]; GBLREF short int patch_path_count; void dse_find_roots(block_id index) { int count; int4 dummy_int; cache_rec_ptr_t dummy_cr; short temp_short; sm_uc_ptr_t bp, b_top, rp, r_top, key_top; global_dir_path *d_ptr; error_def(ERR_DSEBLKRDFAIL); if(!(bp = t_qread(index,&dummy_int,&dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); if (((blk_hdr_ptr_t) bp)->bsiz > cs_addrs->hdr->blk_size) b_top = bp + cs_addrs->hdr->blk_size; else if (((blk_hdr_ptr_t) bp)->bsiz < SIZEOF(blk_hdr)) b_top = bp + SIZEOF(blk_hdr); else b_top = bp + ((blk_hdr_ptr_t) bp)->bsiz; for (rp = bp + SIZEOF(blk_hdr); rp < b_top ;rp = r_top) { GET_SHORT(temp_short,&((rec_hdr_ptr_t)rp)->rsiz); r_top = rp + temp_short; if (r_top > b_top) r_top = b_top; if (r_top - rp < SIZEOF(block_id)) break; global_roots_tail->link = (global_root_list *)malloc(SIZEOF(global_root_list)); global_roots_tail = global_roots_tail->link; global_roots_tail->link = 0; for (key_top = rp + SIZEOF(rec_hdr); key_top < r_top; ) if(!*key_top++ && !*key_top++) break; GET_LONG(global_roots_tail->root,key_top); global_roots_tail->dir_path = (global_dir_path *)malloc(SIZEOF(global_dir_path)); d_ptr = global_roots_tail->dir_path; for (count = 0; ; count++) { d_ptr->block = patch_path[count]; d_ptr->offset = patch_offset[count]; if (count < patch_path_count - 1) d_ptr->next = (global_dir_path *)malloc(SIZEOF(global_dir_path)); else { d_ptr->next = 0; d_ptr->offset = (int4)(rp - bp); break; } d_ptr = d_ptr->next; } } return; } fis-gtm-V6.0-003/sr_port/dse_flush.c0000644000032200000250000000273112201176155016155 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" /* needed for jnl.h */ #include "jnl.h" /* needed for the WCSFLU_* macros */ #include "wcs_flu.h" #include "dse.h" GBLREF gd_region *gv_cur_region; GBLREF short crash_count; GBLREF sgmnt_addrs *cs_addrs; void dse_flush(void) { boolean_t was_crit; error_def(ERR_DSEONLYBGMM); error_def(ERR_DBRDONLY); if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); switch (gv_cur_region->dyn.addr->acc_meth) { case dba_bg: case dba_mm: if (cs_addrs->critical) crash_count = cs_addrs->critical->crashcnt; was_crit = cs_addrs->now_crit; if (!was_crit) grab_crit(gv_cur_region); wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SYNC_EPOCH); if (!was_crit) rel_crit(gv_cur_region); break; default: rts_error(VARLSTCNT(4) ERR_DSEONLYBGMM, 2, LEN_AND_LIT("BUFFER_FLUSH")); break; } return; } fis-gtm-V6.0-003/sr_port/dse_getki.c0000644000032200000250000001471712201176176016151 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_strings.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_ctype.h" #include "gtm_facility.h" #include "gtm_stdlib.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "min_max.h" /* needed for init_root_gv.h */ #include "init_root_gv.h" #include "util.h" #include "cli.h" #include "stringpool.h" #include "dse.h" #include "mvalconv.h" #include "op.h" #include "format_targ_key.h" #ifdef GTM_TRIGGER #include "hashtab_mname.h" #include #include "gv_trigger.h" /* needed for INIT_ROOT_GVT */ #include "targ_alloc.h" #endif #ifdef UNICODE_SUPPORTED #include "gtm_utf8.h" #endif GBLREF gv_key *gv_currkey; GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF mval curr_gbl_root; GBLREF gv_namehead *gv_target; LITREF mval literal_hasht; int dse_getki(char *dst, int *len, char *qual, int qual_len) { char buf[MAX_ZWR_KEY_SZ], *src, *temp_dst, *bot, *top, *tmp, slit[MAX_KEY_SZ + 1], key_buf[MAX_KEY_SZ + 1]; short int max_key; unsigned short buf_len; int key_len, dlr_num, dlr_len; int num; unsigned char *ptr; mval key_subsc; sgmnt_addrs *csa; span_subs subs; buf_len = SIZEOF(buf); if (!cli_get_str(qual, buf, &buf_len)) return FALSE; bot = temp_dst = (char *)&key_buf[0]; top = &buf[buf_len]; src = &buf[0]; if (*src++ != '^') { util_out_print("Error: invalid key.", TRUE); return FALSE; } if ((*src >= 'A' && *src <= 'Z') || (*src >= 'a' && *src <= 'z') || (*src == '%') || (*src == '#')) /* first letter must be an alphabet or % or # */ { *temp_dst++ = *src++; } else { util_out_print("Error: invalid key.", TRUE); return FALSE; } for ( ; *src != '(' && src < top ;src++) { if ((*src >= 'A' && *src <= 'Z') || (*src >= 'a' && *src <= 'z') || (*src >= '0' && *src <= '9')) *temp_dst = *src; else { util_out_print("Error: invalid key.", TRUE); return FALSE; } temp_dst++; } *temp_dst = '\0'; csa = cs_addrs; key_len = (int )(temp_dst - bot); INIT_ROOT_GVT(bot, key_len, curr_gbl_root); bot = (char *)&gv_currkey->base[0]; temp_dst = (char *)&gv_currkey->base[0] + gv_currkey->end; max_key = gv_cur_region->max_key_size; if ('(' == *src) { src++; for (;;) { key_subsc.mvtype = MV_STR; if ('$' == *src) /* may be a $char() */ { src++; if ((dlr_len = parse_dlr_char(src, top, slit)) > 0) { key_subsc.str.addr = slit; key_subsc.str.len = STRLEN(slit); src += dlr_len; } else { util_out_print("Error: invalid key.", TRUE); return FALSE; } } else if ('#' == *src) { /*Special spanning global subscript*/ if ('S' != toupper(*(src + 1)) && 'P' != toupper(*(src + 2)) && 'A' != toupper(*(src + 3)) && 'N' != toupper(*(src + 4))) { util_out_print("Error: invalid key.", TRUE); return FALSE; } src = src + SPAN_SUBS_LEN + 1; for (num = 0, src++; *src != ')'; num = (num * DECIMAL_BASE + (int)(*src++ - ASCII_0))) ; ptr = gv_currkey->base + gv_currkey->end; num = num - 1; SPAN_INITSUBS(&subs, num); SPAN_SUBSCOPY_SRC2DST(ptr, (unsigned char *)&subs); ptr = ptr + SPAN_SUBS_LEN; *ptr++ = KEY_DELIMITER; *ptr = KEY_DELIMITER; gv_currkey->end = ptr - gv_currkey->base; break; } else if (*src != '\"') /* numerical subscript */ { for (key_subsc.str.addr = src ; *src != ')' && *src != ','; src++) { if (src == top || (*src < '0' || *src > '9') && *src != '-' && *src != '.') { util_out_print("Error: invalid key.", TRUE); return FALSE; } } key_subsc.str.len = INTCAST(src - key_subsc.str.addr); s2n(&key_subsc); key_subsc.mvtype &= MV_NUM_MASK; } else { src++; tmp = slit; for (;;) { if (src == top) { util_out_print("Error: invalid key.", TRUE); return FALSE; } if (*src == '\"') if (*++src != '\"') break; *tmp++ = *src++; } key_subsc.str.addr = slit; key_subsc.str.len = INTCAST(tmp - slit); } if ( 0 == key_subsc.str.len && NEVER == cs_addrs->hdr->null_subs) { util_out_print("Error: Null subscripts not allowed", TRUE); return FALSE; } mval2subsc(&key_subsc, gv_currkey); if (gv_currkey->end >= max_key) ISSUE_GVSUBOFLOW_ERROR(gv_currkey); if (*src != ',') break; src++; } if (*src++ != ')') { util_out_print("Error: invalid key.", TRUE); return FALSE; } temp_dst = (char *)&gv_currkey->base[0] + gv_currkey->end; } if (src != top) { util_out_print("Error: invalid key.", TRUE); return FALSE; } *len = (int)(temp_dst - bot + 1); memcpy(dst, &gv_currkey->base[0], *len); return TRUE; } int parse_dlr_char(char *src, char *top, char *dlr_subsc) { int indx = 0, dlr_len, dlr_val, harlen; char lcl_buf[MAX_KEY_SZ + 1]; char *tmp_buf, *strnext; boolean_t dlrzchar = FALSE; tmp_buf = src; if ('Z' == TOUPPER(*tmp_buf)) { dlrzchar = TRUE; tmp_buf++; } if ('C' != TOUPPER(*tmp_buf++)) return 0; if ('H' == TOUPPER(*tmp_buf)) { if (top - tmp_buf <= STR_LIT_LEN("har") || STRNCASECMP(tmp_buf, "har", STR_LIT_LEN("har"))) { if (!dlrzchar) return 0; tmp_buf++; } else tmp_buf += STR_LIT_LEN("har"); } else if (dlrzchar) return 0; if (*tmp_buf++ != '(') return 0; if (!ISDIGIT_ASCII(*tmp_buf)) return 0; while (tmp_buf != top) { if (ISDIGIT_ASCII(*tmp_buf)) lcl_buf[indx++] = *tmp_buf; else if (',' == *tmp_buf || ')' == *tmp_buf) { lcl_buf[indx] = '\0'; dlr_val = ATOI(lcl_buf); if (0 > dlr_val) return 0; if (!gtm_utf8_mode || dlrzchar) { if (255 < dlr_val) return 0; *dlr_subsc++ = dlr_val; } #ifdef UNICODE_SUPPORTED else { strnext = (char *)UTF8_WCTOMB(dlr_val, dlr_subsc); if (strnext == dlr_subsc) return 0; dlr_subsc = strnext; } #endif indx = 0; if (')' == *tmp_buf) { *dlr_subsc = '\0'; break; } } else return 0; tmp_buf++; } if (tmp_buf == top) return 0; tmp_buf++; return (int)(tmp_buf - src); } fis-gtm-V6.0-003/sr_port/dse_integ.c0000644000032200000250000000424112201176155016140 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "cli.h" #include "util.h" #include "dse.h" /* Include prototypes */ #include "t_qread.h" #include "cert_blk.h" GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF block_id patch_curr_blk; error_def(ERR_DSEBLKRDFAIL); #define MAX_UTIL_LEN 40 void dse_integ(void) { block_id blk; char util_buff[MAX_UTIL_LEN]; sm_uc_ptr_t bp; int4 dummy_int, nocrit_present; cache_rec_ptr_t dummy_cr; int util_len; boolean_t was_crit, was_hold_onto_crit; if (CLI_PRESENT == cli_present("BLOCK")) { if (!cli_get_hex("BLOCK", (uint4 *)&blk)) return; if (blk < 0 || blk >= cs_addrs->ti->total_blks) { util_out_print("Error: invalid block number.", TRUE); return; } patch_curr_blk = blk; } memcpy(util_buff, "!/Checking integrity of block ", 30); util_len = 30; util_len += i2hex_nofill(patch_curr_blk, (uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len], ":", 1); util_len += 1; util_buff[util_len] = 0; util_out_print(util_buff, TRUE); was_crit = cs_addrs->now_crit; nocrit_present = (CLI_NEGATED == cli_present("CRIT")); DSE_GRAB_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); if (!(bp = t_qread(patch_curr_blk, &dummy_int, &dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); if (TRUE == cert_blk(gv_cur_region, patch_curr_blk, (blk_hdr_ptr_t)bp, 0, FALSE)) util_out_print("!/ No errors detected.!/", TRUE); else util_out_print(NULL, TRUE); DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); return; } fis-gtm-V6.0-003/sr_port/dse_is_blk_free.c0000644000032200000250000000250312201176155017275 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gdsbml.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "dse.h" /* Include prototypes */ #include "dse_is_blk_free.h" #include "t_qread.h" GBLREF sgmnt_addrs *cs_addrs; bool dse_is_blk_free (block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr) { uint4 status; uint4 index, offset; sm_uc_ptr_t bp; error_def(ERR_DSEBLKRDFAIL); index = (blk / cs_addrs->hdr->bplmap) * cs_addrs->hdr->bplmap; offset = blk - index; if(!(bp = t_qread (index, cycle, cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); status = dse_lm_blk_free(offset * BML_BITS_PER_BLK, bp + SIZEOF(blk_hdr)); if (0 == status) /* status == 00 => blk is busy */ return FALSE; else /* status == 01 and 11 => blk is free. Also illegal value is considered as free */ return TRUE; } fis-gtm-V6.0-003/sr_port/dse_is_blk_free.h0000644000032200000250000000120412201176155017277 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef DSE_IS_BLK_FREE_DEFINED /* Declare parms for dse_is_blk_free.c */ bool dse_is_blk_free (block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr); #define DSE_IS_BLK_FREE_DEFINED #endif fis-gtm-V6.0-003/sr_port/dse_is_blk_in.c0000644000032200000250000000424112201176155016763 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "dsefind.h" #include "dse.h" GBLREF sgmnt_addrs *cs_addrs; GBLREF short int patch_dir_path_count; GBLREF block_id patch_find_blk; GBLREF bool patch_find_root_search; GBLREF int4 patch_offset[MAX_BT_DEPTH + 1]; GBLREF int4 patch_offset1[MAX_BT_DEPTH + 1]; GBLREF block_id patch_path[MAX_BT_DEPTH + 1]; GBLREF block_id patch_path1[MAX_BT_DEPTH + 1]; GBLREF short int patch_path_count; int dse_is_blk_in(sm_uc_ptr_t rp, sm_uc_ptr_t r_top, short size) { sm_uc_ptr_t key_top; char targ_key[MAX_KEY_SZ + 1]; memcpy(targ_key, rp + SIZEOF(rec_hdr), size); if ((patch_find_blk != patch_path[0]) && !dse_order(patch_path[0], &patch_path[1], patch_offset, targ_key, size, 0)) return FALSE; patch_dir_path_count = patch_path_count; if (!patch_find_root_search || (patch_find_blk != patch_path[patch_path_count - 1])) { if ((0 >= patch_path[patch_path_count - 1]) || (patch_path[patch_path_count] > cs_addrs->ti->total_blks)) return FALSE; patch_find_root_search = FALSE; for (key_top = rp + SIZEOF(rec_hdr); (*key_top++ || *key_top++) && (key_top < r_top);) ; size = key_top - rp - SIZEOF(rec_hdr); if (0 > size) size = 0; else if (SIZEOF(targ_key) < size) size = SIZEOF(targ_key); memcpy(targ_key, rp + SIZEOF(rec_hdr), size); patch_path1[0] = patch_path[patch_path_count - 1]; patch_path[patch_path_count - 1] = 0; patch_path_count = 1; if ((patch_find_blk != patch_path1[0]) && !dse_order(patch_path1[0], &patch_path1[1], patch_offset1, targ_key, size, 0)) return FALSE; } else patch_path_count = 0; return TRUE; } fis-gtm-V6.0-003/sr_port/dse_ksrch.c0000644000032200000250000001021012201176155016135 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "copy.h" #include "dse.h" /* Include prototypes */ #include "t_qread.h" #include "mmemory.h" GBLREF short int patch_path_count; GBLREF sgmnt_addrs *cs_addrs; GBLREF char patch_comp_key[MAX_KEY_SZ + 1]; GBLREF unsigned short patch_comp_count; GBLREF bool patch_find_root_search; GBLDEF block_id ksrch_root; error_def(ERR_DSEBLKRDFAIL); int dse_ksrch(block_id srch, block_id_ptr_t pp, int4 *off, char *targ_key, int targ_len) { sm_uc_ptr_t bp, b_top, rp, r_top, key_top, blk_id; unsigned short cc; int tmp_cmpc; int rsize; ssize_t size; int4 cmp; unsigned short dummy_short; int4 dummy_int; cache_rec_ptr_t dummy_cr; if(!(bp = t_qread(srch, &dummy_int, &dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); if (((blk_hdr_ptr_t) bp)->bsiz > cs_addrs->hdr->blk_size) b_top = bp + cs_addrs->hdr->blk_size; else if (((blk_hdr_ptr_t) bp)->bsiz < SIZEOF(blk_hdr)) b_top = bp + SIZEOF(blk_hdr); else b_top = bp + ((blk_hdr_ptr_t) bp)->bsiz; patch_comp_count = 0; patch_comp_key[0] = patch_comp_key[1] = 0; *off = 0; for (rp = bp + SIZEOF(blk_hdr); rp < b_top; rp = r_top) { *off = (int4)(rp - bp); GET_SHORT(dummy_short, &((rec_hdr_ptr_t)rp)->rsiz); rsize = dummy_short; if (rsize < SIZEOF(rec_hdr)) r_top = rp + SIZEOF(rec_hdr); else r_top = rp + rsize; if (r_top > b_top) r_top = b_top; if (r_top - rp < (((blk_hdr_ptr_t)bp)->levl ? SIZEOF(block_id) : MIN_DATA_SIZE) + SIZEOF(rec_hdr)) { *pp = 0; break; } for (key_top = rp + SIZEOF(rec_hdr); key_top < r_top ; ) if (!*key_top++ && !*key_top++) break; if (((blk_hdr_ptr_t)bp)->levl && key_top > (blk_id = r_top - SIZEOF(block_id))) key_top = blk_id; if (EVAL_CMPC((rec_hdr_ptr_t)rp) > patch_comp_count) cc = patch_comp_count; else cc = EVAL_CMPC((rec_hdr_ptr_t)rp); size = (ssize_t)(key_top - rp - SIZEOF(rec_hdr)); if (size > MAX_KEY_SZ - cc) size = MAX_KEY_SZ - cc; if (size < 0) size = 0; memcpy(&patch_comp_key[cc], rp + SIZEOF(rec_hdr), size); patch_comp_count = (int)(cc + size); GET_LONGP(pp, key_top); cmp = memvcmp(targ_key, targ_len, &patch_comp_key[0], patch_comp_count); if (0 > cmp) break; if (!cmp) { if (0 != ((blk_hdr_ptr_t)bp)->levl) break; if (patch_find_root_search) { for (key_top = rp + SIZEOF(rec_hdr); key_top < r_top; ) if (!*key_top++ && !*key_top++) break; GET_LONG(ksrch_root, key_top); } return TRUE; } } patch_path_count++; if (((blk_hdr_ptr_t) bp)->levl && *pp > 0 && *pp < cs_addrs->ti->total_blks && (*pp % cs_addrs->hdr->bplmap) && dse_ksrch(*pp, pp + 1, off + 1, targ_key, targ_len)) return TRUE; return FALSE; } int dse_key_srch(block_id srch, block_id_ptr_t key_path, int4 *off, char *targ_key, int targ_len) { int status = dse_ksrch(srch, key_path, off, targ_key, targ_len); if(status) return status; else if(!patch_find_root_search) { /* We are not searching for the global name in the directory tree and search for the regular-key * has failed. So, adjust to the input key with special subscript to indicate it as a spanning node key. * call dse_ksrch() again. */ targ_len -= 1; /* back off 1 to overlay terminator */ SPAN_INITSUBS((span_subs *)(targ_key + targ_len), 0); targ_len += SPAN_SUBS_LEN; targ_key[targ_len++] = KEY_DELIMITER; targ_key[targ_len++] = KEY_DELIMITER; patch_path_count = 1; /*This indicates the length of the path of node in gvtree*/ patch_find_root_search = FALSE; return(dse_ksrch(srch,key_path, off, targ_key, targ_len)); } return FALSE; } fis-gtm-V6.0-003/sr_port/dse_lm_blk_free.c0000644000032200000250000000214712201176155017276 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "gdsbml.h" #include "cli.h" #include "dse.h" int4 dse_lm_blk_free(int4 blk, sm_uc_ptr_t base_addr) { sm_uc_ptr_t ptr; unsigned char valid; int4 bits; blk /= BML_BITS_PER_BLK; ptr = base_addr + (blk * BML_BITS_PER_BLK) / 8; valid = *ptr; switch (blk % (8 / BML_BITS_PER_BLK)) { case 0: break; case 1: valid = valid >> BML_BITS_PER_BLK; break; case 2: valid = valid >> 2 * BML_BITS_PER_BLK; break; case 3: valid = valid >> 3 * BML_BITS_PER_BLK; break; } bits = valid & 3; return bits; } fis-gtm-V6.0-003/sr_port/dse_m_rest.c0000644000032200000250000000770012201176155016326 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /******************************************************************************* * * MODULE NAME: PATCH_M_REST * * CALLING SEQUENCE: void dse_m_rest (blk, bml_list, bml_size) * block_id blk; * unsigned char *bml_list; * int4 bml_size; * * DESCRIPTION: This is a recursive routine kicked off by PATCH_MAPS * in the RESTORE_ALL function. It reconstructs a * a local copy of all the local bit maps. * * HISTORY: * *******************************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "copy.h" #include "util.h" #include "gdsbml.h" #include "dse.h" /* Include prototypes */ #include "t_qread.h" GBLREF sgmnt_addrs *cs_addrs; #define MAX_UTIL_LEN 64 void dse_m_rest ( block_id blk, /* block number */ unsigned char *bml_list, /* start of local list of local bit maps */ int4 bml_size, /* size of each entry in *bml_list */ sm_vuint_ptr_t blks_ptr, /* total free blocks */ bool in_dir_tree) { sm_uc_ptr_t bp, b_top, rp, r_top, bml_ptr, np, ptr; unsigned char util_buff[MAX_UTIL_LEN]; block_id next; int util_len; int4 dummy_int; cache_rec_ptr_t dummy_cr; int4 bml_index; short level, rsize; int4 bplmap; error_def(ERR_DSEBLKRDFAIL); if(!(bp = t_qread (blk, &dummy_int, &dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); if (((blk_hdr_ptr_t) bp)->bsiz > cs_addrs->hdr->blk_size) b_top = bp + cs_addrs->hdr->blk_size; else if (((blk_hdr_ptr_t) bp)->bsiz < SIZEOF(blk_hdr)) b_top = bp + SIZEOF(blk_hdr); else b_top = bp + ((blk_hdr_ptr_t) bp)->bsiz; level = ((blk_hdr_ptr_t)bp)->levl; bplmap = cs_addrs->hdr->bplmap; for (rp = bp + SIZEOF(blk_hdr); rp < b_top ;rp = r_top) { if (in_dir_tree || level > 1) /* reread block because it may have been flushed from read */ { if (!(np = t_qread(blk,&dummy_int,&dummy_cr))) /* cache due to LRU buffer scheme and reads in recursive */ rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); /* calls to dse_m_rest. */ if (np != bp) { b_top = np + (b_top - bp); rp = np + (rp - bp); r_top = np + (r_top - bp); bp = np; } } GET_SHORT(rsize,&((rec_hdr_ptr_t)rp)->rsiz); r_top = rp + rsize; if (r_top > b_top) r_top = b_top; if (r_top - rp < (SIZEOF(rec_hdr) + SIZEOF(block_id))) break; if (in_dir_tree && level == 0) { for (ptr = rp + SIZEOF(rec_hdr); ; ) { if (*ptr++ == 0 && *ptr++ == 0) break; } GET_LONG(next,ptr); } else GET_LONG(next,r_top - SIZEOF(block_id)); if (next < 0 || next >= cs_addrs->ti->total_blks || (next / bplmap * bplmap == next)) { memcpy(util_buff,"Invalid pointer in block ",25); util_len = 25; util_len += i2hex_nofill(blk, &util_buff[util_len], 8); memcpy(&util_buff[util_len], " record offset ",15); util_len += 15; util_len += i2hex_nofill((int)(rp - bp), &util_buff[util_len], 4); util_buff[util_len] = 0; util_out_print((char*)util_buff,TRUE); continue; } bml_index = next / bplmap; bml_ptr = bml_list + bml_index * bml_size; if (bml_busy(next - next / bplmap * bplmap, bml_ptr + SIZEOF(blk_hdr))) { *blks_ptr = *blks_ptr - 1; if (((blk_hdr_ptr_t) bp)->levl > 1) { dse_m_rest (next, bml_list, bml_size, blks_ptr, in_dir_tree); } else if (in_dir_tree) { assert(((blk_hdr_ptr_t) bp)->levl == 0 || ((blk_hdr_ptr_t) bp)->levl == 1); dse_m_rest (next, bml_list, bml_size, blks_ptr, ((blk_hdr_ptr_t)bp)->levl); } } } return; } fis-gtm-V6.0-003/sr_port/dse_maps.c0000644000032200000250000002025612201176155015776 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_time.h" #include "gdsroot.h" #include "gdskill.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "gdsbml.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "gdscc.h" #include "filestruct.h" #include "jnl.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "cli.h" #include "util.h" #include "send_msg.h" #include "dse.h" /* Include prototypes */ #include "t_qread.h" #include "dse_is_blk_free.h" #include "bit_set.h" #include "bit_clear.h" #include "t_begin_crit.h" #include "t_write.h" #include "t_end.h" #include "longset.h" /* needed for cws_insert.h */ #include "cws_insert.h" #include "process_deferred_stale.h" #include "gvcst_blk_build.h" #define MAX_UTIL_LEN 80 GBLREF char *update_array, *update_array_ptr; GBLREF uint4 update_array_size; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF block_id patch_curr_blk; GBLREF gd_region *gv_cur_region; GBLREF short crash_count; GBLREF boolean_t unhandled_stale_timer_pop; GBLREF srch_hist dummy_hist; error_def(ERR_DBRDONLY); error_def(ERR_DSEBLKRDFAIL); error_def(ERR_DSEFAIL); void dse_maps(void) { block_id blk, bml_blk; blk_segment *bs1, *bs_ptr; int4 blk_seg_cnt, blk_size; /* needed for BLK_INIT, BLK_SEG and BLK_FINI macros */ sm_uc_ptr_t bp; char util_buff[MAX_UTIL_LEN]; int4 bml_size, bml_list_size, blk_index, bml_index; int4 total_blks, blks_in_bitmap; int4 bplmap, dummy_int; unsigned char *bml_list; cache_rec_ptr_t cr, dummy_cr; bt_rec_ptr_t btr; int util_len; uchar_ptr_t blk_ptr; boolean_t was_crit; uint4 jnl_status; srch_blk_status blkhist; jnl_private_control *jpc; jnl_buffer_ptr_t jbp; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; if (CLI_PRESENT == cli_present("BUSY") || CLI_PRESENT == cli_present("FREE") || CLI_PRESENT == cli_present("MASTER") || CLI_PRESENT == cli_present("RESTORE_ALL")) { if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); } CHECK_AND_RESET_UPDATE_ARRAY; /* reset update_array_ptr to update_array */ csa = cs_addrs; assert(&FILE_INFO(gv_cur_region)->s_addrs == csa); was_crit = csa->now_crit; if (csa->critical) crash_count = csa->critical->crashcnt; csd = csa->hdr; bplmap = csd->bplmap; if (CLI_PRESENT == cli_present("BLOCK")) { if (!cli_get_hex("BLOCK", (uint4 *)&blk)) return; if (blk < 0 || blk >= csa->ti->total_blks) { util_out_print("Error: invalid block number.", TRUE); return; } patch_curr_blk = blk; } else blk = patch_curr_blk; if (CLI_PRESENT == cli_present("FREE")) { if (0 == bplmap) { util_out_print("Cannot perform map updates: bplmap field of file header is zero.", TRUE); return; } if (blk / bplmap * bplmap == blk) { util_out_print("Cannot perform action on a map block.", TRUE); return; } bml_blk = blk / bplmap * bplmap; bm_setmap(bml_blk, blk, FALSE); return; } if (CLI_PRESENT == cli_present("BUSY")) { if (0 == bplmap) { util_out_print("Cannot perform map updates: bplmap field of file header is zero.", TRUE); return; } if (blk / bplmap * bplmap == blk) { util_out_print("Cannot perform action on a map block.", TRUE); return; } bml_blk = blk / bplmap * bplmap; bm_setmap(bml_blk, blk, TRUE); return; } blk_size = csd->blk_size; if (CLI_PRESENT == cli_present("MASTER")) { if (0 == bplmap) { util_out_print("Cannot perform maps updates: bplmap field of file header is zero.", TRUE); return; } if (!was_crit) grab_crit(gv_cur_region); bml_blk = blk / bplmap * bplmap; if (dba_mm == csd->acc_meth) bp = MM_BASE_ADDR(csa) + (off_t)bml_blk * blk_size; else { assert(dba_bg == csd->acc_meth); if (!(bp = t_qread(bml_blk, &dummy_int, &dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); } if ((csa->ti->total_blks / bplmap) * bplmap == bml_blk) total_blks = (csa->ti->total_blks - bml_blk); else total_blks = bplmap; if (NO_FREE_SPACE == bml_find_free(0, bp + SIZEOF(blk_hdr), total_blks)) bit_clear(bml_blk / bplmap, csa->bmm); else bit_set(bml_blk / bplmap, csa->bmm); if (bml_blk > csa->nl->highest_lbm_blk_changed) csa->nl->highest_lbm_blk_changed = bml_blk; if (!was_crit) rel_crit(gv_cur_region); return; } if (CLI_PRESENT == cli_present("RESTORE_ALL")) { if (0 == bplmap) { util_out_print("Cannot perform maps updates: bplmap field of file header is zero.", TRUE); return; } total_blks = csa->ti->total_blks; assert(ROUND_DOWN2(blk_size, 2 * SIZEOF(int4)) == blk_size); bml_size = BM_SIZE(bplmap); bml_list_size = (total_blks + bplmap - 1) / bplmap * bml_size; bml_list = (unsigned char *)malloc(bml_list_size); for (blk_index = 0, bml_index = 0; blk_index < total_blks; blk_index += bplmap, bml_index++) bml_newmap((blk_hdr_ptr_t)(bml_list + bml_index * bml_size), bml_size, csa->ti->curr_tn); if (!was_crit) { grab_crit(gv_cur_region); csa->hold_onto_crit = TRUE; /* need to do this AFTER grab_crit */ } blk = get_dir_root(); assert(blk < bplmap); csa->ti->free_blocks = total_blks - DIVIDE_ROUND_UP(total_blks, bplmap); bml_busy(blk, bml_list + SIZEOF(blk_hdr)); csa->ti->free_blocks = csa->ti->free_blocks - 1; dse_m_rest(blk, bml_list, bml_size, &csa->ti->free_blocks, TRUE); for (blk_index = 0, bml_index = 0; blk_index < total_blks; blk_index += bplmap, bml_index++) { t_begin_crit(ERR_DSEFAIL); CHECK_TN(csa, csd, csd->trans_hist.curr_tn); /* can issue rts_error TNTOOLARGE */ CWS_RESET; CHECK_AND_RESET_UPDATE_ARRAY; /* reset update_array_ptr to update_array */ assert(csa->ti->early_tn == csa->ti->curr_tn); blk_ptr = bml_list + bml_index * bml_size; blkhist.blk_num = blk_index; if (!(blkhist.buffaddr = t_qread(blkhist.blk_num, &blkhist.cycle, &blkhist.cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); BLK_INIT(bs_ptr, bs1); BLK_SEG(bs_ptr, blk_ptr + SIZEOF(blk_hdr), bml_size - SIZEOF(blk_hdr)); BLK_FINI(bs_ptr, bs1); t_write(&blkhist, (unsigned char *)bs1, 0, 0, LCL_MAP_LEVL, TRUE, FALSE, GDS_WRITE_KILLTN); BUILD_AIMG_IF_JNL_ENABLED(csd, csa->ti->curr_tn); t_end(&dummy_hist, NULL, csa->ti->curr_tn); } /* Fill in master map */ for (blk_index = 0, bml_index = 0; blk_index < total_blks; blk_index += bplmap, bml_index++) { blks_in_bitmap = (blk_index + bplmap <= total_blks) ? bplmap : total_blks - blk_index; assert(1 < blks_in_bitmap); /* the last valid block in the database should never be a bitmap block */ if (NO_FREE_SPACE != bml_find_free(0, (bml_list + bml_index * bml_size) + SIZEOF(blk_hdr), blks_in_bitmap)) bit_set(blk_index / bplmap, csa->bmm); else bit_clear(blk_index / bplmap, csa->bmm); if (blk_index > csa->nl->highest_lbm_blk_changed) csa->nl->highest_lbm_blk_changed = blk_index; } if (!was_crit) { csa->hold_onto_crit = FALSE; /* need to do this before the rel_crit */ rel_crit(gv_cur_region); } if (unhandled_stale_timer_pop) process_deferred_stale(); free(bml_list); csd->kill_in_prog = csd->abandoned_kills = 0; return; } MEMCPY_LIT(util_buff, "!/Block "); util_len = SIZEOF("!/Block ") - 1; util_len += i2hex_nofill(blk, (uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len], " is marked !AD in its local bit map.!/", SIZEOF(" is marked !AD in its local bit map.!/") - 1); util_len += SIZEOF(" is marked !AD in its local bit map.!/") - 1; util_buff[util_len] = 0; if (!was_crit) grab_crit(gv_cur_region); util_out_print(util_buff, TRUE, 4, dse_is_blk_free(blk, &dummy_int, &dummy_cr) ? "free" : "busy"); if (!was_crit) rel_crit(gv_cur_region); return; } fis-gtm-V6.0-003/sr_port/dse_order.c0000644000032200000250000001006012201176155016141 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "copy.h" #include "dse.h" /* Include prototypes */ #include "t_qread.h" #include "mmemory.h" GBLREF char patch_comp_key[MAX_KEY_SZ + 1]; GBLREF block_id patch_find_blk, patch_left_sib, patch_right_sib; GBLREF block_id patch_path[MAX_BT_DEPTH + 1], patch_path1[MAX_BT_DEPTH + 1]; GBLREF bool patch_find_root_search; GBLREF sgmnt_addrs *cs_addrs; GBLREF short int patch_path_count; GBLREF unsigned short patch_comp_count; error_def(ERR_DSEBLKRDFAIL); int dse_order(block_id srch, block_id_ptr_t pp, int4 *op, char *targ_key, short int targ_len, bool dir_data_blk) { sm_uc_ptr_t bp, b_top, key_top, ptr, rp, r_top; unsigned short cc; int tmp_cmpc; block_id last; short int rsize, size; int4 dummy_int; cache_rec_ptr_t dummy_cr; last = 0; patch_path_count++; if (!(bp = t_qread(srch, &dummy_int, &dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); if (((blk_hdr_ptr_t)bp)->bsiz > cs_addrs->hdr->blk_size) b_top = bp + cs_addrs->hdr->blk_size; else if (SIZEOF(blk_hdr) > ((blk_hdr_ptr_t)bp)->bsiz) b_top = bp + SIZEOF(blk_hdr); else b_top = bp + ((blk_hdr_ptr_t)bp)->bsiz; patch_comp_count = 0; patch_comp_key[0] = patch_comp_key[1] = 0; for (rp = bp + SIZEOF(blk_hdr); rp < b_top ;rp = r_top, last = *pp) { GET_SHORT(rsize, &((rec_hdr_ptr_t)rp)->rsiz); if (SIZEOF(rec_hdr) > rsize) r_top = rp + SIZEOF(rec_hdr); else r_top = rp + rsize; if ((r_top > b_top) || (r_top == b_top && ((blk_hdr*)bp)->levl)) { if ((SIZEOF(rec_hdr) + SIZEOF(block_id) != (b_top - rp)) || EVAL_CMPC((rec_hdr *)rp)) return FALSE; if (dir_data_blk && !((blk_hdr_ptr_t)bp)->levl) { for (ptr = rp + SIZEOF(rec_hdr); (*ptr++ || *ptr++) && (ptr <= b_top);) ; GET_LONGP(pp, ptr); } else GET_LONGP(pp, b_top - SIZEOF(block_id)); break; } else { if ((SIZEOF(block_id) + SIZEOF(rec_hdr)) > (r_top - rp)) break; if (dir_data_blk && !((blk_hdr_ptr_t)bp)->levl) { for (ptr = rp + SIZEOF(rec_hdr); (*ptr++ || *ptr++) && (ptr <= r_top);) ; key_top = ptr; } else key_top = r_top - SIZEOF(block_id); if (EVAL_CMPC((rec_hdr_ptr_t)rp) > patch_comp_count) cc = patch_comp_count; else cc = EVAL_CMPC((rec_hdr_ptr_t)rp); size = key_top - rp - SIZEOF(rec_hdr); if ((SIZEOF(patch_comp_key) - 2 - cc) < size) size = SIZEOF(patch_comp_key) - 2 - cc; if (0 > size) size = 0; memcpy(&patch_comp_key[cc], rp + SIZEOF(rec_hdr), size); patch_comp_count = cc + size; GET_LONGP(pp, key_top); if (0 >= memvcmp(targ_key, targ_len, patch_comp_key, patch_comp_count)) break; } } *op = (int4)(rp - bp); if ((*pp == patch_find_blk) && !dir_data_blk) { patch_left_sib = last; if (r_top < b_top) { rp = r_top; GET_SHORT(rsize, &((rec_hdr_ptr_t)r_top)->rsiz); r_top = rp + rsize; if (r_top > b_top) r_top = b_top; if (SIZEOF(block_id) <= (r_top - rp)) GET_LONG(patch_right_sib, r_top - SIZEOF(block_id)); } return TRUE; } if ((*pp > 0) && (*pp < cs_addrs->ti->total_blks) && (*pp % cs_addrs->hdr->bplmap)) { if ((1 < ((blk_hdr_ptr_t)bp)->levl) && dse_order(*pp, pp + 1, op + 1, targ_key, targ_len, 0)) return TRUE; else if ((1 == ((blk_hdr_ptr_t)bp)->levl) && patch_find_root_search) return dse_order(*pp, pp + 1, op + 1, targ_key, targ_len, 1); else if ((0 == ((blk_hdr_ptr_t)bp)->levl) && patch_find_root_search) { patch_find_root_search = FALSE; return TRUE; } } patch_path_count--; return FALSE; } fis-gtm-V6.0-003/sr_port/dse_over.c0000644000032200000250000001363012201176155016007 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_iconv.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "gdscc.h" #include "cli.h" #include "filestruct.h" #include "jnl.h" #include "io.h" #include "iosp.h" #include "util.h" #include "dse.h" /* Include prototypes */ #include "t_qread.h" #include "t_write.h" #include "t_end.h" #include "t_begin_crit.h" #include "gvcst_blk_build.h" #include "ebc_xlat.h" #include "t_abort.h" #include "stringpool.h" #include "gtm_conv.h" #include "gtm_utf8.h" GBLREF char *update_array, *update_array_ptr; GBLREF gd_region *gv_cur_region; GBLREF uint4 update_array_size; GBLREF gd_addr *gd_header; GBLREF srch_hist dummy_hist; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF block_id patch_curr_blk; GBLREF gtm_chset_t dse_over_chset; #if defined(KEEP_zOS_EBCDIC) || defined(VMS) GBLREF iconv_t dse_over_cvtcd; #endif GBLREF cw_set_element cw_set[]; GBLREF UConverter *chset_desc[]; LITREF mstr chset_names[]; GBLREF spdesc stringpool; void dse_over(void) { static char *data = NULL; static int data_size; block_id blk; uchar_ptr_t lbp; uint4 offset; int data_len, size; blk_segment *bs1, *bs_ptr; int4 blk_seg_cnt, blk_size; unsigned char *cvt_src_ptr, *cvt_dst_ptr; unsigned int insize, outsize; char chset_name[MAX_CHSET_NAME]; mstr chset_mstr; unsigned short name_len = 0; srch_blk_status blkhist; mstr cvt_src; int cvt_len; error_def(ERR_DBRDONLY); error_def(ERR_DSEBLKRDFAIL); error_def(ERR_DSEFAIL); if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); CHECK_AND_RESET_UPDATE_ARRAY; /* reset update_array_ptr to update_array */ blk_size = cs_addrs->hdr->blk_size; if (cli_present("BLOCK") == CLI_PRESENT) { if (!cli_get_hex("BLOCK", (uint4 *)&blk)) return; if (blk < 0 || blk >= cs_addrs->ti->total_blks) { util_out_print("Error: invalid block number.",TRUE); return; } patch_curr_blk = blk; } else blk = patch_curr_blk; if (CLI_PRESENT == cli_present("OCHSET")) { name_len = SIZEOF(chset_name); if (cli_get_str("OCHSET", chset_name, &name_len) && 0 != name_len) { chset_name[name_len] = 0; #if defined(KEEP_zOS_EBCDIC) || defined(VMS) if ( (iconv_t)0 != dse_over_cvtcd ) { ICONV_CLOSE_CD(dse_over_cvtcd); } if (!strcmp(chset_name, INSIDE_CH_SET)) dse_over_cvtcd = (iconv_t)0; else ICONV_OPEN_CD(dse_over_cvtcd, INSIDE_CH_SET, chset_name); #else chset_mstr.addr = chset_name; chset_mstr.len = name_len; SET_ENCODING(dse_over_chset, &chset_mstr); get_chset_desc(&chset_names[dse_over_chset]); #endif } } else { #ifdef KEEP_zOS_EBCDIC if ((iconv_t)0 != dse_over_cvtcd ) { ICONV_CLOSE_CD(dse_over_cvtcd); dse_over_cvtcd = (iconv_t)0; /* default ASCII, no conversion */ } #else dse_over_chset = CHSET_M; #endif } if (cli_present("OFFSET") != CLI_PRESENT) { util_out_print("Error: offset must be specified.", TRUE); return; } if (!cli_get_hex("OFFSET", &offset)) return; if (offset < SIZEOF(blk_hdr)) { util_out_print("Error: offset too small.", TRUE); return; } if (cli_present("DATA") != CLI_PRESENT) { util_out_print("Error: data must be specified.", TRUE); return; } t_begin_crit(ERR_DSEFAIL); blkhist.blk_num = blk; if (!(blkhist.buffaddr = t_qread(blkhist.blk_num, &blkhist.cycle, &blkhist.cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); size = ((blk_hdr_ptr_t)blkhist.buffaddr)->bsiz; if (size < SIZEOF(blk_hdr)) size = SIZEOF(blk_hdr); else if (size >= blk_size) size = blk_size; if (offset >= size) { util_out_print("Error: offset too large.", TRUE); t_abort(gv_cur_region, cs_addrs); return; } if (NULL == data) { data = malloc(MAX_LINE); data_size = MAX_LINE; } if (FALSE == dse_data(&data[0], &data_len)) { t_abort(gv_cur_region, cs_addrs); return; } #if defined(KEEP_zOS_EBCDIC) || defined(VMS) cvt_src_ptr = cvt_dst_ptr = (unsigned char *)data; insize = outsize = (unsigned int)data_len; if ((iconv_t)0 != dse_over_cvtcd) ICONVERT(dse_over_cvtcd, &cvt_src_ptr, &insize, &cvt_dst_ptr, &outsize); /* in-place conversion */ #else cvt_src.len = (unsigned int)data_len; cvt_src.addr = data; if (CHSET_M != dse_over_chset) { cvt_len = gtm_conv(chset_desc[dse_over_chset], chset_desc[CHSET_UTF8], &cvt_src, NULL, NULL); if (cvt_len > data_size) { free(data); data = malloc(cvt_len); data_size = cvt_len; } memcpy(data, stringpool.free, cvt_len); data_len = cvt_len; } #endif if (offset + data_len > size) { util_out_print("Error: data will not fit in block at given offset.", TRUE); t_abort(gv_cur_region, cs_addrs); return; } lbp = (uchar_ptr_t)malloc(blk_size); memcpy (lbp, blkhist.buffaddr, blk_size); memcpy(lbp + offset, &data[0], data_len); BLK_INIT(bs_ptr, bs1); BLK_SEG(bs_ptr, (uchar_ptr_t)lbp + SIZEOF(blk_hdr), (int)((blk_hdr_ptr_t)lbp)->bsiz - SIZEOF(blk_hdr)); if (!BLK_FINI(bs_ptr, bs1)) { util_out_print("Error: bad blk build.", TRUE); free(lbp); t_abort(gv_cur_region, cs_addrs); return; } t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); return; } fis-gtm-V6.0-003/sr_port/dse_page.c0000644000032200000250000000123712201176155015750 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "util.h" #include "dse.h" void dse_page(void) { util_out_print("!^",TRUE); return; } fis-gtm-V6.0-003/sr_port/dse_puttime.h0000644000032200000250000000106212201176155016524 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __DST_PUTTIME_H__ #define __DST_PUTTIME_H__ void dse_puttime(int_ptr_t time, char *c, bool flush); #endif fis-gtm-V6.0-003/sr_port/dse_r_dmp.c0000644000032200000250000000636412201176155016143 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "cli.h" #include "dse.h" #include "util.h" #include "skan_offset.h" #include "skan_rnum.h" /* Include prototypes */ #include "t_qread.h" GBLREF block_id patch_curr_blk; GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF int patch_is_fdmp; GBLREF int patch_fdmp_recs; GBLREF int patch_rec_counter; GBLREF VSIG_ATOMIC_T util_interrupt; error_def(ERR_DSEBLKRDFAIL); error_def(ERR_CTRLC); boolean_t dse_r_dmp(void) { block_id blk; sm_uc_ptr_t bp, b_top, rp; int4 count; int4 dummy_int; cache_rec_ptr_t dummy_cr; short record, size; boolean_t was_crit, was_hold_onto_crit; int4 nocrit_present; if (cli_present("BLOCK") == CLI_PRESENT) { uint4 tmp_blk; if(!cli_get_hex("BLOCK", &tmp_blk)) return FALSE; blk = (block_id)tmp_blk; if (blk < 0 || blk >= cs_addrs->ti->total_blks || !(blk % cs_addrs->hdr->bplmap)) { util_out_print("Error: invalid block number.", TRUE); return FALSE; } patch_curr_blk = blk; } if (cli_present("COUNT") == CLI_PRESENT) { if (!cli_get_hex("COUNT", (uint4 *)&count)) return FALSE; } else count = 1; was_crit = cs_addrs->now_crit; nocrit_present = (CLI_NEGATED == cli_present("CRIT")); DSE_GRAB_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); if (!(bp = t_qread(patch_curr_blk, &dummy_int, &dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); if (((blk_hdr_ptr_t) bp)->bsiz > cs_addrs->hdr->blk_size) b_top = bp + cs_addrs->hdr->blk_size; else if (((blk_hdr_ptr_t) bp)->bsiz < SIZEOF(blk_hdr)) b_top = bp + SIZEOF(blk_hdr); else b_top = bp + ((blk_hdr_ptr_t) bp)->bsiz; if (((blk_hdr_ptr_t) bp)->levl && patch_is_fdmp) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); util_out_print("Error: cannot perform GLO/ZWR dump on index block.", TRUE); return FALSE; } if (cli_present("RECORD") == CLI_PRESENT) { if (!(rp = skan_rnum (bp, FALSE))) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); return FALSE; } } else if (!(rp = skan_offset (bp, FALSE))) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); return FALSE; } util_out_print(0, TRUE); for ( ; 0 < count; count--) { if (util_interrupt || !(rp = dump_record(rp, patch_curr_blk, bp, b_top))) break; patch_rec_counter += 1; } DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); if (util_interrupt) rts_error(VARLSTCNT(1) ERR_CTRLC); else if (cli_present("HEADER") == CLI_NEGATED) util_out_print(0, TRUE); return TRUE; } fis-gtm-V6.0-003/sr_port/dse_range.c0000644000032200000250000001524712201176155016136 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "cli.h" #include "copy.h" #include "min_max.h" #include "util.h" #include "dse.h" /* Include prototypes */ #include "t_qread.h" #define MAX_UTIL_LEN 20 GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF VSIG_ATOMIC_T util_interrupt; GBLREF block_id patch_find_blk; GBLREF block_id patch_path[MAX_BT_DEPTH + 1]; GBLREF short int patch_path_count; GBLREF bool patch_find_root_search; error_def(ERR_DSEBLKRDFAIL); error_def(ERR_CTRLC); void dse_range(void) { char lower[MAX_KEY_SZ + 1], targ_key[MAX_KEY_SZ + 1], upper[MAX_KEY_SZ + 1], util_buff[MAX_UTIL_LEN]; block_id from, to, blk, blk_child; sm_uc_ptr_t bp, b_top, key_bot, key_top, key_top1, rp, r_top; char level; int4 dummy_int, nocrit_present; cache_rec_ptr_t dummy_cr; short int rsize, size, size1; int cnt, dummy, lower_len, util_len, upper_len; boolean_t busy_matters, free, got_lonely_star, index, low, lost, star, up, was_crit, was_hold_onto_crit; if (cli_present("FROM") == CLI_PRESENT) { if (!cli_get_hex("FROM", (uint4 *)&from)) return; if (from < 0 || from > cs_addrs->ti->total_blks || !(from % cs_addrs->hdr->bplmap)) { util_out_print("Error: invalid block number.", TRUE); return; } } else from = 1; if (cli_present("TO") == CLI_PRESENT) { if(!cli_get_hex("TO", (uint4 *)&to)) return; if (to < 0 || to > cs_addrs->ti->total_blks || !(to % cs_addrs->hdr->bplmap)) { util_out_print("Error: invalid block number.", TRUE); return; } } else to = cs_addrs->ti->total_blks - 1; if (low = (cli_present("LOWER") == CLI_PRESENT)) { if (!dse_getki(&lower[0], &lower_len, LIT_AND_LEN("LOWER"))) return; } if (up = (cli_present("UPPER") == CLI_PRESENT)) { if (!dse_getki(&upper[0], &upper_len, LIT_AND_LEN("UPPER"))) return; } star = (cli_present("STAR") == CLI_PRESENT); if (!low && !up && !star) { util_out_print("Must specify star, or a lower or upper key limit.", TRUE); return; } index = (cli_present("INDEX") == CLI_PRESENT); lost = (cli_present("LOST") == CLI_PRESENT); dummy = cli_present("BUSY"); if (dummy == CLI_PRESENT) { busy_matters = TRUE; free = FALSE; } else if (dummy == CLI_NEGATED) busy_matters = free = TRUE; else busy_matters = free = FALSE; patch_path[0] = get_dir_root(); cnt = 0; was_crit = cs_addrs->now_crit; nocrit_present = (CLI_NEGATED == cli_present("CRIT")); DSE_GRAB_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); for (blk = from; blk <= to ;blk++) { if (util_interrupt) { DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); rts_error(VARLSTCNT(1) ERR_CTRLC); break; } if (!(blk % cs_addrs->hdr->bplmap)) continue; if (!(bp = t_qread(blk, &dummy_int, &dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); level = ((blk_hdr_ptr_t)bp)->levl; if (index && (level == 0)) continue; if (busy_matters && (free != dse_is_blk_free(blk, &dummy_int, &dummy_cr))) continue; if (((blk_hdr_ptr_t) bp)->bsiz > cs_addrs->hdr->blk_size) b_top = bp + cs_addrs->hdr->blk_size; else if (((blk_hdr_ptr_t) bp)->bsiz < SIZEOF(blk_hdr)) b_top = bp + SIZEOF(blk_hdr); else b_top = bp + ((blk_hdr_ptr_t) bp)->bsiz; rp = bp + SIZEOF(blk_hdr); GET_SHORT(rsize, &((rec_hdr_ptr_t) rp)->rsiz); if (rsize < SIZEOF(rec_hdr)) r_top = rp + SIZEOF(rec_hdr); else r_top = rp + rsize; if (r_top >= b_top) r_top = b_top; got_lonely_star = FALSE; if (((blk_hdr_ptr_t) bp)->levl) { key_top = r_top - SIZEOF(block_id); if (star && (r_top == b_top)) got_lonely_star = TRUE; } else { if (!up && !low) continue; for (key_top = rp + SIZEOF(rec_hdr); key_top < r_top ; ) if (!*key_top++ && !*key_top++) break; } if (!got_lonely_star) { key_bot = rp + SIZEOF(rec_hdr); size = key_top - key_bot; if (size <= 0) continue; if (size > SIZEOF(targ_key)) size = SIZEOF(targ_key); if (lost) { for (key_top1 = rp + SIZEOF(rec_hdr); key_top1 < r_top ; ) if (!*key_top1++) break; size1 = key_top1 - rp - SIZEOF(rec_hdr); if (size1 > SIZEOF(targ_key)) size1 = SIZEOF(targ_key); patch_find_root_search = TRUE; patch_path_count = 1; patch_find_blk = blk; if (dse_is_blk_in(rp, r_top, size1)) continue; } if (low && memcmp(lower, key_bot, MIN(lower_len, size)) > 0) continue; if (up && memcmp(upper, key_bot, MIN(upper_len, size)) < 0) continue; } else { got_lonely_star = FALSE; if (lost) { blk_child = *(block_id_ptr_t)key_top; if (!(bp = t_qread(blk_child, &dummy_int, &dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); if (((blk_hdr_ptr_t) bp)->bsiz > cs_addrs->hdr->blk_size) b_top = bp + cs_addrs->hdr->blk_size; else if (((blk_hdr_ptr_t) bp)->bsiz < SIZEOF(blk_hdr)) b_top = bp + SIZEOF(blk_hdr); else b_top = bp + ((blk_hdr_ptr_t) bp)->bsiz; rp = bp + SIZEOF(blk_hdr); GET_SHORT(rsize, &((rec_hdr_ptr_t) rp)->rsiz); if (rsize < SIZEOF(rec_hdr)) r_top = rp + SIZEOF(rec_hdr); else r_top = rp + rsize; if (r_top >= b_top) r_top = b_top; if (((blk_hdr_ptr_t) bp)->levl) key_top = r_top - SIZEOF(block_id); for (key_top1 = rp + SIZEOF(rec_hdr); key_top1 < r_top ; ) if (!*key_top1++) break; size1 = key_top1 - rp - SIZEOF(rec_hdr); if (size1 > 0) { if (size1 > SIZEOF(targ_key)) size1 = SIZEOF(targ_key); patch_find_root_search = TRUE; patch_path_count = 1; patch_find_blk = blk; if (dse_is_blk_in(rp, r_top, size1)) continue; } } } if (!cnt++) util_out_print("!/Blocks in the specified key range:", TRUE); util_out_print("Block: !8XL Level: !2UL", TRUE, blk, level); } DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); if (cnt) util_out_print("Found !UL blocks", TRUE, cnt); else util_out_print("None found.", TRUE); return; } fis-gtm-V6.0-003/sr_port/dse_rest.c0000644000032200000250000001214612201176155016012 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "gtm_string.h" #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "gdscc.h" #include "dse.h" #include "cli.h" #include "init_root_gv.h" #include "filestruct.h" #include "jnl.h" #include "util.h" /* Include prototypes */ #include "t_qread.h" #include "t_write.h" #include "t_end.h" #include "t_begin_crit.h" #include "gvcst_blk_build.h" #include "t_abort.h" #define MAX_UTIL_LEN 80 GBLREF char *update_array, *update_array_ptr; GBLREF uint4 update_array_size; GBLREF srch_hist dummy_hist; GBLREF gd_region *gv_cur_region; GBLREF gd_addr *gd_header; GBLREF block_id patch_curr_blk; GBLREF save_strct patch_save_set[PATCH_SAVE_SIZE]; GBLREF unsigned short int patch_save_count; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF gd_addr *original_header; GBLREF cw_set_element cw_set[]; void dse_rest(void) { block_id to, from; gd_region *region; int i, util_len; uchar_ptr_t lbp; char util_buff[MAX_UTIL_LEN], rn[MAX_RN_LEN + 1]; blk_segment *bs1, *bs_ptr; int4 blk_seg_cnt, blk_size; unsigned short rn_len; uint4 version; gd_addr *temp_gdaddr; gd_binding *map; boolean_t found; srch_blk_status blkhist; error_def(ERR_DBRDONLY); error_def(ERR_DSEBLKRDFAIL); error_def(ERR_DSEFAIL); if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); CHECK_AND_RESET_UPDATE_ARRAY; /* reset update_array_ptr to update_array */ if (cli_present("VERSION") != CLI_PRESENT) { util_out_print("Error: save version number must be specified.", TRUE); return; } if (!cli_get_int("VERSION", (int4 *)&version)) return; if (cli_present("BLOCK") == CLI_PRESENT) { if (!cli_get_hex("BLOCK", (uint4 *)&to)) return; if (to < 0 || to >= cs_addrs->ti->total_blks) { util_out_print("Error: invalid block number.", TRUE); return; } patch_curr_blk = to; } else to = patch_curr_blk; if (cli_present("FROM") == CLI_PRESENT) { if (!cli_get_hex("FROM", (uint4 *)&from)) return; if (from < 0 || from >= cs_addrs->ti->total_blks) { util_out_print("Error: invalid block number.", TRUE); return; } } else from = to; if (cli_present("REGION") == CLI_PRESENT) { rn_len = SIZEOF(rn); if (!cli_get_str("REGION", rn, &rn_len)) return; for (i = rn_len; i < MAX_RN_LEN + 1; i++) rn[i] = 0; found = FALSE; temp_gdaddr = gd_header; gd_header = original_header; for (i=0, region = gd_header->regions; i < gd_header->n_regions ;i++, region++) if (found = !memcmp(®ion->rname[0], &rn[0], MAX_RN_LEN)) break; GET_SAVED_GDADDR(gd_header, temp_gdaddr, map, gv_cur_region); if (!found) { util_out_print("Error: region not found.", TRUE); return; } if (!region->open) { util_out_print("Error: that region was not opened because it is not bound to any namespace.", TRUE); return; } } else region = gv_cur_region; found = FALSE; for (i = 0; i < patch_save_count; i++) if (patch_save_set[i].blk == from && patch_save_set[i].region == region && (found = version == patch_save_set[i].ver)) break; if (!found) { util_out_print("Error: no such version.", TRUE); return; } memcpy(util_buff, "!/Restoring block ", 18); util_len = 18; util_len += i2hex_nofill(to, (uchar_ptr_t)&util_buff[util_len], 8); memcpy(&util_buff[util_len]," from version !UL", 17); util_len += 17; util_buff[util_len] = 0; util_out_print(util_buff,FALSE,version); if (to != from) { memcpy(util_buff, " of block ", 10); util_len = 10; util_len += i2hex_nofill(from, (uchar_ptr_t)&util_buff[util_len], 8); util_buff[util_len] = 0; util_out_print(util_buff, FALSE); } if (region != gv_cur_region) util_out_print(" in region !AD", FALSE, LEN_AND_STR(rn)); util_out_print("!/",TRUE); if (to > cs_addrs->ti->total_blks) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); t_begin_crit(ERR_DSEFAIL); blk_size = cs_addrs->hdr->blk_size; blkhist.blk_num = to; if (!(blkhist.buffaddr = t_qread(blkhist.blk_num, &blkhist.cycle, &blkhist.cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); lbp = (uchar_ptr_t)patch_save_set[i].bp; BLK_INIT(bs_ptr, bs1); BLK_SEG(bs_ptr, (uchar_ptr_t)lbp + SIZEOF(blk_hdr), (int)((blk_hdr_ptr_t)lbp)->bsiz - SIZEOF(blk_hdr)); if (!BLK_FINI(bs_ptr, bs1)) { util_out_print("Error: bad blk build.", TRUE); t_abort(gv_cur_region, cs_addrs); return; } t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); return; } fis-gtm-V6.0-003/sr_port/dse_rmrec.c0000644000032200000250000001361712201176155016151 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "gdscc.h" #include "cli.h" #include "copy.h" #include "filestruct.h" #include "jnl.h" #include "util.h" #include "skan_offset.h" #include "skan_rnum.h" #include "dse.h" /* Include prototypes */ #include "t_qread.h" #include "t_write.h" #include "t_end.h" #include "t_begin_crit.h" #include "gvcst_blk_build.h" #include "t_abort.h" GBLREF char *update_array, *update_array_ptr; GBLREF uint4 update_array_size; GBLREF gd_addr *gd_header; GBLREF gd_region *gv_cur_region; GBLREF srch_hist dummy_hist; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF block_id patch_curr_blk; GBLREF char patch_comp_key[MAX_KEY_SZ + 1]; GBLREF unsigned short patch_comp_count; GBLREF cw_set_element cw_set[]; error_def(ERR_DBRDONLY); error_def(ERR_DSEBLKRDFAIL); error_def(ERR_DSEFAIL); void dse_rmrec(void) { block_id blk; blk_segment *bs1, *bs_ptr; int4 blk_seg_cnt, blk_size; int4 count; uchar_ptr_t lbp, b_top, rp, r_top, key_top, rp_base; char comp_key[MAX_KEY_SZ + 1]; unsigned short cc, cc_base; int tmp_cmpc; short int size, i, rsize; srch_blk_status blkhist; if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); CHECK_AND_RESET_UPDATE_ARRAY; /* reset update_array_ptr to update_array */ if (cli_present("BLOCK") == CLI_PRESENT) { if(!cli_get_hex("BLOCK", (uint4 *)&blk)) return; if (blk < 0 || blk >= cs_addrs->ti->total_blks || !(blk % cs_addrs->hdr->bplmap)) { util_out_print("Error: invalid block number.", TRUE); return; } patch_curr_blk = blk; } if (cli_present("COUNT") == CLI_PRESENT) { if (!cli_get_hex("COUNT", (uint4 *)&count) || count < 1) return; } else count = 1; t_begin_crit(ERR_DSEFAIL); blk_size = cs_addrs->hdr->blk_size; blkhist.blk_num = patch_curr_blk; if (!(blkhist.buffaddr = t_qread(blkhist.blk_num, &blkhist.cycle, &blkhist.cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); lbp = (uchar_ptr_t)malloc(blk_size); memcpy(lbp, blkhist.buffaddr, blk_size); if (((blk_hdr_ptr_t)lbp)->bsiz > cs_addrs->hdr->blk_size) b_top = lbp + cs_addrs->hdr->blk_size; else if (((blk_hdr_ptr_t)lbp)->bsiz < SIZEOF(blk_hdr)) b_top = lbp + SIZEOF(blk_hdr); else b_top = lbp + ((blk_hdr_ptr_t)lbp)->bsiz; if (cli_present("RECORD") == CLI_PRESENT) { if (!(rp = rp_base = skan_rnum(lbp, FALSE))) { free(lbp); t_abort(gv_cur_region, cs_addrs); return; } } else if (!(rp = rp_base = skan_offset(lbp, FALSE))) { free(lbp); t_abort(gv_cur_region, cs_addrs); return; } memcpy(&comp_key[0], &patch_comp_key[0], SIZEOF(patch_comp_key)); cc_base = patch_comp_count; for ( ; ; ) { GET_SHORT(rsize, &((rec_hdr_ptr_t)rp)->rsiz); if (rsize < SIZEOF(rec_hdr)) r_top = rp + SIZEOF(rec_hdr); else r_top = rp + rsize; if (r_top >= b_top) { if (count) { if (((blk_hdr_ptr_t) lbp)->levl) util_out_print("Warning: removed a star record from the end of this block.", TRUE); ((blk_hdr_ptr_t)lbp)->bsiz = (unsigned int)(rp_base - lbp); BLK_INIT(bs_ptr, bs1); BLK_SEG(bs_ptr, (uchar_ptr_t)lbp + SIZEOF(blk_hdr), (int)((blk_hdr_ptr_t)lbp)->bsiz - SIZEOF(blk_hdr)); if (!BLK_FINI(bs_ptr, bs1)) { util_out_print("Error: bad blk build.",TRUE); free(lbp); t_abort(gv_cur_region, cs_addrs); return; } t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); free(lbp); return; } r_top = b_top; } if (((blk_hdr_ptr_t)lbp)->levl) key_top = r_top - SIZEOF(block_id); else { for (key_top = rp + SIZEOF(rec_hdr); key_top < r_top; ) if (!*key_top++ && !*key_top++) break; } if (EVAL_CMPC((rec_hdr_ptr_t)rp) > patch_comp_count) cc = patch_comp_count; else cc = EVAL_CMPC((rec_hdr_ptr_t)rp); size = key_top - rp - SIZEOF(rec_hdr); if (size > SIZEOF(patch_comp_key) - 2 - cc) size = SIZEOF(patch_comp_key) - 2 - cc; if (size < 0) size = 0; memcpy(&patch_comp_key[cc], rp + SIZEOF(rec_hdr), size); patch_comp_count = cc + size; if (--count >= 0) { rp = r_top; continue; } size = (patch_comp_count < cc_base) ? patch_comp_count : cc_base; for (i = 0; i < size && patch_comp_key[i] == comp_key[i]; i++) ; SET_CMPC((rec_hdr_ptr_t)rp_base, i); rsize = r_top - key_top + SIZEOF(rec_hdr) + patch_comp_count - i; PUT_SHORT(&((rec_hdr_ptr_t)rp_base)->rsiz, rsize); memcpy(rp_base + SIZEOF(rec_hdr), &patch_comp_key[i], patch_comp_count - i); memmove(rp_base + SIZEOF(rec_hdr) + patch_comp_count - i, key_top, b_top - key_top); ((blk_hdr_ptr_t)lbp)->bsiz = (unsigned int)(rp_base + rsize - lbp + b_top - r_top); BLK_INIT(bs_ptr, bs1); BLK_SEG(bs_ptr, (uchar_ptr_t)lbp + SIZEOF(blk_hdr), ((blk_hdr_ptr_t)lbp)->bsiz - SIZEOF(blk_hdr)); if (!BLK_FINI(bs_ptr, bs1)) { util_out_print("Error: bad blk build.", TRUE); free(lbp); t_abort(gv_cur_region, cs_addrs); return; } t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); free(lbp); return; } } fis-gtm-V6.0-003/sr_port/dse_rmsb.c0000644000032200000250000000351112201176155015774 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "dse.h" #include "cli.h" #include "util.h" GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF block_id patch_curr_blk; GBLREF save_strct patch_save_set[PATCH_SAVE_SIZE]; GBLREF unsigned short patch_save_count; void dse_rmsb(void) { block_id blk; unsigned int i; uint4 version; bool found; if (cli_present("VERSION") != CLI_PRESENT) { util_out_print("Error: save version number must be specified.", TRUE); return; } if (!cli_get_int("VERSION", (int4 *)&version)) return; if (cli_present("BLOCK") == CLI_PRESENT) { if (!cli_get_hex("BLOCK", (uint4 *)&blk)) return; if (blk < 0 || blk >= cs_addrs->ti->total_blks || !(blk % cs_addrs->hdr->bplmap)) { util_out_print("Error: invalid block number.", TRUE); return; } patch_curr_blk = blk; } found = FALSE; for (i = 0; i < patch_save_count; i++) if (patch_save_set[i].blk == patch_curr_blk && patch_save_set[i].region == gv_cur_region &&(found = version == patch_save_set[i].ver)) break; if (!found) { util_out_print("Error: no such version.", TRUE); return; } patch_save_count--; free(patch_save_set[i].bp); memcpy(&patch_save_set[i], &patch_save_set[i + 1], (patch_save_count - i) * SIZEOF(save_strct)); return; } fis-gtm-V6.0-003/sr_port/dse_save.c0000644000032200000250000001131112201176155015764 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "gtm_string.h" #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "dse.h" #include "cli.h" #include "util.h" /* Include prototypes */ #include "t_qread.h" #define MAX_UTIL_LEN 80 GBLDEF save_strct patch_save_set[PATCH_SAVE_SIZE]; GBLDEF unsigned short patch_save_count = 0; GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF block_id patch_curr_blk; error_def(ERR_DSEBLKRDFAIL); void dse_save(void) { block_id blk; unsigned i, j, util_len; unsigned short buff_len; boolean_t was_block, was_crit, was_hold_onto_crit; char buff[100], *ptr, util_buff[MAX_UTIL_LEN]; sm_uc_ptr_t bp; int4 dummy_int, nocrit_present; cache_rec_ptr_t dummy_cr; memset(util_buff, 0, MAX_UTIL_LEN); if (was_block = (cli_present("BLOCK") == CLI_PRESENT)) { if (!cli_get_hex("BLOCK", (uint4 *)&blk)) return; if (blk < 0 || blk >= cs_addrs->ti->total_blks) { util_out_print("Error: invalid block number.", TRUE); return; } patch_curr_blk = blk; } else blk = patch_curr_blk; if (cli_present("LIST") == CLI_PRESENT) { if (was_block) { util_len = SIZEOF("!/Saved versions of block "); memcpy(util_buff, "!/Saved versions of block ", util_len); util_len += i2hex_nofill(blk, (uchar_ptr_t)&util_buff[util_len-1], 8); util_buff[util_len-1] = 0; util_out_print(util_buff, TRUE); for (i = j = 0; i < patch_save_count; i++) if (patch_save_set[i].blk == blk) { j++; if (*patch_save_set[i].comment) util_out_print("Version !UL Region !AD Comment: !AD!/", TRUE, patch_save_set[i].ver, REG_LEN_STR(patch_save_set[i].region), LEN_AND_STR(patch_save_set[i].comment)); else util_out_print("Version !UL Region !AD!/", TRUE, patch_save_set[i].ver, REG_LEN_STR(patch_save_set[i].region)); } if (!j) util_out_print("None.!/", TRUE); return; } util_out_print("!/Save history:!/", TRUE); for (i = j = 0; i < patch_save_count; i++) { util_len = SIZEOF("Block "); memcpy(util_buff, "Block ", util_len); util_len += i2hex_nofill(patch_save_set[i].blk, (uchar_ptr_t)&util_buff[util_len-1], 8); util_buff[util_len-1] = 0; util_out_print(util_buff, TRUE); j++; if (*patch_save_set[i].comment) { util_out_print("Version !UL Region !AD Comment: !AD!/", TRUE, patch_save_set[i].ver, REG_LEN_STR(patch_save_set[i].region), LEN_AND_STR(patch_save_set[i].comment)); } else { util_out_print("Version !UL Region !AD!/", TRUE, patch_save_set[i].ver, REG_LEN_STR(patch_save_set[i].region)); } } if (!j) util_out_print(" None.!/", TRUE); return; } j = 1; for (i = 0; i < patch_save_count; i++) if (patch_save_set[i].blk == blk && patch_save_set[i].region == gv_cur_region && patch_save_set[i].ver >= j) j = patch_save_set[i].ver + 1; util_len = SIZEOF("!/Saving version !UL of block "); memcpy(util_buff, "!/Saving version !UL of block ", util_len); util_len += i2hex_nofill(blk, (uchar_ptr_t)&util_buff[util_len-1], 8); util_buff[util_len-1] = 0; util_out_print(util_buff, TRUE, j); patch_save_set[patch_save_count].ver = j; patch_save_set[patch_save_count].blk = blk; patch_save_set[patch_save_count].region = gv_cur_region; patch_save_set[patch_save_count].bp = (char *)malloc(cs_addrs->hdr->blk_size); if (blk >= cs_addrs->ti->total_blks) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); was_crit = cs_addrs->now_crit; nocrit_present = (CLI_NEGATED == cli_present("CRIT")); DSE_GRAB_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); if (!(bp = t_qread(blk, &dummy_int, &dummy_cr))) rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); memcpy(patch_save_set[patch_save_count].bp, bp, cs_addrs->hdr->blk_size); DSE_REL_CRIT_AS_APPROPRIATE(was_crit, was_hold_onto_crit, nocrit_present, cs_addrs, gv_cur_region); buff_len = SIZEOF(buff); if ((cli_present("COMMENT") == CLI_PRESENT) && cli_get_str("COMMENT", buff, &buff_len)) { ptr = &buff[buff_len]; *ptr = 0; j = (unsigned int)(ptr - &buff[0] + 1); patch_save_set[patch_save_count].comment = (char *)malloc(j); memcpy(patch_save_set[patch_save_count].comment, &buff[0], j); } else patch_save_set[patch_save_count].comment = ""; patch_save_count++; return; } fis-gtm-V6.0-003/sr_port/dse_shift.c0000644000032200000250000001045312201176155016151 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "gdscc.h" #include "dse.h" #include "cli.h" #include "filestruct.h" #include "jnl.h" #include "util.h" /* Include prototypes */ #include "t_qread.h" #include "t_write.h" #include "t_end.h" #include "t_begin_crit.h" #include "gvcst_blk_build.h" #include "t_abort.h" GBLREF char *update_array, *update_array_ptr; GBLREF gd_region *gv_cur_region; GBLREF uint4 update_array_size; GBLREF srch_hist dummy_hist; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF gd_addr *gd_header; GBLREF block_id patch_curr_blk; GBLREF cw_set_element cw_set[]; void dse_shift(void) { bool forward; uint4 offset, shift; int4 size; sm_uc_ptr_t bp; uchar_ptr_t lbp; blk_segment *bs1, *bs_ptr; int4 blk_seg_cnt, blk_size; srch_blk_status blkhist; error_def(ERR_DBRDONLY); error_def(ERR_DSEBLKRDFAIL); error_def(ERR_DSEFAIL); if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); CHECK_AND_RESET_UPDATE_ARRAY; /* reset update_array_ptr to update_array */ if (patch_curr_blk < 0 || patch_curr_blk >= cs_addrs->ti->total_blks || !(patch_curr_blk % cs_addrs->hdr->bplmap)) { util_out_print("Error: invalid block number.", TRUE); return; } if (cli_present("OFFSET") != CLI_PRESENT) { util_out_print("Error: offset must be specified.", TRUE); return; } if (!cli_get_hex("OFFSET", &offset)) return; shift = 0; if (cli_present("FORWARD") == CLI_PRESENT) { if (!cli_get_hex("FORWARD", &shift)) return; forward = TRUE; lbp = (unsigned char *)malloc((size_t)shift); } else if (cli_present("BACKWARD") == CLI_PRESENT) { if (!cli_get_hex("BACKWARD", &shift)) return; if (shift > offset) { util_out_print("Error: shift greater than offset not allowed.", TRUE); return; } forward = FALSE; lbp = (unsigned char *)0; } if (!shift) { util_out_print("Error: must specify amount to shift.", TRUE); if (lbp) free(lbp); return; } blk_size = cs_addrs->hdr->blk_size; t_begin_crit(ERR_DSEFAIL); blkhist.blk_num = patch_curr_blk; if (!(blkhist.buffaddr = t_qread(blkhist.blk_num, &blkhist.cycle, &blkhist.cr))) { if (lbp) free(lbp); rts_error(VARLSTCNT(1) ERR_DSEBLKRDFAIL); } bp = blkhist.buffaddr; size = ((blk_hdr *)bp)->bsiz; if (size < 0) size = 0; else if (size > cs_addrs->hdr->blk_size) size = cs_addrs->hdr->blk_size; if (offset < SIZEOF(blk_hdr) || offset > size) { util_out_print("Error: offset not in range of block.", TRUE); t_abort(gv_cur_region, cs_addrs); if (lbp) free(lbp); return; } BLK_INIT(bs_ptr, bs1); if (forward) { if (shift + size >= cs_addrs->hdr->blk_size) { util_out_print("Error: block not large enough to accomodate shift.", TRUE); t_abort(gv_cur_region, cs_addrs); if (lbp) free(lbp); return; } memset(lbp, 0, shift); BLK_SEG(bs_ptr, bp + SIZEOF(blk_hdr), offset - SIZEOF(blk_hdr)); BLK_SEG(bs_ptr, lbp, shift); if (size - offset) BLK_SEG(bs_ptr, bp + offset, size - offset); } else { if (shift > offset) shift = offset - SIZEOF(blk_hdr); if (offset - shift > SIZEOF(blk_hdr)) BLK_SEG(bs_ptr, bp + SIZEOF(blk_hdr), offset - shift - SIZEOF(blk_hdr)); if (size - offset) BLK_SEG(bs_ptr, bp + offset, size - offset); } if (!BLK_FINI(bs_ptr, bs1)) { util_out_print("Error: bad blk build.", TRUE); t_abort(gv_cur_region, cs_addrs); if (lbp) free(lbp); return; } t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)bp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN); BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn); t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED); return; } fis-gtm-V6.0-003/sr_port/dse_wcreinit.c0000644000032200000250000000322412201176155016656 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "cli.h" #include "dse.h" #ifdef UNIX # include "gtm_stdio.h" #endif GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF short crash_count; error_def(ERR_DBRDONLY); error_def(ERR_DSEINVLCLUSFN); error_def(ERR_DSEONLYBGMM); error_def(ERR_DSEWCINITCON); void dse_wcreinit (void) { unsigned char *c; uint4 large_block; boolean_t was_crit; # ifdef UNIX char *fgets_res; # endif if (gv_cur_region->read_only) rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); if (cs_addrs->hdr->clustered) { rts_error(VARLSTCNT(1) ERR_DSEINVLCLUSFN); return; } if (cs_addrs->critical) crash_count = cs_addrs->critical->crashcnt; GET_CONFIRM_AND_HANDLE_NEG_RESPONSE if (cs_addrs->hdr->acc_meth != dba_bg && cs_addrs->hdr->acc_meth != dba_mm) { rts_error(VARLSTCNT(4) ERR_DSEONLYBGMM, 2, LEN_AND_LIT("WCINIT")); return; } was_crit = cs_addrs->now_crit; if (!was_crit) grab_crit(gv_cur_region); DSE_WCREINIT(cs_addrs); if (!was_crit) rel_crit (gv_cur_region); return; } fis-gtm-V6.0-003/sr_port/dsefind.h0000644000032200000250000000132312201176155015616 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ typedef struct global_dir_path_struct { block_id block; int4 offset; struct global_dir_path_struct *next; }global_dir_path; typedef struct global_root_list_struct { block_id root; global_dir_path *dir_path; struct global_root_list_struct *link; }global_root_list; fis-gtm-V6.0-003/sr_port/dsewrap.mpt0000644000032200000250000002650012201176155016224 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2012, 2013 Fidelity Information Services, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %DSEWRAP %dsewrap ; Wrappers for DSE to avoid inadvertently making database changes set $ETRAP="do errtrap^%DSEWRAP" set $ecode=",U255," ; must call an entryref quit:$quit 255 quit ; in case error trap does not end the call DUMP(r,o,w,d) ; upper case wrapper for dump new tmp set tmp=$$dump(r,.o,w,d) quit:$quit tmp quit dump(reglist,output,what,detail) ; dump information ; reglist - comma separated list of regions, "*" (default) for all regions ; output - required variable passed by reference where output is returned ; what - optional information to dump - "fileheader" (default) is only option for now ; detail - optional default is basic information, "all" is full fileheader dump ; install an error handler if non exists if 0=$length($ETRAP) new $ETRAP set $ETRAP="do errtrap^%DSEWRAP" new cmd,dse,debug,error,gtmdist,i,io,isVMS,line,mod,nopipe,region,ver ; save previous $IO to restore once the routine has completed set io=$io if $data(%DSEWRAP("debug")) do . set debug=$increment(%DSEWRAP("debug")) . set debug(debug,"input","reglist")=$get(reglist) . set debug(debug,"input","what")=$get(what) . set debug(debug,"input","detail")=$get(detail) ; ; Determine if we can use PIPES or not AND where to find DSE set ver=$tr($piece($zversion," ",2),"V-.",""),ver=$select(ver<1000:ver*10,1:$extract(ver,1,5)) set isVMS=$zversion["VMS" set nopipe=((ver<53003)&($get(%DSEWRAP("forcenopipe"),0)))!isVMS,mod=$select(isVMS:"/",1:"-") set gtmdist=$select(isVMS:"gtm$dist",1:"gtm_dist") ; ; Applicable regions list set reglist=$$reglist($$FUNC^%UCASE($get(reglist,"*")),isVMS) ; What operation? for now, should be just "dump -fileheader [-all]" if (0=$length($get(what)))!("fileheader"=$$FUNC^%LCASE($get(what))) set what=mod_"fileheader" else set $ecode=",U254," quit:$quit 254 quit if 0=$length($get(detail)) set detail="" else if "all"=$$FUNC^%LCASE(detail) set detail=mod_"all" else if $length(detail," ")>1 do . set detail=$$^%MPIECE(detail," "," ") . for i=1:1:$length(detail," ") if $piece(detail," ",i)'?1(1"/",1"-").A set $piece(detail," ",i)=mod_$piece(detail," ",i) set cmd="dump "_what_" "_detail ; Use alternate GT.M version - only supported with pipes if nopipe&$data(%DSEWRAP("alternate")) set $ecode=",U252," quit:$quit 252 quit ; DSE command to use set dse=$get(%DSEWRAP("alternate"),$ztrnlnm(gtmdist)_"/dse") if $data(debug) merge debug(debug,"outputreg")=reglist if reglist="" set $ecode=",U251," quit:$quit 251 quit ; Drive DSE if 0=nopipe set error=$$dsepipecmd(.output,reglist,dse,cmd) else set error=$$dsefilecmd(.output,reglist,cmd,isVMS) use io if $data(%DSEWRAP("debug")) merge %DSEWRAP("debug")=debug quit:$quit error quit ; drive DSE through a PIPE device dsepipecmd(output,regionlist,dse,cmd) new error,curreg open "dseproc":(shell="/bin/sh":command=dse)::"pipe" use "dseproc" for curreg=2:1:$length(regionlist,",") do . set region=$piece(regionlist,",",curreg) . if ($length(region)=0)&($data(debug)) set debug(debug,"reg",curreg)="first"_$c(10) . if $length(region)>0 do ; should be 0 only when curreg=2 . . write region,! if $data(debug) set debug(debug,"reg",curreg)=region_$c(10) . . set error=$$parsefhead(.output,1) . write cmd,! if $data(debug) set debug(debug,"reg",curreg)=$get(debug(debug,"reg",curreg))_cmd . set error=$$parsefhead(.output,1) write "exit",! write /eof set error=$$parsefhead(.output,1) close "dseproc" quit error ; when PIPE devices are not supported drive DSE via a HEREDOC in a script dsefilecmd(output,regionlist,cmd,isVMS) new scriptfile,dsecmd,dumpfile,error,i,hdr,ftr,line,ts set ts="_"_$tr($horolog,",","_") set scriptfile=$select(isVMS:"dsedump"_ts_".com",1:"dsedump"_ts_".sh") set dsecmd=$select(isVMS:"@",1:"chmod 755 "_scriptfile_"; ./")_scriptfile set dumpfile="dsedump.txt" open scriptfile:newversion use scriptfile ; print the header set hdr=$select(isVMS:"dsecomhdr",1:"dseshhdr") for i=1:1 set line=$text(@hdr+i) quit:line["quit" write $piece(line,";",2),! ; print the dump commands per region for curreg=2:1:$length(regionlist,",") do . set region=$piece(regionlist,",",curreg) . if $length(region)>0 write region,! ; should be 0 only when curreg=2 . write cmd,! ; print the footer set ftr=$select(isVMS:"dsecomftr",1:"dseshftr") for i=1:1 set line=$text(@ftr+i) quit:line["quit" write $piece(line,";",2),! ; close and execute the script file close scriptfile zsystem dsecmd ; read script output and rename the file open dumpfile:readonly use dumpfile set error=$$parsefhead(.output) close dumpfile:(rename=dumpfile_ts) ; if no error occurred and debug is UNDEF, delete the script file if (0=error)&(0=$data(debug)) open scriptfile:readonly close scriptfile:delete quit error ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; generate the applicable region list ; the output string is a comma separated list of "FIND -REGION=" and ; not a list of regions. The first piece is always null as a null string ; indicates that the script could find no applicable regions. The second piece ; could be null. If so, that piece represents the first region in which DSE ; starts up reglist(reglist,isVMS) ; reglist - comma separated list of regions ; isVMS - use '/' (vms) or '-' (unix) for the modifier ; determine GT.CM regions, '::' (vms) vs ':' (unix) new reg,regavail,i,mod,gtcmKey,regpath set mod=$select(isVMS:"/",1:"-") set gtcmKey=$select(isVMS:"::",1:":") ; determine the applicable regions - reglist vs actual available regions set reglist=$select($get(reglist)="":"*",reglist="ALL":"*",1:reglist) set regavail="" if "*"'=reglist for i=1:1:$length(reglist,",") do . set reg=$piece(reglist,",",i) set regavail(reg)=1 ; define the region kill reg for i=1:1 set reg=$view("gvnext",$get(reg)) quit:reg="" do . set regpath=$VIEW("GVFILE",reg) . quit:(1<$length(regpath,gtcmKey)) . if ("*"=reglist)!($data(regavail(reg))) do . . set $piece(regavail,",",$length(regavail,",")+1)=$select(i>1:"find "_mod_"region="_reg,1:"") quit regavail ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; parsefhead(output,active) new error,debug,fcnt,field,file,i,line,parsed,region,value set error=0 if $data(%DSEWRAP("debug")) set debug=$increment(%DSEWRAP("debug")) if $length($etrap)=0 set $etrap="use $p zshow ""*"" halt" ; for i=1:1 read line(i):5 quit:error quit:$zeof quit:$select($data(active)=0:0,line(i)["DSE>":1,1:0) do . if ($test=0)&($length(line(i))=0) write ! . set line=$tr($$FUNC^%TRIM(line(i)),$c(10,13),"") . quit:($length(line)=0) . if line["%GTM-E-" set error=1 if $data(%DSEWRAP("debug")) set debug(debug,"error")=line . if line?1"DSE>".E kill region,file quit ; DSE prompt means reset header information . quit:line["Error: already in region: " ; ignore already in region error . if line?1"File"1." ".E set fcnt=$length(line," "),file=$piece(line," ",fcnt) quit . if line?1"Region"1." ".E do quit . . set fcnt=$length(line," "),region=$piece(line," ",fcnt) . . if $data(parsed(region,"File")) kill parsed(region) ; DUPLICATE, throw it away . . set parsed(region,"File")=file . quit:$data(region)=0 . if line?1"Date/Time".E set parsed(region,"Date/Time")=$$FUNC^%TRIM($extract(line,10,$length(line))) quit . ;;; Match stats like output "DRD : #" . else if line?3(1U,1N)1" : #".E do . . set field=$$FUNC^%TRIM($piece(line,"0x",1)),value="0x"_$piece(line,"0x",2) . . do addfield(.parsed,region,field,value) . ;;; Match lines with " : (0x[0-9A0Z]*| (TRUE|FALSE))" in them . else if $length(line," : ")>1 do . . set field=$$FUNC^%TRIM($piece(line," : ",1)),value=$tr($piece(line," : ",2)," ","") . . do addfield(.parsed,region,field,value) . ;;; Match all column oriented data . else do . . ;;;; Adjust for the varying column width - the order matters . . if $extract(line,44,45)=" " set $extract(line,44,45)="|" ; dump -all : Snapshot information . . else if $extract(line,35,42)=" " set $extract(line,35,42)="|" ; dump -all : all after "Full Block Write.*" . . else if $extract(line,42,43)=" " set $extract(line,42,43)="|" ; dump . . new columns,col,data,lastfield,lastpiece . . set columns=$length(line,"|") . . ;;;; Handle the column data . . for col=1:1:columns do . . . set data=$$FUNC^%TRIM($piece(line,"|",col)) ; trim because of "Snapshot in progress" . . . set lastpiece=$length(data," ") . . . ;;;;;; Special case - value is a compound statement like "[WAS_ON] OFF" . . . if (data["State")&(data["[") set lastpiece=$length(data," ")-1 . . . ; value is separated by the last space . . . set value=$piece(data," ",lastpiece,$length(data," ")) . . . ; take everything but the value and trim off extra spaces . . . set field=$$FUNC^%TRIM($extract(data,1,($length(data)-$length(value)))) . . . ;;;;;; Special case - fields where value may not exist . . . if (data?1"Snapshot file name")!(data?1(1"Journal",1"Temp")1" File:") set value="",field=data . . . ;;;;;; Special case - paired records like those with "Transaction =" . . . if field="Transaction =" set field=lastfield_" TN" ; handle paired records . . . if $data(%DSEWRAP("debug")) set debug(debug,i,field)=value . . . do addfield(.parsed,region,field,value) . . . set lastfield=field merge output=parsed if $data(%DSEWRAP("debug")) do . merge %DSEWRAP("debug",debug,"line")=line . set debug(debug,"pipe0ZOEF")=$zeof,debug(debug,"pipe0DEVICE")=$device,debug(debug,"pipe0ZA")=$ZA . merge %DSEWRAP("debug")=debug quit:$quit error quit addfield(var,region,field,value) if $data(var(region,field))\10 set var(region,field,$increment(var(region,field)))=value else if $data(var(region,field)) do . set var(region,field,1)=var(region,field),var(region,field)=2,var(region,field,2)=value else set var(region,field)=value quit ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; errtrap use $p set $etrap="use $principal write $zstatus,! zhalt 1" set userecode=$piece($ecode,",",2) set errtext=$select(userecode?1"U"3N:$text(@userecode),1:"") if $length(errtext) write $text(+0),@$piece(errtext,";",2),! else write $zstatus,! if $zlevel<5 zhalt +$extract(userecode,2,$length(userecode)) quit ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Scripts to drive DSE via ZSystem dsecomhdr ;$ define sys$output dsedump.txt ;$ define sys$error dsedump.txt ;$ purge /nolog dsedump.txt ;$ $gtm$dist:dse.exe quit dsecomftr ;$ deassign sys$output ;$ deassign sys$error quit dseshhdr ;#!/bin/sh ;$gtm_dist/dse > dsedump.txt 2>&1 << EOF quit dseshftr ;EOF quit ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Error message texts U251 ;"-F-NOREGIONS none of the target regions exist" U252 ;"-F-NOPIPENOALTERNATE GT.M "_$zversion_" does not support pipes and cannot drive a different version of GT.M" U253 ;"-F-ILLEGALDETAIL """_detail_""" is not a valid specification of details to dump" U254 ;"-F-ILLEGALSELECTION """_what_""" is not a valid selection of what to dump" U255 ;"-F-BADINVOCATION Must invoke as DO DUMP^"_$text(+0)_"(...)" fis-gtm-V6.0-003/sr_port/dump_lockhist.c0000644000032200000250000000372612201176155017053 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "filestruct.h" #include "gtmio.h" #include "have_crit.h" GBLREF gd_region *gv_cur_region; GBLREF int process_id; /* Routine to dump the lock history array on demand starting with most recent and working backwards */ void dump_lockhist(void) { #ifdef DEBUG /* should only be called conditional on DEBUG, but play it safe */ int4 lockIdx, lockIdx_first; node_local_ptr_t locknl; locknl = FILE_INFO(gv_cur_region)->s_addrs.nl; FPRINTF(stderr, "\nProcess lock history (in reverse order) -- Current pid: %d\n", process_id); /* Print headers */ FPRINTF(stderr, "Func LockAddr Caller Pid Retry TrIdx\n"); FPRINTF(stderr, "----------------------------------------------------------\n"); for (lockIdx_first = lockIdx = locknl->lockhist_idx; ;) { if (NULL != locknl->lockhists[lockIdx].lock_addr) { FPRINTF(stderr, "%.4s %16lx %16lx %6d %6d %d\n", locknl->lockhists[lockIdx].lock_op, locknl->lockhists[lockIdx].lock_addr, locknl->lockhists[lockIdx].lock_callr, locknl->lockhists[lockIdx].lock_pid, locknl->lockhists[lockIdx].loop_cnt, lockIdx); } if (--lockIdx < 0) /* If we have fallen off the short end.. */ lockIdx = LOCKHIST_ARRAY_SIZE - 1; /* .. move to the tall end */ if (lockIdx == lockIdx_first) break; /* Completed the loop */ } FPRINTF(stderr,"\0"); FFLUSH(stderr); #endif } fis-gtm-V6.0-003/sr_port/dump_record.c0000644000032200000250000002020312201176176016501 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include #include "gtmctype.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "cli.h" #include "copy.h" #include "min_max.h" /* needed for init_root_gv.h */ #include "init_root_gv.h" #include "util.h" #include "dse.h" #include "print_target.h" #include "op.h" #ifdef GTM_TRIGGER #include "hashtab_mname.h" #include /* needed for gv_trigger.h */ #include "gv_trigger.h" /* needed for INIT_ROOT_GVT */ #include "targ_alloc.h" #endif #ifdef UNICODE_SUPPORTED #include "gtm_icu_api.h" #include "gtm_utf8.h" #endif GBLDEF bool wide_out; GBLDEF char patch_comp_key[MAX_KEY_SZ + 1]; GBLDEF unsigned short patch_comp_count; GBLDEF int patch_rec_counter; GBLREF sgmnt_addrs *cs_addrs; GBLREF VSIG_ATOMIC_T util_interrupt; GBLREF mval curr_gbl_root; GBLREF int patch_is_fdmp; GBLREF int patch_fdmp_recs; GBLREF gv_key *gv_currkey; GBLREF gv_namehead *gv_target; LITREF mval literal_hasht; #define MAX_UTIL_LEN 80 #define NUM_BYTES_PER_LINE 20 sm_uc_ptr_t dump_record(sm_uc_ptr_t rp, block_id blk, sm_uc_ptr_t bp, sm_uc_ptr_t b_top) { sm_uc_ptr_t r_top, key_top, cptr0, cptr1, cptr_top, cptr_base = NULL, cptr_next = NULL; char key_buf[MAX_KEY_SZ + 1], *temp_ptr, *temp_key, util_buff[MAX_UTIL_LEN]; char *prefix_str, *space_str, *dot_str, *format_str; unsigned short cc; int tmp_cmpc; unsigned short size; int4 util_len, head; uint4 ch; int buf_len, field_width,fastate, chwidth = 0; ssize_t chlen; block_id blk_id; boolean_t rechdr_displayed = FALSE; sgmnt_addrs *csa; if (rp >= b_top) return NULL; head = cli_present("HEADER"); GET_SHORT(size, &((rec_hdr_ptr_t)rp)->rsiz); cc = EVAL_CMPC((rec_hdr_ptr_t)rp); if ((CLI_NEGATED != head) && !patch_is_fdmp) { MEMCPY_LIT(util_buff, "Rec:"); util_len = SIZEOF("Rec:") - 1; util_len += i2hex_nofill(patch_rec_counter, (uchar_ptr_t)&util_buff[util_len], 4); MEMCPY_LIT(&util_buff[util_len], " Blk "); util_len += SIZEOF(" Blk ") - 1; util_len += i2hex_nofill(blk, (uchar_ptr_t)&util_buff[util_len], 8); MEMCPY_LIT(&util_buff[util_len], " Off "); util_len += SIZEOF(" Off ") - 1; util_len += i2hex_nofill((int)(rp - bp), (uchar_ptr_t)&util_buff[util_len], 4); MEMCPY_LIT(&util_buff[util_len], " Size "); util_len += SIZEOF(" Size ") - 1; util_len += i2hex_nofill(size, (uchar_ptr_t)&util_buff[util_len], 4); MEMCPY_LIT(&util_buff[util_len], " Cmpc "); util_len += SIZEOF(" Cmpc ") - 1; util_len += i2hex_nofill(cc, (uchar_ptr_t)&util_buff[util_len], 3); MEMCPY_LIT(&util_buff[util_len], " "); util_len += SIZEOF(" ") - 1; util_buff[util_len] = 0; util_out_print(util_buff, FALSE); } r_top = rp + size; if (r_top > b_top) r_top = b_top; else if (r_top < rp + SIZEOF(rec_hdr)) r_top = rp + SIZEOF(rec_hdr); if (cc > patch_comp_count) cc = patch_comp_count; if (((blk_hdr_ptr_t)bp)->levl) key_top = r_top - SIZEOF(block_id); else { for (key_top = rp + SIZEOF(rec_hdr); key_top < r_top;) if (!*key_top++ && !*key_top++) break; } size = key_top - rp - SIZEOF(rec_hdr); if (size > SIZEOF(patch_comp_key) - 2 - cc) size = SIZEOF(patch_comp_key) - 2 - cc; memcpy(&patch_comp_key[cc], rp + SIZEOF(rec_hdr), size); patch_comp_count = cc + size; patch_comp_key[patch_comp_count] = patch_comp_key[patch_comp_count + 1] = 0; if (patch_is_fdmp) { if (dse_fdmp(key_top, (int)(r_top - key_top))) patch_fdmp_recs++; } else { if (r_top - SIZEOF(block_id) >= key_top) { GET_LONG(blk_id, key_top); if ((((blk_hdr_ptr_t)bp)->levl) || (blk_id <= cs_addrs->ti->total_blks)) { MEMCPY_LIT(util_buff, "Ptr "); util_len = SIZEOF("Ptr ") - 1; util_len += i2hex_nofill(blk_id, (uchar_ptr_t)&util_buff[util_len], SIZEOF(blk_id) * 2); MEMCPY_LIT(&util_buff[util_len], " "); util_len += SIZEOF(" ") - 1; util_buff[util_len] = 0; util_out_print(util_buff, FALSE); } } util_out_print("Key ", FALSE); if (r_top == b_top && ((blk_hdr_ptr_t)bp)->levl && !EVAL_CMPC((rec_hdr_ptr_t)rp) && r_top - rp == SIZEOF(rec_hdr) + SIZEOF(block_id)) util_out_print("*", FALSE); else if (patch_comp_key[0]) { util_out_print("^", FALSE); csa = cs_addrs; RETRIEVE_ROOT_VAL(patch_comp_key, key_buf, temp_ptr, temp_key, buf_len); INIT_ROOT_GVT(key_buf, buf_len, curr_gbl_root); } print_target((uchar_ptr_t)patch_comp_key); util_out_print(0, TRUE); if (CLI_PRESENT != head) { prefix_str = " |"; if (wide_out) { format_str = " !AD"; dot_str = " ."; space_str = " "; field_width = 4; } else { format_str = " !AD"; dot_str = " ."; space_str = " "; field_width = 3; } fastate = 0; for (cptr0 = rp; cptr0 < r_top; cptr0 += NUM_BYTES_PER_LINE) { if (util_interrupt) { /* return, rather than signal ERR_CTRLC so that the calling routine can deal with that signal and do the appropriate cleanup */ return NULL; } util_len = 8; i2hex_blkfill((int)(cptr0 - bp), (uchar_ptr_t)util_buff, 8); MEMCPY_LIT(&util_buff[util_len], " : |"); util_len += SIZEOF(" : |") - 1; util_buff[util_len] = 0; util_out_print(util_buff, FALSE); /* Dump hexadecimal byte values */ for (cptr1 = cptr0; cptr1 < (cptr0 + NUM_BYTES_PER_LINE); cptr1++) { if (cptr1 < r_top) { i2hex_blkfill(*(sm_uc_ptr_t)cptr1, (uchar_ptr_t)util_buff, field_width); util_buff[field_width] = 0; util_out_print(util_buff, FALSE); } else util_out_print(space_str, FALSE); } util_out_print("|", TRUE); util_out_print(prefix_str, FALSE); /* Display character/wide-character glyphs */ for (cptr1 = cptr0, cptr_top = cptr0 + NUM_BYTES_PER_LINE; cptr1 < cptr_top; cptr1++) { if (!rechdr_displayed && (cptr1 == (rp + SIZEOF(rec_hdr)))) rechdr_displayed = TRUE; assert(rechdr_displayed || (cptr1 < (rp + SIZEOF(rec_hdr)))); assert(!rechdr_displayed || (cptr1 >= (rp + SIZEOF(rec_hdr)))); switch (fastate) { case 0: /* prints single-byte characters or intepret multi-byte characters */ if (cptr1 >= r_top) util_out_print(space_str, FALSE); else if (!gtm_utf8_mode || IS_ASCII(*cptr1) || !rechdr_displayed) { /* single-byte characters */ if (PRINTABLE(*(sm_uc_ptr_t)cptr1)) util_out_print(format_str, FALSE, 1, cptr1); else util_out_print(dot_str, FALSE); } #ifdef UNICODE_SUPPORTED else { /* multi-byte characters */ cptr_next = UTF8_MBTOWC(cptr1, r_top, ch); chlen = cptr_next - cptr1; if (WEOF == ch || !U_ISPRINT(ch)) { /* illegal or non-printable characters */ cptr1--; fastate = 1; } else { /* multi-byte printable characters */ cptr_base = cptr1; chwidth = UTF8_WCWIDTH(ch); assert(chwidth >= 0 && chwidth <= 2); cptr1--; fastate = 2; } } #endif break; case 1: /* illegal or non-printable characters */ util_out_print(dot_str, FALSE); if (--chlen <= 0) fastate = 0; break; case 2: /* printable multi-byte characters */ if (chlen-- > 1) /* fill leading bytes with spaces */ util_out_print(space_str, FALSE); else { util_out_print("!AD", FALSE, field_width - chwidth, space_str); if (0 < chwidth) util_out_print("!AD", FALSE, cptr_next - cptr_base, cptr_base); fastate = 0; } break; } } util_out_print("|", TRUE); } } if (CLI_NEGATED != head) util_out_print(0, TRUE); } return (r_top == b_top) ? NULL : r_top; } fis-gtm-V6.0-003/sr_port/dumptable.c0000644000032200000250000000257112201176155016160 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "compiler.h" #include "list_file.h" #include "dumptable.h" static readonly char argtype[][6] = { "","TVAR ","TVAL ","TINT ","TVAD " ,"TCAD ","VREG ","MLIT ","MVAR " ,"TRIP ","TNXT ","TJMP ","INDR " ,"MLAB ","ILIT ","CDLT ","TEMP " }; static readonly char start8[] = " stored at r8 + "; static readonly char start9[] = " stored at r9 + "; GBLREF int4 sa_temps[]; GBLREF int4 sa_temps_offset[]; void dumptable(void) { char outbuf[256]; int i; unsigned char *c; for (i=1; i <= TCAD_REF ; i++) { c = (unsigned char *)&outbuf[0]; memcpy(c,argtype[i],5); c += 5; *c++ = ' '; c = i2asc(c,sa_temps[i]); if (i == TVAR_REF) { memcpy(c, &start8[0], SIZEOF(start8) - 1); c += SIZEOF(start8) - 1; } else { memcpy(c, &start9[0], SIZEOF(start9) - 1); c += SIZEOF(start9) - 1; } c = i2asc(c,sa_temps_offset[i]); *c++ = 0; list_tab(); list_line(outbuf); } } fis-gtm-V6.0-003/sr_port/dumptable.h0000644000032200000250000000110412201176155016154 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef DUMPTABLE_INCLUDED #define DUMPTABLE_INCLUDED void dumptable(void); /***type int added***/ #endif /* DUMPTABLE_INCLUDED */ fis-gtm-V6.0-003/sr_port/eb_muldiv.c0000644000032200000250000001642112201176155016150 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* eb_muldiv - emulate extended precision (18-digit) multiplication and division */ #include "mdef.h" #include "arit.h" #include "eb_muldiv.h" #define FLO_HI 1e9 #define FLO_LO 1e8 #define FLO_BIAS 1e3 #define DFLOAT2MINT(X,DF) (X[1] = DF, X[0] = (DF - (double)X[1])*FLO_HI) #define RADIX 10000 /* eb_int_mul - multiply two GT.M INT's * * input * v1, u1 - GT.M INT's * * output * if the product will fit into a GT.M INT format: * function result = FALSE => no promotion necessary * p[] = INT product of (v1*m1) * else (implies overflow out of INT format): * function result = TRUE => promotion to extended precision necessary * p[] = undefined */ bool eb_int_mul (int4 v1, int4 u1, int4 p[]) { double pf; int4 tp[2], promote; promote = TRUE; /* promote if overflow or too many significant fractional digits */ pf = (double)u1*(double)v1/FLO_BIAS; if ((pf < FLO_HI) && (pf > -FLO_HI)) { DFLOAT2MINT(tp, pf); if (tp[0] == 0) /* don't need extra precision */ { promote = FALSE; p[0] = tp[0]; p[1] = tp[1]; } } return promote; } /* eb_mul - multiply two GT.M extended precision numeric values * * input * v[], u[] - GT.M extended precision numeric value mantissas * * output * function result = scale factor of result * p[] = GT.M extended precision mantissa of (u*v) */ int4 eb_mul (int4 v[], int4 u[], int4 p[]) /* p = u*v */ { short i, j; int4 acc, carry, m1[5], m2[5], prod[9], scale; /* Throughout, larger index => more significance. */ for (i = 0 ; i < 9 ; i++) prod[i] = 0; /* Break up 2-4-(3/1)-4-4 */ m1[0] = v[0] % RADIX; m2[0] = u[0] % RADIX; m1[1] = (v[0]/RADIX) % RADIX; m2[1] = (u[0]/RADIX) % RADIX; m1[2] = (v[1] % (RADIX/10))*10 + v[0]/(RADIX*RADIX); m2[2] = (u[1] % (RADIX/10))*10 + u[0]/(RADIX*RADIX); m1[3] = (v[1]/(RADIX/10)) % RADIX; m2[3] = (u[1]/(RADIX/10)) % RADIX; m1[4] = v[1]/((RADIX/10)*RADIX); m2[4] = u[1]/((RADIX/10)*RADIX); for (j = 0 ; j <= 4 ; j++) { if (m2[j] != 0) { for (i = 0, carry = 0 ; i <= 4 ; i++) { acc = m1[i]*m2[j] + prod[i+j] + carry; prod[i+j] = acc % RADIX; carry = acc / RADIX; } if ( 9 > i+j) prod[i+j] = carry; else if (0 != carry) assert(FALSE); } } if (prod[8] >= RADIX/10) { /* Assemble back 4-4-1/3-4-2 */ scale = 0; /* no scaling needed */ p[0] = ((prod[6]%1000)*RADIX + prod[5])*(RADIX/ 100) + (prod[4]/ 100); p[1] = ( prod[8] *RADIX + prod[7])*(RADIX/1000) + (prod[6]/1000); } else /* prod[8] < RADIX/10 [means not normalized] */ { /* Assemble back 3-4-2/2-4-3 */ scale = -1; /* to compensate for normalization */ p[0] = ((prod[6]%100)*RADIX + prod[5])*(RADIX/ 10) + (prod[4]/ 10); p[1] = ( prod[8] *RADIX + prod[7])*(RADIX/100) + (prod[6]/100); } return scale; } /* eb_mvint_div - divide to GT.M INT's * * input * v, u - INT's to be divided * * output * if the quotient will fit into a GT.M INT: * function value = FALSE => no promotion necessary * q[] = INT quotient of (v/u) * else (implies overflow out of GT.M INT forat): * function value = TRUE => promotion to extended precision necessary * q[] = undefined */ bool eb_mvint_div (int4 v, int4 u, int4 q[]) { double qf; int4 tq[2], promote; promote = TRUE; /* promote if overflow or too many significant fractional digits */ qf = (double)v*FLO_BIAS/(double)u; if ((qf < FLO_HI) && (qf > -FLO_HI)) { DFLOAT2MINT(tq, qf); if (tq[0] == 0) /* don't need extra word of precision */ { promote = FALSE; q[0] = tq[0]; q[1] = tq[1]; } } return promote; } /* eb_int_div - integer division of two GT.M INT's * * input * v1, u1 - GT.M INT's to be divided * * output * if result fits into a GT.M INT: * function value = FALSE => no promotion necessary * q[] = INT result of (v1\u1) * else (implies some sort of overflow): * function result = TRUE => promotion to extended precision necessary * q[] = undefined */ bool eb_int_div (int4 v1, int4 u1, int4 q[]) { double qf; qf= (double)v1*FLO_BIAS/(double)u1; if (qf < FLO_HI && qf > -FLO_HI) { DFLOAT2MINT(q,qf); q[1]= (q[1]/MV_BIAS)*MV_BIAS; return FALSE; } else { return TRUE; } } /* eb_div - divide two GT.M extended precision numeric values * * input * x[], y[] - GT.M extended precision numeric value mantissas * * output * function result = scale factor of result * q[] = GT.M extended precision mantissa of (y/x) */ int4 eb_div (int4 x[], int4 y[], int4 q[]) /* q = y/x */ { int4 borrow, carry, i, j, scale, prod, qx[5], xx[5], yx[10]; for (i = 0 ; i < 5 ; i++) yx[i] = 0; if (x[1] < y[1] || (x[1] == y[1] && x[0] <= y[0])) /* i.e., if x <= y */ { /* Break y apart 3-4-2/2-4-3 */ scale = 1; yx[5] = (y[0]%(RADIX/10))*10; yx[6] = (y[0]/(RADIX/10))%RADIX; yx[7] = (y[1]%(RADIX/100))*(RADIX/100) + y[0]/((RADIX/10)*RADIX); yx[8] = (y[1]/(RADIX/100))%RADIX; yx[9] = y[1]/((RADIX/100)*RADIX); } else { /* Break y apart 4-4-1/3-4-2 */ scale = 0; yx[5] = (y[0]%(RADIX/100))*100; yx[6] = (y[0]/(RADIX/100))%RADIX; yx[7] = (y[1]%(RADIX/1000))*(RADIX/10) + y[0]/((RADIX/100)*RADIX); yx[8] = (y[1]/(RADIX/1000))%RADIX; yx[9] = y[1]/((RADIX/1000)*RADIX); } /* Break x apart 4-4-1/3-4-2 */ xx[0] = (x[0]%(RADIX/100))*100; xx[1] = (x[0]/(RADIX/100))%RADIX; xx[2] = (x[1]%(RADIX/1000))*(RADIX/10) + x[0]/((RADIX/100)*RADIX); xx[3] = (x[1]/(RADIX/1000))%RADIX; xx[4] = x[1]/((RADIX/1000)*RADIX); assert (yx[9] <= xx[4]); for (i = 4 ; i >= 0 ; i--) { qx[i] = (yx[i+5]*RADIX + yx[i+4]) / xx[4]; if (qx[i] != 0) { /* Multiply x by qx[i] and subtract from remainder. */ for (j = 0, borrow = 0 ; j <= 4 ; j++) { prod = qx[i]*xx[j] + borrow; borrow = prod/RADIX; yx[i+j] -= (prod%RADIX); if (yx[i+j] < 0) { yx[i+j] += RADIX; borrow ++; } } yx[i+5] -= borrow; while (yx[i+5] < 0) { qx[i] --; /* estimate too high */ for (j = 0, carry = 0 ; j <= 4 ; j++) { yx[i+j] += (xx[j] + carry); carry = yx[i+j]/RADIX; yx[i+j] %= RADIX; } yx[i+5] += carry; } } assert (0 <= qx[i] && qx[i] < RADIX); /* make sure in range */ assert (yx[i+5] == 0); /* check that remainder doesn't overflow */ } /* Assemble q 4-4-1/3-4-2 */ q[0] = ((qx[2]%1000)*RADIX + qx[1])*100 + (qx[0]/ 100); q[1] = ( qx[4] *RADIX + qx[3])* 10 + (qx[2]/1000); assert ( (FLO_LO <= q[1] && q[1] < FLO_HI) || (q[1] == 0 && q[0] == 0 && y[1] == 0 && y[0] == 0) ); return scale; } /* eb_int_mod - INT modulus of two GT.M INT's * * input * v1, u1 - GT.M INT's * * output * p[] = INT value of (v1 mod u1) == (v1 - (u1*floor(v1/u1))) */ void eb_int_mod (int4 v1, int4 u1, int4 p[]) { int4 quo, rat, neg; if (u1 == 0 || v1 == 0) { p[1]= 0; } else { quo = v1/u1; rat = v1 != quo*u1; neg = (v1 < 0 && u1 > 0) || (v1 > 0 && u1 < 0); p[1] = v1 - u1*(quo - (neg && rat)); } return; } fis-gtm-V6.0-003/sr_port/eb_muldiv.h0000644000032200000250000000144312201176155016153 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __EB_MULDIV_H__ #define __EB_MULDIV_H__ bool eb_int_mul (int4 v1, int4 u1, int4 p[]); int4 eb_mul (int4 v[], int4 u[], int4 p[]); /* p = u*v */ bool eb_mvint_div (int4 v, int4 u, int4 q[]); bool eb_int_div (int4 v1, int4 u1, int4 q[]); int4 eb_div (int4 x[], int4 y[], int4 q[]); /* q = y/x */ void eb_int_mod (int4 v1, int4 u1, int4 p[]); #endif fis-gtm-V6.0-003/sr_port/ebc_xlat.c0000644000032200000250000001276312201176155015770 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2003 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /**************************************************************** * * * This module provides translation functions between the * * ASCII and EBCDIC code sets. * * * ****************************************************************/ #include "mdef.h" #include "ebc_xlat.h" /* Translation tables */ /* These were generated using iconv between "ISO8859-1" (ASCII) */ /* and "IBM-1047" (EBCDIC)); */ /* EBCDIC to ASCII */ LITDEF unsigned char e2a[256] = { /* 00 - 07: */ 0x0, 0x1, 0x2, 0x3, 0x9c, 0x9, 0x86, 0x7f, /* 08 - 0f: */ 0x97, 0x8d, 0x8e, 0xb, 0xc, 0xd, 0xe, 0xf, /* 10 - 17: */ 0x10, 0x11, 0x12, 0x13, 0x9d, 0xa, 0x8, 0x87, /* 18 - 1f: */ 0x18, 0x19, 0x92, 0x8f, 0x1c, 0x1d, 0x1e, 0x1f, /* 20 - 27: */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x17, 0x1b, /* 28 - 2f: */ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x5, 0x6, 0x7, /* 30 - 37: */ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x4, /* 38 - 3f: */ 0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a, /* 40 - 47: */ 0x20, 0xa0, 0xe2, 0xe4, 0xe0, 0xe1, 0xe3, 0xe5, /* 48 - 4f: */ 0xe7, 0xf1, 0xa2, 0x2e, 0x3c, 0x28, 0x2b, 0x7c, /* 50 - 57: */ 0x26, 0xe9, 0xea, 0xeb, 0xe8, 0xed, 0xee, 0xef, /* 58 - 5f: */ 0xec, 0xdf, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x5e, /* 60 - 67: */ 0x2d, 0x2f, 0xc2, 0xc4, 0xc0, 0xc1, 0xc3, 0xc5, /* 68 - 6f: */ 0xc7, 0xd1, 0xa6, 0x2c, 0x25, 0x5f, 0x3e, 0x3f, /* 70 - 77: */ 0xf8, 0xc9, 0xca, 0xcb, 0xc8, 0xcd, 0xce, 0xcf, /* 78 - 7f: */ 0xcc, 0x60, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22, /* 80 - 87: */ 0xd8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 88 - 8f: */ 0x68, 0x69, 0xab, 0xbb, 0xf0, 0xfd, 0xfe, 0xb1, /* 90 - 97: */ 0xb0, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, /* 98 - 9f: */ 0x71, 0x72, 0xaa, 0xba, 0xe6, 0xb8, 0xc6, 0xa4, /* a0 - a7: */ 0xb5, 0x7e, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, /* a8 - af: */ 0x79, 0x7a, 0xa1, 0xbf, 0xd0, 0x5b, 0xde, 0xae, /* b0 - b7: */ 0xac, 0xa3, 0xa5, 0xb7, 0xa9, 0xa7, 0xb6, 0xbc, /* b8 - bf: */ 0xbd, 0xbe, 0xdd, 0xa8, 0xaf, 0x5d, 0xb4, 0xd7, /* c0 - c7: */ 0x7b, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* c8 - cf: */ 0x48, 0x49, 0xad, 0xf4, 0xf6, 0xf2, 0xf3, 0xf5, /* d0 - d7: */ 0x7d, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, /* d8 - df: */ 0x51, 0x52, 0xb9, 0xfb, 0xfc, 0xf9, 0xfa, 0xff, /* e0 - e7: */ 0x5c, 0xf7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, /* e8 - ef: */ 0x59, 0x5a, 0xb2, 0xd4, 0xd6, 0xd2, 0xd3, 0xd5, /* f0 - f7: */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* f8 - ff: */ 0x38, 0x39, 0xb3, 0xdb, 0xdc, 0xd9, 0xda, 0x9f }; /* ASCII to EBCDIC */ LITDEF unsigned char a2e[256] = { /* 00 - 07: */ 0x0, 0x1, 0x2, 0x3, 0x37, 0x2d, 0x2e, 0x2f, /* 08 - 0f: */ 0x16, 0x5, 0x15, 0xb, 0xc, 0xd, 0xe, 0xf, /* 10 - 17: */ 0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, /* 18 - 1f: */ 0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f, /* 20 - 27: */ 0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, /* 28 - 2f: */ 0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61, /* 30 - 37: */ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 38 - 3f: */ 0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f, /* 40 - 47: */ 0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 48 - 4f: */ 0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, /* 50 - 57: */ 0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, /* 58 - 5f: */ 0xe7, 0xe8, 0xe9, 0xad, 0xe0, 0xbd, 0x5f, 0x6d, /* 60 - 67: */ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 68 - 6f: */ 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, /* 70 - 77: */ 0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, /* 78 - 7f: */ 0xa7, 0xa8, 0xa9, 0xc0, 0x4f, 0xd0, 0xa1, 0x7, /* 80 - 87: */ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x6, 0x17, /* 88 - 8f: */ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x9, 0xa, 0x1b, /* 90 - 97: */ 0x30, 0x31, 0x1a, 0x33, 0x34, 0x35, 0x36, 0x8, /* 98 - 9f: */ 0x38, 0x39, 0x3a, 0x3b, 0x4, 0x14, 0x3e, 0xff, /* a0 - a7: */ 0x41, 0xaa, 0x4a, 0xb1, 0x9f, 0xb2, 0x6a, 0xb5, /* a8 - af: */ 0xbb, 0xb4, 0x9a, 0x8a, 0xb0, 0xca, 0xaf, 0xbc, /* b0 - b7: */ 0x90, 0x8f, 0xea, 0xfa, 0xbe, 0xa0, 0xb6, 0xb3, /* b8 - bf: */ 0x9d, 0xda, 0x9b, 0x8b, 0xb7, 0xb8, 0xb9, 0xab, /* c0 - c7: */ 0x64, 0x65, 0x62, 0x66, 0x63, 0x67, 0x9e, 0x68, /* c8 - cf: */ 0x74, 0x71, 0x72, 0x73, 0x78, 0x75, 0x76, 0x77, /* d0 - d7: */ 0xac, 0x69, 0xed, 0xee, 0xeb, 0xef, 0xec, 0xbf, /* d8 - df: */ 0x80, 0xfd, 0xfe, 0xfb, 0xfc, 0xba, 0xae, 0x59, /* e0 - e7: */ 0x44, 0x45, 0x42, 0x46, 0x43, 0x47, 0x9c, 0x48, /* e8 - ef: */ 0x54, 0x51, 0x52, 0x53, 0x58, 0x55, 0x56, 0x57, /* f0 - f7: */ 0x8c, 0x49, 0xcd, 0xce, 0xcb, 0xcf, 0xcc, 0xe1, /* f8 - ff: */ 0x70, 0xdd, 0xde, 0xdb, 0xdc, 0x8d, 0x8e, 0xdf }; void asc_to_ebc(unsigned char *estring_out, unsigned char *astring_in, int len) { int i; unsigned char *in_ptr, *out_ptr; for (i = 0, in_ptr = astring_in, out_ptr = estring_out; i < len; i++, in_ptr++, out_ptr++) *out_ptr = a2e[*in_ptr]; } void ebc_to_asc(unsigned char *astring_out, unsigned char *estring_in, int len) { int i; unsigned char *in_ptr, *out_ptr; for (i = 0, in_ptr = estring_in, out_ptr = astring_out; i < len; i++, in_ptr++, out_ptr++) *out_ptr = e2a[*in_ptr]; } fis-gtm-V6.0-003/sr_port/ebc_xlat.h0000644000032200000250000000122612201176155015765 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __EBC_XLAT_H__ #define __EBC_XLAT_H__ void asc_to_ebc(unsigned char *estring_out, unsigned char *astring_in, int len); void ebc_to_asc(unsigned char *astring_out, unsigned char *estring_in, int len); #endif fis-gtm-V6.0-003/sr_port/ecode_add.c0000644000032200000250000001726312201176176016101 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" /* for memcpy() */ #include "min_max.h" /* for MIN macro */ #include /* for stack_frame.h */ #include "stack_frame.h" /* for stack_frame type */ #include "error_trap.h" #include "get_command_line.h" /* for get_command_line() prototype */ #include "dollar_zlevel.h" /* for dollar_zlevel() prototype */ GBLREF dollar_ecode_type dollar_ecode; /* structure containing $ECODE related information */ GBLREF dollar_stack_type dollar_stack; /* structure containing $STACK related information */ GBLREF stack_frame *error_frame; /* "frame_pointer" at the time of adding the current ECODE */ GBLREF stack_frame *frame_pointer; #define INCR_ECODE_INDEX(ecode_index, str, strlen) \ { \ memcpy(dollar_ecode.end, str, strlen); \ dollar_ecode.array[ecode_index].ecode_str.addr = dollar_ecode.end; \ dollar_ecode.array[ecode_index].ecode_str.len = strlen; \ /* -1 below for not calculating the terminating ',' as part of this ECODE, \ * but instead calculate that as part of the beginning of the next ECODE */ \ dollar_ecode.end += strlen - 1; \ ecode_index++; \ } #define DECR_ECODE_INDEX(ecode_index) \ { \ ecode_index--; \ space_left += dollar_ecode.array[ecode_index].ecode_str.len - 1; \ } /* returns TRUE if able to fit in string held by tmpmval into dollar_stack * returns FALSE otherwise */ static boolean_t fill_dollar_stack_info(mval *mvalptr, mstr *mstrptr) { ssize_t space_left; if (mvalptr->str.len) { space_left = dollar_stack.top - dollar_stack.end; if (mvalptr->str.len > space_left) { dollar_stack.incomplete = TRUE; /* we stop storing $STACK(level) info once we reach a frame level * that can't be fitted in the available space */ return FALSE; } memcpy(dollar_stack.end, mvalptr->str.addr, mvalptr->str.len); mstrptr->addr = dollar_stack.end; mstrptr->len = mvalptr->str.len; dollar_stack.end += mstrptr->len; assert(dollar_stack.end <= dollar_stack.top); } else mstrptr->len = 0; return TRUE; } /* returns TRUE if able to fit in one $STACK(level,...) of information in global variable structure "dollar_stack". * returns FALSE otherwise */ static boolean_t fill_dollar_stack_level(int array_level, int frame_level, int cur_zlevel) { mstr *mstrptr; mval tmpmval; dollar_stack_struct *dstack; assert(FALSE == dollar_stack.incomplete); /* we should not have come here if previous $STACK levels were incomplete */ dstack = &dollar_stack.array[array_level]; /* fill in $STACK(level) */ if (frame_level) get_frame_creation_info(frame_level, cur_zlevel, &tmpmval); else get_command_line(&tmpmval, FALSE); /* FALSE to indicate we want actual (not processed) command line */ /* note that tmpmval at this point will most likely point to the stringpool. but we rely on stp_gcol to free it up */ mstrptr = &dstack->mode_str; if (FALSE == fill_dollar_stack_info(&tmpmval, mstrptr)) return FALSE; /* fill in $STACK(level,"ECODE") */ dstack->ecode_ptr = (frame_level == (cur_zlevel - 1)) ? &dollar_ecode.array[dollar_ecode.index - 1] : NULL; /* fill in $STACK(level,"PLACE") */ get_frame_place_mcode(frame_level, DOLLAR_STACK_PLACE, cur_zlevel, &tmpmval); mstrptr = &dstack->place_str; if (FALSE == fill_dollar_stack_info(&tmpmval, mstrptr)) return FALSE; /* fill in $STACK(level,"MCODE") */ get_frame_place_mcode(frame_level, DOLLAR_STACK_MCODE, cur_zlevel, &tmpmval); mstrptr = &dstack->mcode_str; if (FALSE == fill_dollar_stack_info(&tmpmval, mstrptr)) return FALSE; return TRUE; } boolean_t ecode_add(mstr *str) /* add "str" to $ECODE and return whether SUCCESS or FAILURE as TRUE/FALSE */ { int ecode_index, stack_index; boolean_t shrink; int cur_zlevel, level; char eclostmid_buf[MAX_DIGITS_IN_INT + STR_LIT_LEN(",Z,")], *dest; ssize_t space_left, eclostmid_len; error_def(ERR_ECLOSTMID); dest = &eclostmid_buf[0]; *dest++ = ','; *dest++ = 'Z'; dest = (char *)i2asc((unsigned char *)dest, ERR_ECLOSTMID); *dest++ = ','; eclostmid_len = dest - &eclostmid_buf[0]; assert(SIZEOF(eclostmid_buf) >= eclostmid_len); assert(str->len < DOLLAR_ECODE_ALLOC); space_left = dollar_ecode.top - dollar_ecode.end; ecode_index = dollar_ecode.index; shrink = FALSE; if (space_left < str->len) { shrink = TRUE; assert(1 == shrink); /* since we need a value of 1 (instead of any non-zero) for usage below */ space_left -= eclostmid_len - 1;/* note : space_left can become negative but code below handles that */ } if (ecode_index >= (DOLLAR_ECODE_MAXINDEX - shrink)) { assert(DOLLAR_ECODE_MAXINDEX >= ecode_index); if (DOLLAR_ECODE_MAXINDEX == ecode_index) { DECR_ECODE_INDEX(ecode_index); shrink = TRUE; } if (shrink) { DECR_ECODE_INDEX(ecode_index); assert((DOLLAR_ECODE_MAXINDEX - 2) == ecode_index); } } assert(ecode_index < DOLLAR_ECODE_MAXINDEX); for ( ; space_left < (int)str->len; ) /* note explicit typecasting to make sure it is a signed comparison */ { ecode_index--; if (1 > ecode_index) /* if ecode_index == -1 ==> str->len > DOLLAR_ECODE_ALLOC so nothing can be done in PRO */ return FALSE; /* if ecode_index == 0 ==> first ECODE needs to be overlaid. we do not want to do that. */ space_left += dollar_ecode.array[ecode_index].ecode_str.len - 1; } for (stack_index = 0; stack_index < dollar_stack.index; stack_index++) { if (dollar_stack.array[stack_index].ecode_ptr > &dollar_ecode.array[ecode_index]) return FALSE; /* do not want to overlay any ECODE that $STACK(level,"ECODE") is pointing to */ } assert(0 <= ecode_index); if (dollar_ecode.index != ecode_index) { dollar_ecode.end = dollar_ecode.array[ecode_index].ecode_str.addr; dollar_ecode.index = ecode_index; } if (shrink) { INCR_ECODE_INDEX(dollar_ecode.index, &eclostmid_buf[0], (mstr_len_t)eclostmid_len); } INCR_ECODE_INDEX(dollar_ecode.index, str->addr, str->len); if ((1 == dollar_ecode.index) || ((!dollar_stack.incomplete) && (2 == dollar_ecode.index) && (dollar_ecode.first_ecode_error_frame == error_frame))) { /* need to fill in $STACK entries if either the first ECODE or if an error in the first ECODE error-handler. * do not fill in nested error $STACK info if the first ECODE's $STACK info itself was incompletely filled in */ if (1 == dollar_ecode.index) { /* first ECODE. note down error_frame info in "first_ecode_error_frame" as well as $STACK(level) info */ dollar_ecode.first_ecode_error_frame = frame_pointer; assert(0 == dollar_stack.index); } cur_zlevel = dollar_zlevel(); assert(dollar_stack.index <= cur_zlevel); for (level = dollar_stack.index; level < MIN(cur_zlevel, DOLLAR_STACK_MAXINDEX); ) { /* we do not store $STACK(level) info for levels > 256 */ if (fill_dollar_stack_level(level, level, cur_zlevel)) level++; /* update array_level only if we had enough space to fill in all of above */ else break; } if ((2 == dollar_ecode.index) && (cur_zlevel == dollar_stack.index) && (DOLLAR_STACK_MAXINDEX > cur_zlevel)) { /* if nested error occurred at the same frame_level as the first error, * store $STACK information for the nested error in $STACK(frame_level+1) */ assert(level == dollar_stack.index); if (fill_dollar_stack_level(level, cur_zlevel - 1, cur_zlevel)) level++; } dollar_stack.index = level; } return TRUE; } fis-gtm-V6.0-003/sr_port/ecode_get.c0000644000032200000250000000215612201176155016120 0ustar librarygtc/**************************************************************** * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "stringpool.h" #include "error_trap.h" GBLREF dollar_ecode_type dollar_ecode; /* structure containing $ECODE related information */ void ecode_get(int level, mval *val) { mstr tmpmstr; val->mvtype = MV_STR; assert(-1 == level); /* currently -1 is the only valid negative level argument to ecode_get() */ if (dollar_ecode.index) { assert(dollar_ecode.end > dollar_ecode.begin); val->str.addr = dollar_ecode.begin; val->str.len = INTCAST(dollar_ecode.end - dollar_ecode.begin + 1); /* to account for terminating ',' */ s2pool(&val->str); } else { assert(dollar_ecode.end == dollar_ecode.begin); val->str.len = 0; } } fis-gtm-V6.0-003/sr_port/ecode_init.c0000644000032200000250000000347212201176176016311 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "stack_frame.h" #include "error.h" /* for ERROR_RTN */ #include "error_trap.h" GBLREF dollar_ecode_type dollar_ecode; /* structure containing $ECODE related information */ GBLREF dollar_stack_type dollar_stack; /* structure containing $STACK related information */ /* NOTE: every malloc'd storage here should be free'd in a nested call-in environment. * gtmci_isv_restore (in gtmci_isv.c) needs to be reflected for any future mallocs added here. */ void ecode_init(void) { dollar_ecode.begin = (char *)malloc(DOLLAR_ECODE_ALLOC); dollar_ecode.top = dollar_ecode.begin + DOLLAR_ECODE_ALLOC; dollar_ecode.array = (dollar_ecode_struct *)malloc(SIZEOF(dollar_ecode_struct) * DOLLAR_ECODE_MAXINDEX); dollar_ecode.error_rtn_addr = NON_IA64_ONLY(CODE_ADDRESS(ERROR_RTN)) IA64_ONLY(CODE_ADDRESS_C(ERROR_RTN)); dollar_ecode.error_rtn_ctxt = GTM_CONTEXT(ERROR_RTN); dollar_ecode.error_return_addr = (error_ret_fnptr)ERROR_RETURN; dollar_stack.begin = (char *)malloc(DOLLAR_STACK_ALLOC); dollar_stack.top = dollar_stack.begin + DOLLAR_STACK_ALLOC; dollar_stack.array = (dollar_stack_struct *)malloc(SIZEOF(dollar_stack_struct) * DOLLAR_STACK_MAXINDEX); NULLIFY_DOLLAR_ECODE; /* this macro resets dollar_ecode.{end,index}, dollar_stack.{begin,index,incomplete} and * first_ecode_error_frame to point as if no error occurred at all */ } fis-gtm-V6.0-003/sr_port/ecode_set.c0000644000032200000250000000560012201176155016131 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "error.h" #include "error_trap.h" #include "merrors_ansi.h" /* ECODE_MAX_LEN is the maximum length of the string representation of "errnum"'s ECODE. * This is arrived at as follows : ",M,Z,". Each number can be at most MAX_NUM_SIZE. * The three ","s and the letters "M" and "Z" add up to 5 characters. * In addition we give a buffer for overflow in the production version (just in case). */ #define BUFFER_FOR_OVERFLOW 15 /* give some buffer in case overflow happens in PRO */ #define ECODE_MAX_LEN ((2 * MAX_DIGITS_IN_INT) + STR_LIT_LEN(",M,Z,")) #define ECODE_MAX_LEN_WITH_BUFFER ((ECODE_MAX_LEN) + (BUFFER_FOR_OVERFLOW)) error_def(ERR_SETECODE); void ecode_set(int errnum) { mval tmpmval; const err_ctl *ectl; mstr ecode_mstr; char ecode_buff[ECODE_MAX_LEN_WITH_BUFFER]; char *ecode_ptr; int ansi_error; int severity; /* If this routine was called with error code SETECODE, * an end-user just put a correct value into $ECODE, * and it shouldn't be replaced by this routine. */ if (ERR_SETECODE == errnum) return; /* When the value of $ECODE is non-empty, error trapping is invoked. When the severity level does not warrant * error trapping, no value should be copied into $ECODE. Note: the message is verified it IS a GTM message before * checking the severity code so system error numbers aren't misinterpreted. */ severity = errnum & SEV_MSK; if ((NULL != err_check(errnum)) && ((INFO == severity) || (SUCCESS == severity))) return; /* Get ECODE string from error-number. If the error has an ANSI standard code, return ,Mnnn, (nnn is ANSI code). * Always return ,Zxxx, (xxx is GT.M code). Note that the value of $ECODE must start and end with a comma */ ecode_ptr = &ecode_buff[0]; *ecode_ptr++ = ','; if (ectl = err_check(errnum)) { ansi_error = ((errnum & FACMASK(ectl->facnum)) && (MSGMASK(errnum, ectl->facnum) <= ectl->msg_cnt)) ? error_ansi[MSGMASK(errnum, ectl->facnum) - 1] : 0; if (0 < ansi_error) { *ecode_ptr++ = 'M'; ecode_ptr = (char *)i2asc((unsigned char *)ecode_ptr, ansi_error); *ecode_ptr++ = ','; } } *ecode_ptr++ = 'Z'; ecode_ptr = (char *)i2asc((unsigned char *)ecode_ptr, errnum); *ecode_ptr++ = ','; ecode_mstr.addr = &ecode_buff[0]; ecode_mstr.len = INTCAST(ecode_ptr - ecode_mstr.addr); assert(ecode_mstr.len <= ECODE_MAX_LEN); assertpro(ECODE_MAX_LEN_WITH_BUFFER >= ecode_mstr.len); ecode_add(&ecode_mstr); } fis-gtm-V6.0-003/sr_port/eintr_wrappers.h0000644000032200000250000001574512201176155017263 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* Define macros to do system calls and restart as appropriate * * FCNTL, FCNTL3 Loop until fcntl call succeeds or fails with other than EINTR. * TCFLUSH Loop until tcflush call succeeds or fails with other than EINTR. * Tcsetattr Loop until tcsetattr call succeeds or fails with other than EINTR. */ #ifndef EINTR_WRP_Included #define EINTR_WRP_Included #include #include #include "have_crit.h" #include "gt_timer.h" #if defined(DEBUG) && defined(UNIX) #include "io.h" #include "gtm_stdio.h" #include "wcs_sleep.h" #include "deferred_signal_handler.h" #include "wbox_test_init.h" #endif #define ACCEPT_SOCKET(SOCKET, ADDR, LEN, RC) \ { \ do \ { \ RC = ACCEPT(SOCKET, ADDR, LEN); \ } while(-1 == RC && EINTR == errno); \ } #define CHG_OWNER(PATH, OWNER, GRP, RC) \ { \ do \ { \ RC = CHOWN(PATH, OWNER, GRP); \ } while(-1 == RC && EINTR == errno); \ } #define CLOSEDIR(DIR, RC) \ { \ do \ { \ RC = closedir(DIR); \ } while(-1 == RC && EINTR == errno); \ } #define CONNECT_SOCKET(SOCKET, ADDR, LEN, RC) \ { \ do \ { \ RC = CONNECT(SOCKET, ADDR, LEN); \ } while(-1 == RC && EINTR == errno); \ } #define CREATE_FILE(PATHNAME, MODE, RC) \ { \ do \ { \ RC = CREAT(PATHNAME, MODE); \ } while(-1 == RC && EINTR == errno); \ } #define DOREAD_A_NOINT(FD, BUF, SIZE, RC) \ { \ do \ { \ RC = DOREAD_A(FD, BUF, SIZE); \ } while(-1 == RC && EINTR == errno); \ } #define DUP2(FDESC1, FDESC2, RC) \ { \ do \ { \ RC = dup2(FDESC1, FDESC2); \ } while(-1 == RC && EINTR == errno); \ } #define FCLOSE(STREAM, RC) \ { \ do \ { \ RC = fclose(STREAM); \ } while(-1 == RC && EINTR == errno); \ } #define FCNTL2(FDESC, ACTION, RC) \ { \ do \ { \ RC = fcntl(FDESC, ACTION); \ } while(-1 == RC && EINTR == errno); \ } #define FCNTL3(FDESC, ACTION, ARG, RC) \ { \ do \ { \ RC = fcntl(FDESC, ACTION, ARG); \ } while(-1 == RC && EINTR == errno); \ } #define FGETS_FILE(BUF, LEN, FP, RC) \ { \ do \ { \ FGETS(BUF, LEN, FP, RC); \ } while(NULL == RC && !feof(FP) && ferror(FP) && EINTR == errno); \ } #define FSTAT_FILE(FDESC, INFO, RC) \ { \ do \ { \ DEFER_INTERRUPTS(INTRPT_IN_FSTAT); \ RC = fstat(FDESC, INFO); \ ENABLE_INTERRUPTS(INTRPT_IN_FSTAT); \ } while(-1 == RC && EINTR == errno); \ } #define FSTATVFS_FILE(FDESC, FSINFO, RC) \ { \ do \ { \ FSTATVFS(FDESC, FSINFO, RC); \ } while(-1 == RC && EINTR == errno); \ } #define FTRUNCATE(FDESC, LENGTH, RC) \ { \ do \ { \ RC = ftruncate(FDESC, LENGTH); \ } while(-1 == RC && EINTR == errno); \ } #define MSGSND(MSGID, MSGP, MSGSZ, FLG, RC) \ { \ do \ { \ RC = msgsnd(MSGID, MSGP, MSGSZ, FLG); \ } while(-1 == RC && EINTR == errno); \ } #define OPEN_PIPE(FDESC, RC) \ { \ do \ { \ RC = pipe(FDESC); \ } while(-1 == RC && EINTR == errno); \ } #define READ_FILE(FD, BUF, SIZE, RC) \ { \ do \ { \ RC = read(FD, BUF, SIZE); \ } while(-1 == RC && EINTR == errno); \ } #define RECVFROM_SOCK(SOCKET, BUF, LEN, FLAGS, \ ADDR, ADDR_LEN, RC) \ { \ do \ { \ RC = RECVFROM(SOCKET, BUF, LEN, \ FLAGS, ADDR, ADDR_LEN); \ } while(-1 == RC && EINTR == errno); \ } #define SELECT(FDS, INLIST, OUTLIST, XLIST, \ TIMEOUT, RC) \ { \ struct timeval eintr_select_timeval; \ do \ { \ eintr_select_timeval = *(TIMEOUT); \ RC = select(FDS, INLIST, OUTLIST, \ XLIST, &eintr_select_timeval); \ } while(-1 == RC && EINTR == errno); \ } #define SEND(SOCKET, BUF, LEN, FLAGS, RC) \ { \ do \ { \ RC = send(SOCKET, BUF, LEN, FLAGS); \ } while(-1 == RC && EINTR == errno); \ } #define SENDTO_SOCK(SOCKET, BUF, LEN, FLAGS, \ ADDR, ADDR_LEN, RC) \ { \ do \ { \ RC = SENDTO(SOCKET, BUF, LEN, FLAGS, \ ADDR, ADDR_LEN); \ } while(-1 == RC && EINTR == errno); \ } #define STAT_FILE(PATH, INFO, RC) \ { \ do \ { \ RC = Stat(PATH, INFO); \ } while((uint4)-1 == RC && EINTR == errno); \ } #define TCFLUSH(FDESC, REQUEST, RC) \ { \ do \ { \ RC = tcflush(FDESC, REQUEST); \ } while(-1 == RC && EINTR == errno); \ } #if defined(UNIX) #define Tcsetattr(FDESC, WHEN, TERMPTR, RC, ERRNO) \ { \ GBLREF sigset_t block_ttinout; \ sigset_t oldset; \ int rc; \ SIGPROCMASK(SIG_BLOCK, &block_ttinout, &oldset, rc); \ do \ { \ RC = tcsetattr(FDESC, WHEN, TERMPTR); \ } while(-1 == RC && EINTR == errno); \ ERRNO = errno; \ SIGPROCMASK(SIG_SETMASK, &oldset, NULL, rc); \ } #endif #define TRUNCATE_FILE(PATH, LENGTH, RC) \ { \ do \ { \ RC = TRUNCATE(PATH, LENGTH); \ } while(-1 == RC && EINTR == errno); \ } #define WAIT(STATUS, RC) \ { \ do \ { \ RC = wait(STATUS); \ } while(-1 == RC && EINTR == errno); \ } #define WAITPID(PID, STATUS, OPTS, RC) \ { \ /* Ensure that the incoming PID is non-zero. We currently don't know of any places where we want to invoke \ * waitpid with child PID being 0 as that would block us till any of the child spawned by this parent process \ * changes its state unless invoked with WNOHANG bit set. Make sure not waiting on current pid \ */ \ assert(0 != PID); \ assert(getpid() != PID); \ do \ { \ RC = waitpid(PID, STATUS, OPTS); \ } while(-1 == RC && EINTR == errno); \ } #define GTM_FSYNC(FD, RC) \ { \ do \ { \ RC = fsync(FD); \ } while(-1 == RC && EINTR == errno); \ } #define SIGPROCMASK(FUNC, NEWSET, OLDSET, RC) \ { \ do \ { \ RC = sigprocmask(FUNC, NEWSET, OLDSET); \ } while (-1 == RC && EINTR == errno); \ } #if defined(DEBUG) && defined(UNIX) #define SYSCONF(PARM, RC) \ { \ DEFER_INTERRUPTS(INTRPT_IN_SYSCONF); \ if (gtm_white_box_test_case_enabled \ && (WBTEST_SYSCONF_WRAPPER == gtm_white_box_test_case_number)) \ { \ DBGFPF((stderr, "will sleep indefinitely now\n")); \ while (TRUE) \ LONG_SLEEP(60); \ } \ RC = sysconf(PARM); \ ENABLE_INTERRUPTS(INTRPT_IN_SYSCONF); \ } #else #define SYSCONF(PARM, RC) \ { \ DEFER_INTERRUPTS(INTRPT_IN_SYSCONF); \ RC = sysconf(PARM); \ ENABLE_INTERRUPTS(INTRPT_IN_SYSCONF); \ } #endif #endif fis-gtm-V6.0-003/sr_port/emit_code.c0000644000032200000250000015771212201176176016146 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "gtm_string.h" #include #include "gtm_fcntl.h" #include "gtm_stat.h" #include "gtm_stdio.h" #include "compiler.h" #include "opcode.h" #include "mdq.h" #include "vxi.h" #include "vxt.h" #include "cgp.h" #include "obj_gen.h" #include #include "obj_file.h" #include "list_file.h" #include "min_max.h" #include #ifdef UNIX #include "xfer_enum.h" #endif #include "hashtab_mname.h" #include "stddef.h" /* Required to find out variable length argument runtime function calls*/ #if defined(__x86_64__) || defined(__ia64) # include "code_address_type.h" # ifdef XFER # undef XFER # endif /* XFER */ # define XFER(a,b) #b # include "xfer_desc.i" DEFINE_XFER_TABLE_DESC; GBLDEF int call_4lcldo_variant; /* used in emit_jmp for call[sp] and forlcldo */ #endif /* __x86_64__ || __ia64 */ #define MVAL_INT_SIZE DIVIDE_ROUND_UP(SIZEOF(mval), SIZEOF(UINTPTR_T)) #ifdef DEBUG # include "vdatsize.h" /* VAX DISASSEMBLER TEXT */ static const char vdat_bdisp[VDAT_BDISP_SIZE + 1] = "B^"; static const char vdat_wdisp[VDAT_WDISP_SIZE + 1] = "W^"; static const char vdat_r9[VDAT_R9_SIZE + 1] = "(r9)"; static const char vdat_r8[VDAT_R8_SIZE + 1] = "(r8)"; static const char vdat_gr[VDAT_GR_SIZE + 1] = "G^"; static const char vdat_immed[VDAT_IMMED_SIZE + 1] = "I^#"; static const char vdat_r11[VDAT_R11_SIZE + 1] = "(R11)"; static const char vdat_gtmliteral[VDAT_GTMLITERAL_SIZE + 1] = "GTM$LITERAL"; static const char vdat_def[VDAT_DEF_SIZE + 1] = "@"; IA64_ONLY(GBLDEF char asm_mode = 0; /* 0 - disassembly mode. 1 - decode mode */) GBLDEF unsigned char *obpt; /* output buffer index */ GBLDEF unsigned char outbuf[ASM_OUT_BUFF]; /* assembly language output buffer */ static int vaxi_cnt = 1; /* Vax instruction count */ /* Disassembler text: */ LITREF char *xfer_name[]; LITREF char vxi_opcode[][6]; GBLREF char *oc_tab_graphic[]; #endif LITREF octabstruct oc_tab[]; /* op-code table */ LITREF short ttt[]; /* triple templates */ GBLREF boolean_t run_time; GBLREF int sa_temps_offset[]; GBLREF int sa_temps[]; LITREF int sa_class_sizes[]; GBLDEF CODE_TYPE code_buf[NUM_BUFFERRED_INSTRUCTIONS]; GBLDEF int code_idx; #ifdef DEBUG GBLDEF struct inst_count generated_details[MAX_CODE_COUNT], calculated_details[MAX_CODE_COUNT]; GBLDEF int4 generated_count, calculated_count; #endif /* DEBUG */ GBLDEF int calculated_code_size, generated_code_size; GBLDEF int jmp_offset; /* Offset to jump target */ GBLDEF int code_reference; /* Offset from pgm start to current loc */ DEBUG_ONLY(static boolean_t opcode_emitted;) static int stack_depth = 0; /* On x86_64, the smaller offsets are encoded in 1 byte (4 bytes otherwise). But for some cases, the offsets may be different during APPROX_ADDR and MACHINE phases, hence generating different size instruction. to solve this even the smaller offsets need to be encoded in 4 bytes so that same size instructions are generated in both APPROX_ADDR and MACHINE phase. the variable force_32 is used for this purpose*/ X86_64_ONLY(GBLDEF boolean_t force_32 = FALSE;) GBLREF int curr_addr; GBLREF char cg_phase; /* code generation phase */ GBLREF char cg_phase_last; /* the previous code generation phase */ /*variables for counting the arguments*/ static int vax_pushes_seen, vax_number_of_arguments; static struct push_list { struct push_list *next; unsigned char value[PUSH_LIST_SIZE]; } *current_push_list_ptr, *push_list_start_ptr; static int push_list_index; static boolean_t ocnt_ref_seen = FALSE; static oprtype *ocnt_ref_opr; static triple *current_triple; error_def(ERR_MAXARGCNT); error_def(ERR_SRCNAM); error_def(ERR_UNIMPLOP); void trip_gen (triple *ct) { oprtype **sopr, *opr; /* triple operand */ oprtype *saved_opr[MAX_ARGS]; unsigned short oct; short tp; /* template pointer */ const short *tsp; /* template short pointer */ triple *ttp; /* temp triple pointer */ int irep_index; oprtype *irep_opr; const short *repl; /* temp irep ptr */ short repcnt; int off; # if !defined(TRUTH_IN_REG) && (!(defined(__osf__) || defined(__x86_64__) || defined(Linux390))) GTMASSERT; # endif DEBUG_ONLY(opcode_emitted = FALSE); current_triple = ct; /* save for possible use by internal rtns */ tp = ttt[ct->opcode]; if (tp <= 0) { stx_error(ERR_UNIMPLOP); return; } code_idx = 0; vax_pushes_seen = 0; vax_number_of_arguments = 0; if (cg_phase_last != cg_phase) { cg_phase_last = cg_phase; if (cg_phase == CGP_APPROX_ADDR) push_list_init(); else reset_push_list_ptr(); } code_reference = ct->rtaddr; oct = oc_tab[ct->opcode].octype; sopr = &saved_opr[0]; *sopr++ = &ct->destination; for (ttp = ct, opr = ttp->operand ; opr < ARRAYTOP(ttp->operand); ) { if (opr->oprclass) { if (opr->oprclass == TRIP_REF && opr->oprval.tref->opcode == OC_PARAMETER) { ttp = opr->oprval.tref; opr = ttp->operand; continue; } *sopr++ = opr; if (sopr >= ARRAYTOP(saved_opr)) /* user-visible max args is MAX_ARGS - 3 */ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MAXARGCNT, 1, MAX_ARGS - 3); } opr++; } *sopr = 0; jmp_offset = 0; if (oct & OCT_JUMP || ct->opcode == OC_LDADDR || ct->opcode == OC_FORLOOP) { if (ct->operand[0].oprval.tref->rtaddr == 0) /* forward reference */ { jmp_offset = LONG_JUMP_OFFSET; assert(cg_phase == CGP_APPROX_ADDR); } else jmp_offset = ct->operand[0].oprval.tref->rtaddr - ct->rtaddr; switch(ct->opcode) { case OC_CALL: case OC_FORLCLDO: case OC_CALLSP: # ifdef __x86_64__ tsp = (short *)&ttt[ttt[tp]]; if (-128 <= tsp[CALL_4LCLDO_XFER] && 127 >= tsp[CALL_4LCLDO_XFER]) off = jmp_offset - XFER_BYTE_INST_SIZE; else off = jmp_offset - XFER_LONG_INST_SIZE; if (-128 <= (off - BRB_INST_SIZE) && 127 >= (off - BRB_INST_SIZE)) call_4lcldo_variant = BRB_INST_SIZE; /* used by emit_jmp */ else { call_4lcldo_variant = JMP_LONG_INST_SIZE; /* used by emit_jmp */ tsp = (short *)&ttt[ttt[tp + 1]]; if (-128 <= tsp[CALL_4LCLDO_XFER] && 127 >= tsp[CALL_4LCLDO_XFER]) off = jmp_offset - XFER_BYTE_INST_SIZE; else off = jmp_offset - XFER_LONG_INST_SIZE; if (-32768 > (off - JMP_LONG_INST_SIZE) && 32767 < (off - JMP_LONG_INST_SIZE)) tsp = (short *)&ttt[ttt[tp + 2]]; } break; # else off = (jmp_offset - CALL_INST_SIZE)/INST_SIZE; /* [kmk] */ if (off >= -128 && off <= 127) tsp = &ttt[ttt[tp]]; else if (off >= -32768 && off <= 32767) tsp = &ttt[ttt[tp + 1]]; else tsp = &ttt[ttt[tp + 2]]; break; # endif /* __x86_64__ */ case OC_JMP: case OC_JMPEQU: case OC_JMPGEQ: case OC_JMPGTR: case OC_JMPLEQ: case OC_JMPNEQ: case OC_JMPLSS: case OC_JMPTSET: case OC_JMPTCLR: case OC_LDADDR: case OC_FORLOOP: tsp = &ttt[ttt[tp]]; break; default: GTMASSERT; } } else if (oct & OCT_COERCE) { switch (oc_tab[ct->operand[0].oprval.tref->opcode].octype & (OCT_VALUE | OCT_BOOL)) { case OCT_MVAL: tp = ttt[tp]; break; case OCT_MINT: tp = ttt[tp + 3]; break; case OCT_BOOL: tp = ttt[tp + 4]; break; default: GTMASSERT; break; } tsp = &ttt[tp]; } else tsp = &ttt[tp]; for (; *tsp != VXT_END;) { if (*tsp == VXT_IREPAB || *tsp == VXT_IREPL) { repl = tsp; repl += 2; repcnt = *repl++; assert(repcnt != 1); for (irep_index = repcnt, irep_opr = &ct->operand[1]; irep_index > 2; --irep_index) { assert(irep_opr->oprclass == TRIP_REF); irep_opr = &irep_opr->oprval.tref->operand[1]; } if (irep_opr->oprclass == TRIP_REF) { repl = tsp; do { tsp = repl; tsp = emit_vax_inst((short *)tsp, &saved_opr[0], --sopr); # ifdef DEBUG if (cg_phase == CGP_ASSEMBLY) emit_asmlist(ct); # endif } while (sopr > &saved_opr[repcnt]); } else { sopr = &saved_opr[repcnt]; tsp = repl; } } else { assert(*tsp > 0 && *tsp <= 511); tsp = emit_vax_inst((short *)tsp, &saved_opr[0], sopr); # ifdef DEBUG if (cg_phase == CGP_ASSEMBLY) emit_asmlist(ct); # endif } /* else */ } /* for */ if (cg_phase == CGP_APPROX_ADDR) if (vax_pushes_seen > 0) add_to_vax_push_list(vax_pushes_seen); } #ifdef DEBUG void emit_asmlist(triple *ct) { int offset; unsigned char *c; obpt -= 2; *obpt = ' '; /* erase trailing comma */ if (!opcode_emitted) { opcode_emitted = TRUE; offset = (int)(&outbuf[0] + 60 - obpt); if (offset >= 1) { /* tab to position 60 */ memset(obpt, ' ', offset); obpt += offset; } else { /* leave at least 2 spaces */ memset(obpt, ' ', 2); obpt += 2; } *obpt++ = ';'; for (c = (unsigned char*)oc_tab_graphic[ct->opcode]; *c;) *obpt++ = *c++; } emit_eoi(); format_machine_inst(); } void emit_eoi (void) { IA64_ONLY(if (asm_mode == 0) {) *obpt++ = '\0'; list_tab(); list_line((char *)outbuf); IA64_ONLY(}) return; } #endif short *emit_vax_inst (short *inst, oprtype **fst_opr, oprtype **lst_opr) { static short last_vax_inst = 0; short sav_in, save_inst; boolean_t oc_int; oprtype *opr; triple *ct; int cnt, cnttop, reg, words_to_move, reg_offset, save_reg_offset, targ_reg; int branch_idx, branch_offset, loop_top_idx, instr; code_idx = 0; switch (cg_phase) { case CGP_ASSEMBLY: # ifdef DEBUG list_chkpage(); obpt = &outbuf[0]; memset(obpt, SP, SIZEOF(outbuf)); i2asc((uchar_ptr_t)obpt, vaxi_cnt++); obpt += 7; if (VXT_IREPAB != *inst && VXT_IREPL != *inst) instr = *inst; else instr = (*inst == VXT_IREPAB) ? VXI_PUSHAB : VXI_PUSHL; memcpy(obpt, &vxi_opcode[instr][0], 6); obpt += 10; *obpt++ = SP; *obpt++ = SP; /***** WARNING - FALL THRU *****/ # endif case CGP_ADDR_OPT: case CGP_APPROX_ADDR: case CGP_MACHINE: switch ((sav_in = *inst++)) { case VXI_BEQL: emit_jmp(GENERIC_OPCODE_BEQ, &inst, GTM_REG_COND_CODE); break; case VXI_BGEQ: emit_jmp(GENERIC_OPCODE_BGE, &inst, GTM_REG_COND_CODE); break; case VXI_BGTR: emit_jmp(GENERIC_OPCODE_BGT, &inst, GTM_REG_COND_CODE); break; case VXI_BLEQ: emit_jmp(GENERIC_OPCODE_BLE, &inst, GTM_REG_COND_CODE); break; case VXI_BLSS: emit_jmp(GENERIC_OPCODE_BLT, &inst, GTM_REG_COND_CODE); break; case VXI_BNEQ: emit_jmp(GENERIC_OPCODE_BNE, &inst, GTM_REG_COND_CODE); break; case VXI_BLBC: case VXI_BLBS: assert(*inst == VXT_REG); inst++; # ifdef TRUTH_IN_REG reg = GTM_REG_CODEGEN_TEMP; NON_GTM64_ONLY(GEN_LOAD_WORD(reg, gtm_reg(*inst++), 0);) GTM64_ONLY( GEN_LOAD_WORD_4(reg, gtm_reg(*inst++), 0);) # else /* For platforms, where the $TRUTH value is not carried in a register and must be fetched from a global variable by subroutine call. */ assert(*inst == 0x5a); /* VAX r10 or $TEST register */ inst++; emit_call_xfer(SIZEOF(intszofptr_t) * xf_dt_get); reg = GTM_REG_R0; /* function return value */ # endif /* Generate a cmp instruction using the return value of the previous call, which will be in EAX */ X86_64_ONLY(GEN_CMP_EAX_IMM32(0);) if (sav_in == VXI_BLBC) X86_64_ONLY(emit_jmp(GENERIC_OPCODE_BEQ, &inst, 0);) NON_X86_64_ONLY(emit_jmp(GENERIC_OPCODE_BLBC, &inst, reg);) else { assert(sav_in == VXI_BLBS); X86_64_ONLY(emit_jmp(GENERIC_OPCODE_BNE, &inst, 0);) NON_X86_64_ONLY(emit_jmp(GENERIC_OPCODE_BLBS, &inst, reg);) } break; case VXI_BRB: emit_jmp(GENERIC_OPCODE_BR, &inst, 0); break; case VXI_BRW: emit_jmp(GENERIC_OPCODE_BR, &inst, 0); break; case VXI_BICB2: # ifdef TRUTH_IN_REG GEN_CLEAR_TRUTH; # endif assert(*inst == VXT_LIT); inst++; assert(*inst == 1); inst++; assert(*inst == VXT_REG); inst++; inst++; break; case VXI_BISB2: # ifdef TRUTH_IN_REG GEN_SET_TRUTH; # endif assert(*inst == VXT_LIT); inst++; assert(*inst == 1); inst++; assert(*inst == VXT_REG); inst++; inst++; break; case VXI_CALLS: oc_int = TRUE; if (*inst == VXT_LIT) { inst++; cnt = (int4)*inst++; } else { assert(*inst == VXT_VAL); inst++; opr = *(fst_opr + *inst); assert(opr->oprclass == TRIP_REF); ct = opr->oprval.tref; if (ct->destination.oprclass) opr = &ct->destination; # ifdef __vms /* This is a case where VMS puts the argument count in a special register so handle that differently here. */ if (opr->oprclass == TRIP_REF) { assert(ct->opcode == OC_ILIT); cnt = ct->operand[0].oprval.ilit; code_buf[code_idx++] = ALPHA_INS_LDA | ALPHA_REG_AI << ALPHA_SHIFT_RA | ALPHA_REG_ZERO << ALPHA_SHIFT_RB | (cnt & ALPHA_MASK_DISP) << ALPHA_SHIFT_DISP; inst++; } else { assert(opr->oprclass == TINT_REF); oc_int = FALSE; opr = *(fst_opr + *inst++); reg = get_arg_reg(); emit_trip(opr, TRUE, ALPHA_INS_LDL, reg); emit_push(reg); } # else /* All other platforms put argument counts in normal parameter registers and go through this path instead. */ if (opr->oprclass == TRIP_REF) { assert(ct->opcode == OC_ILIT); cnt = ct->operand[0].oprval.ilit; reg = get_arg_reg(); IA64_ONLY(LOAD_IMM14(reg, cnt);) NON_IA64_ONLY(GEN_LOAD_IMMED(reg, cnt);) cnt++; inst++; } else { assert(opr->oprclass == TINT_REF); oc_int = FALSE; opr = *(fst_opr + *inst++); reg = get_arg_reg(); emit_trip(opr, TRUE, GENERIC_OPCODE_LOAD, reg); } emit_push(reg); # endif } assert(*inst == VXT_XFER); inst++; emit_call_xfer((int)*inst++); if (oc_int) { if (cnt != 0) emit_pop(cnt); } else { /* During the commonization of emit_code.c I discovered that TINT_REF is not currently used in the compiler so this may be dead code but I'm leaving this path in here anyway because I don't want to put it back in if we find we need it. (4/2003 SE) */ emit_trip(opr, TRUE, GENERIC_OPCODE_LOAD, CALLS_TINT_TEMP_REG); emit_pop(1); } break; case VXI_CLRL: assert(*inst == VXT_VAL); inst++; GEN_CLEAR_WORD_EMIT(CLRL_REG); break; case VXI_CMPL: assert(*inst == VXT_VAL); inst++; GEN_LOAD_WORD_EMIT(CMPL_TEMP_REG); assert(*inst == VXT_VAL); inst++; X86_64_ONLY(GEN_LOAD_WORD_EMIT(GTM_REG_CODEGEN_TEMP);) NON_X86_64_ONLY(GEN_LOAD_WORD_EMIT(GTM_REG_COND_CODE);) X86_64_ONLY(GEN_CMP_REGS(CMPL_TEMP_REG, GTM_REG_CODEGEN_TEMP)) NON_X86_64_ONLY(GEN_SUBTRACT_REGS(CMPL_TEMP_REG, GTM_REG_COND_CODE, GTM_REG_COND_CODE);) break; case VXI_INCL: assert(*inst == VXT_VAL); inst++; save_inst = *inst++; emit_trip(*(fst_opr + save_inst), TRUE, GENERIC_OPCODE_LOAD, GTM_REG_ACCUM); GEN_ADD_IMMED(GTM_REG_ACCUM, 1); emit_trip(*(fst_opr + save_inst), TRUE, GENERIC_OPCODE_STORE, GTM_REG_ACCUM); break; case VXI_JMP: if (*inst == VXT_VAL) { inst++; emit_trip(*(fst_opr + *inst++), FALSE, GENERIC_OPCODE_LOAD, GTM_REG_CODEGEN_TEMP); GEN_JUMP_REG(GTM_REG_CODEGEN_TEMP); } else emit_jmp(GENERIC_OPCODE_BR, &inst, 0); break; case VXI_JSB: assert(*inst == VXT_XFER); inst++; emit_call_xfer((int)*inst++); /* Callee may have popped some values so we can't count on anything left on the stack. */ stack_depth = 0; break; case VXI_MOVAB: if (*inst == VXT_JMP) { inst += 2; emit_pcrel(); NON_RISC_ONLY(IGEN_LOAD_ADDR_REG(GTM_REG_ACCUM)) RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_ADDR_REG(GTM_REG_ACCUM);) assert(*inst == VXT_ADDR); inst++; emit_trip(*(fst_opr + *inst++), FALSE, GENERIC_OPCODE_STORE, GTM_REG_ACCUM); } else if (*inst == VXT_ADDR || *inst == VXT_VAL) { boolean_t addr; addr = (*inst == VXT_VAL); inst++; save_inst = *inst++; assert(*inst == VXT_REG); inst++; emit_trip(*(fst_opr + save_inst), addr, GENERIC_OPCODE_LDA, gtm_reg(*inst++)); } else GTMASSERT; break; case VXI_MOVC3: /* The MOVC3 instruction is only used to copy an mval from one place to another so that is the expansion we will generate. The most efficient expansion is to generate a series of load and store instructions. Do the loads first then the stores to keep the pipelines flowing and not stall waiting for any given load or store to complete. Because some platforms (notably HPPA) do not have enough argument registers to contain an entire MVAL and because an mval may grow from its present size and affect other platforms some day, We put the whole code gen thing in a loop so we can do this regardless of how big it gets. */ assert(*inst == VXT_LIT); inst += 2; assert(*inst == VXT_VAL); inst++; emit_trip(*(fst_opr + *inst++), TRUE, GENERIC_OPCODE_LDA, MOVC3_SRC_REG); assert(*inst == VXT_VAL); inst++; emit_trip(*(fst_opr + *inst++), TRUE, GENERIC_OPCODE_LDA, MOVC3_TRG_REG); # if defined(__MVS__) || defined(Linux390) /* The MVC instruction on zSeries facilitates memory copy(mval in this case) in a single * instruction instead of multiple 8/4 byte copies. * * TODO: Revisit other platforms using generic emit_code and verify if the below * logic of multiple copies can be replaced with more efficient instruction(s) * available on that particular platform. */ GEN_MVAL_COPY(MOVC3_SRC_REG, MOVC3_TRG_REG, SIZEOF(mval)); # else for (words_to_move = MVAL_INT_SIZE, reg_offset = 0; words_to_move;) { reg = MACHINE_FIRST_ARG_REG; save_reg_offset = reg_offset; for (cnt = 0, cnttop = MIN(words_to_move, MACHINE_REG_ARGS) ; cnt < cnttop; cnt++, reg_offset += SIZEOF(UINTPTR_T)) { X86_64_ONLY(targ_reg = GET_ARG_REG(cnt);) NON_X86_64_ONLY(targ_reg = reg + cnt;) NON_GTM64_ONLY(GEN_LOAD_WORD(targ_reg, MOVC3_SRC_REG, reg_offset);) GTM64_ONLY(GEN_LOAD_WORD_8(targ_reg, MOVC3_SRC_REG, reg_offset);) } reg = MACHINE_FIRST_ARG_REG; for (cnt = 0; cnt < cnttop; cnt++, save_reg_offset += SIZEOF(UINTPTR_T), words_to_move--) { X86_64_ONLY(targ_reg = GET_ARG_REG(cnt);) NON_X86_64_ONLY(targ_reg = reg + cnt;) NON_GTM64_ONLY(GEN_STORE_WORD(targ_reg, MOVC3_TRG_REG, save_reg_offset);) GTM64_ONLY(GEN_STORE_WORD_8(targ_reg, MOVC3_TRG_REG, save_reg_offset);) } } # endif break; case VXI_MOVL: if (*inst == VXT_REG) { inst++; if (*inst > 0x5f) /* OC_CURRHD: any mode >= 6 (deferred), any register */ { inst++; NON_GTM64_ONLY(GEN_LOAD_WORD(GTM_REG_ACCUM, GTM_REG_FRAME_POINTER, 0);) GTM64_ONLY(GEN_LOAD_WORD_8(GTM_REG_ACCUM, GTM_REG_FRAME_POINTER, 0);) assert(*inst == VXT_ADDR); inst++; emit_trip(*(fst_opr + *inst++), FALSE, GENERIC_OPCODE_STORE, GTM_REG_ACCUM); } else { boolean_t addr; assert(*inst == 0x50); /* register mode: (from) r0 */ inst++; if (*inst == VXT_VAL || *inst == VXT_ADDR) { addr = (*inst == VXT_VAL); inst++; emit_trip(*(fst_opr + *inst++), addr, GENERIC_OPCODE_STORE, MOVL_RETVAL_REG); } else if (*inst == VXT_REG) { inst++; # ifdef TRUTH_IN_REG if (*inst == 0x5a) /* to VAX r10 or $TEST */ { NON_GTM64_ONLY(GEN_STORE_WORD(MOVL_RETVAL_REG, GTM_REG_DOLLAR_TRUTH, 0);) GTM64_ONLY(GEN_STORE_WORD_4(MOVL_RETVAL_REG, GTM_REG_DOLLAR_TRUTH, 0);) } else { GEN_MOVE_REG(gtm_reg(*inst), MOVL_RETVAL_REG); } # else if (*inst == 0x5a) /* to VAX r10 or $TEST */ { reg = get_arg_reg(); GEN_MOVE_REG(reg, MOVL_RETVAL_REG); emit_push(reg); emit_call_xfer(SIZEOF(intszofptr_t) * xf_dt_store); } else { GEN_MOVE_REG(gtm_reg(*inst), MOVL_RETVAL_REG); } # endif inst++; } else GTMASSERT; } } else if (*inst == VXT_VAL) { inst++; save_inst = *inst++; assert(*inst == VXT_REG); inst++; assert(*inst == 0x51); /* register mode: R1 */ inst++; emit_trip(*(fst_opr + save_inst), TRUE, GENERIC_OPCODE_LOAD, MOVL_REG_R1); } else GTMASSERT; break; case VXT_IREPAB: assert(*inst == VXT_VAL); inst += 2; reg = get_arg_reg(); emit_trip(*lst_opr, TRUE, GENERIC_OPCODE_LDA, reg); emit_push(reg); break; case VXI_PUSHAB: reg = get_arg_reg(); if (*inst == VXT_JMP) { inst += 2; emit_pcrel(); NON_RISC_ONLY(IGEN_LOAD_ADDR_REG(reg)) RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_ADDR_REG(reg);) } else if (*inst == VXT_VAL || *inst == VXT_GREF) { inst++; emit_trip(*(fst_opr + *inst++), TRUE, GENERIC_OPCODE_LDA, reg); } else GTMASSERT; emit_push(reg); break; case VXT_IREPL: assert(*inst == VXT_VAL); inst += 2; reg = get_arg_reg(); emit_trip(*lst_opr, TRUE, GENERIC_OPCODE_LOAD, reg); emit_push(reg); break; case VXI_PUSHL: reg = get_arg_reg(); if (*inst == VXT_LIT) { inst++; GEN_LOAD_IMMED(reg, *inst); inst++; } else if (*inst == VXT_ADDR) { inst++; emit_trip(*(fst_opr + *inst++), FALSE, GENERIC_OPCODE_LOAD, reg); } else if (*inst == VXT_VAL) { inst++; emit_trip(*(fst_opr + *inst++), TRUE, GENERIC_OPCODE_LOAD, reg); } else GTMASSERT; emit_push(reg); break; case VXI_TSTL: assert(*inst == VXT_VAL || *inst == VXT_REG); if (*inst == VXT_VAL) { inst++; emit_trip( *(fst_opr + *inst++), TRUE, GENERIC_OPCODE_LOAD, X86_64_ONLY(GTM_REG_CODEGEN_TEMP) NON_X86_64_ONLY(GTM_REG_COND_CODE) ); X86_64_ONLY(GEN_CMP_IMM32(GTM_REG_CODEGEN_TEMP, 0)) } else if (*inst == VXT_REG) { inst++; X86_64_ONLY(assert(gtm_reg(*inst) == I386_REG_RAX); /* Same as R0 */) X86_64_ONLY(GEN_CMP_EAX_IMM32(0);) NON_X86_64_ONLY(GEN_MOVE_REG(GTM_REG_COND_CODE, gtm_reg(*inst));) inst++; } break; default: GTMASSERT; break; } break; default: GTMASSERT; break; } assert(code_idx < NUM_BUFFERRED_INSTRUCTIONS); if (cg_phase == CGP_MACHINE) { generated_code_size += code_idx; # ifdef DEBUG if (generated_count < MAX_CODE_COUNT) { generated_details[generated_count].size = code_idx; generated_details[generated_count++].sav_in = sav_in; } # endif /* DEBUG */ emit_immed ((char *)&code_buf[0], (uint4)(INST_SIZE * code_idx)); } else if (cg_phase != CGP_ASSEMBLY) { if (cg_phase == CGP_APPROX_ADDR) { calculated_code_size += code_idx; # ifdef DEBUG if (calculated_count < MAX_CODE_COUNT) { calculated_details[calculated_count].size = code_idx; calculated_details[calculated_count++].sav_in = sav_in; } # endif /* DEBUG */ } curr_addr += (INST_SIZE * code_idx); } code_reference += (INST_SIZE * code_idx); jmp_offset -= (INST_SIZE * code_idx); last_vax_inst = sav_in; return inst; } #ifndef __x86_64__ /* For x86_64, this is defined in emit_code_sp.c */ void emit_jmp (uint4 branchop, short **instp, int reg) { uint4 branchop_opposite; int src_reg; int skip_idx; NON_RISC_ONLY(int tmp_code_idx;) int branch_offset; /* assert(jmp_offset != 0); */ /* assert commented since jmp_offset could be zero in CGP_ADDR_OPT phase after a jump to the immediately following * instruction is nullified (as described below) */ /* size of this particular instruction */ jmp_offset -= (int)((char *)&code_buf[code_idx] - (char *)&code_buf[0]); # if !(defined(__MVS__) || defined(Linux390)) /* The code_buff on zSeries is filled with 2 byte chunks */ assert((jmp_offset & 3) == 0); # endif branch_offset = jmp_offset / INST_SIZE; /* Some platforms have a different origin for the offset */ EMIT_JMP_ADJUST_BRANCH_OFFSET; switch (cg_phase) { # ifdef DEBUG case CGP_ASSEMBLY: *obpt++ = 'x'; *obpt++ = '^'; *obpt++ = '0'; *obpt++ = 'x'; obpt += i2hex_nofill(INST_SIZE * branch_offset, (uchar_ptr_t)obpt, 8); *obpt++ = ','; *obpt++ = ' '; /***** WARNING - FALL THRU *****/ # endif case CGP_ADDR_OPT: case CGP_APPROX_ADDR: case CGP_MACHINE: assert(VXT_JMP == **instp); *instp += 1; assert(1 == **instp); (*instp)++; if (0 == branch_offset) { /* This is a jump to the immediately following instruction. Nullify the jump and don't generate any instruction (not even a NOP) */ /* code_buf[code_idx++] = GENERIC_OPCODE_NOP; */ } else if (EMIT_JMP_SHORT_CODE_CHECK) { /* Short jump immediate operand - some platforms also do a compare */ EMIT_JMP_SHORT_CODE_GEN; } else { /* Potentially longer jump sequence */ skip_idx = -1; if (EMIT_JMP_OPPOSITE_BR_CHECK) { /* This jump sequence is longer and is not conditional so if we need a conditional jump, create the opposite conditional jump to jump around the longer jump to the target thereby preserving the original semantics. */ EMIT_JMP_GEN_COMPARE; switch (branchop) { case GENERIC_OPCODE_BEQ: branchop_opposite = GENERIC_OPCODE_BNE; break; case GENERIC_OPCODE_BGE: branchop_opposite = GENERIC_OPCODE_BLT; break; case GENERIC_OPCODE_BGT: branchop_opposite = GENERIC_OPCODE_BLE; break; case GENERIC_OPCODE_BLE: branchop_opposite = GENERIC_OPCODE_BGT; break; case GENERIC_OPCODE_BLT: branchop_opposite = GENERIC_OPCODE_BGE; break; case GENERIC_OPCODE_BNE: branchop_opposite = GENERIC_OPCODE_BEQ; break; # ifdef __alpha case GENERIC_OPCODE_BLBC: branchop_opposite = GENERIC_OPCODE_BLBS; break; case GENERIC_OPCODE_BLBS: branchop_opposite = GENERIC_OPCODE_BLBC; break; # endif default: GTMASSERT; break; } RISC_ONLY( skip_idx = code_idx++; /* Save index of branch inst. Set target offset later */ code_buf[skip_idx] = IGEN_COND_BRANCH_REG_OFFSET(branchop_opposite, reg, 0); branch_offset--; ) NON_RISC_ONLY( skip_idx = code_idx; /* Save index of branch inst. Set target offset later */ IGEN_COND_BRANCH_REG_OFFSET(branchop_opposite, reg, 0) branch_offset -= NUM_INST_IGEN_COND_BRANCH_REG_OFFSET; ) # ifdef DELAYED_BRANCH code_buf[code_idx++] = GENERIC_OPCODE_NOP; branch_offset--; # endif } if (EMIT_JMP_LONG_CODE_CHECK) { /* This is more common unconditional branch generation and should be mutually exclusive to EMIT_JMP_OPPOSITE_BR_CHECK. Some platforms will have the "short" branch generation up top be more common but that form does not cover unconditional jumps (Examples: AIX and HP-UX) */ assert(!(EMIT_JMP_OPPOSITE_BR_CHECK)); NON_RISC_ONLY(IGEN_UCOND_BRANCH_REG_OFFSET(branchop, branch_offset)) RISC_ONLY( code_buf[code_idx++] = IGEN_UCOND_BRANCH_REG_OFFSET(branchop, 0, branch_offset); ) # ifdef DELAYED_BRANCH code_buf[code_idx++] = GENERIC_OPCODE_NOP; # endif } else { if (EMIT_JMP_OPPOSITE_BR_CHECK) { /* VAX conditional long jump generates two native branch instructions - one conditional branch (above) and one PC relative branch (below). The second branch instruction also needs adjustment of the origin. */ EMIT_JMP_ADJUST_BRANCH_OFFSET; } GEN_PCREL; emit_base_offset(GTM_REG_CODEGEN_TEMP, (INST_SIZE * branch_offset)); RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_ADDR_REG(GTM_REG_CODEGEN_TEMP);) NON_RISC_ONLY(IGEN_LOAD_ADDR_REG(GTM_REG_CODEGEN_TEMP)) GEN_JUMP_REG(GTM_REG_CODEGEN_TEMP); } if (skip_idx != -1) { /* Fill in the offset from our opposite jump instruction to here .. the place to bypass the jump. */ branch_offset = BRANCH_OFFSET_FROM_IDX(skip_idx, code_idx); RISC_ONLY(code_buf[skip_idx] |= IGEN_COND_BRANCH_OFFSET(branch_offset);) NON_RISC_ONLY( tmp_code_idx = code_idx; code_idx = skip_idx; IGEN_COND_BRANCH_REG_OFFSET(branchop_opposite, reg, branch_offset) code_idx = tmp_code_idx; ) } } break; default: GTMASSERT; break; } } #endif /* !__x86_64__ */ /* Emit code that generates a relative pc based jump target. The last instruction is not complete so the caller may finish it with whatever instruction is necessary. */ void emit_pcrel(void) { int branch_offset; jmp_offset -= INTCAST((char *)&code_buf[code_idx] - (char *)&code_buf[0]); switch (cg_phase) { # ifdef DEBUG case CGP_ASSEMBLY: *obpt++ = 'x'; *obpt++ = '^'; *obpt++ = '0'; *obpt++ = 'x'; obpt += i2hex_nofill(jmp_offset + code_reference, (uchar_ptr_t)obpt, 8); *obpt++ = ','; *obpt++ = ' '; /***** WARNING - FALL THRU *****/ # endif case CGP_ADDR_OPT: case CGP_APPROX_ADDR: case CGP_MACHINE: branch_offset = jmp_offset / INST_SIZE; GEN_PCREL; EMIT_JMP_ADJUST_BRANCH_OFFSET; /* Account for different branch origins on different platforms */ emit_base_offset(GTM_REG_CODEGEN_TEMP, INST_SIZE * branch_offset); break; default: GTMASSERT; break; } } /* Emit the code for a given triple */ void emit_trip(oprtype *opr, boolean_t val_output, uint4 generic_inst, int trg_reg) { boolean_t inst_emitted; unsigned char reg, op_mod, op_reg; int offset, immediate; int upper_idx, lower_idx; triple *ct; int low, extra, high; GTM64_ONLY(int next_ptr_offset = 8;) if (opr->oprclass == TRIP_REF) { ct = opr->oprval.tref; if (ct->destination.oprclass) opr = &ct->destination; /* else lit or error */ } inst_emitted = FALSE; switch (cg_phase) { case CGP_ADDR_OPT: case CGP_APPROX_ADDR: switch (opr->oprclass) { case TRIP_REF: assert(ct->destination.oprclass == 0); assert(val_output); switch (ct->opcode) { case OC_LIT: assert(ct->operand[0].oprclass == MLIT_REF); if (run_time) reg = GTM_REG_PV; else reg = GTM_REG_LITERAL_BASE; if (CGP_ADDR_OPT == cg_phase) { /* We want the expansion to be proper sized this time. Note that this won't be true so much on the initial CGP_ADDR_OPT pass but will be true on the shrink_trips() pass after the literals are compiled. */ offset = literal_offset(ct->operand[0].oprval.mlit->rt_addr); /* Need non-zero base reg for AIX */ X86_64_ONLY(force_32 = TRUE;) emit_base_offset(reg, offset); X86_64_ONLY(force_32 = FALSE;) } else { /* Gross expansion ok first time through */ /* Non-0 base reg for AIX */ X86_64_ONLY(force_32 = TRUE;) emit_base_offset(reg, LONG_JUMP_OFFSET); X86_64_ONLY(force_32 = FALSE;) } X86_64_ONLY(IGEN_LOAD_ADDR_REG(trg_reg)) # if !(defined(__MVS__) || defined(Linux390)) NON_X86_64_ONLY(code_idx++;) # else IGEN_LOAD_ADDR_REG(trg_reg); # endif inst_emitted = TRUE; break; case OC_CDLIT: emit_base_offset(GTM_REG_PV, find_linkage(ct->operand[0].oprval.cdlt)); if (GENERIC_OPCODE_LDA == generic_inst) { RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_LINKAGE(trg_reg);) NON_RISC_ONLY(IGEN_LOAD_LINKAGE(trg_reg);) inst_emitted = TRUE; } else { RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_LINKAGE(GTM_REG_CODEGEN_TEMP);) NON_RISC_ONLY(IGEN_LOAD_LINKAGE(GTM_REG_CODEGEN_TEMP);) emit_base_offset(GTM_REG_CODEGEN_TEMP, 0); } break; case OC_ILIT: assert(GENERIC_OPCODE_LOAD == generic_inst); immediate = ct->operand[0].oprval.ilit; EMIT_TRIP_ILIT_GEN; inst_emitted = TRUE; break; case OC_TRIPSIZE: /* This tiples value is calculated in the shrink_jmp/shrink_trips phase. It is a parameter to (currently only) op_exfun and is the length of the generated jump instruction. op_exfun needs this length to adjust the return address in the created stackframe so it does not have to parse instructions at the return address to see what return signature was created. We will add asserts to this generation in later phases after the true value has been calculated. At this point, it is zero. */ immediate = ct->operand[0].oprval.tsize->size; EMIT_TRIP_ILIT_GEN; inst_emitted = TRUE; break; default: GTMASSERT; break; } break; case TINT_REF: case TVAL_REF: assert(val_output); offset = sa_temps_offset[opr->oprclass]; offset -= (sa_temps[opr->oprclass] - opr->oprval.temp) * sa_class_sizes[opr->oprclass]; GTM64_ONLY( if ( sa_class_sizes[opr->oprclass] == 4 ) { next_ptr_offset = 4; REVERT_GENERICINST_TO_WORD(generic_inst); } ) NON_GTM64_ONLY( if (offset < 0 || offset > MAX_OFFSET) GTMASSERT; ) emit_base_offset(GTM_REG_FRAME_TMP_PTR, offset); break; case TCAD_REF: case TVAD_REF: case TVAR_REF: offset = sa_temps_offset[opr->oprclass]; offset -= (sa_temps[opr->oprclass] - opr->oprval.temp) * sa_class_sizes[opr->oprclass]; GTM64_ONLY( if ( sa_class_sizes[opr->oprclass] == 4 ) { next_ptr_offset = 4; REVERT_GENERICINST_TO_WORD(generic_inst); } ) NON_GTM64_ONLY( if (offset < 0 || offset > MAX_OFFSET) GTMASSERT; ) if (opr->oprclass == TVAR_REF) reg = GTM_REG_FRAME_VAR_PTR; else reg = GTM_REG_FRAME_TMP_PTR; emit_base_offset(reg, offset); if (val_output) { if (GENERIC_OPCODE_LDA == generic_inst) { NON_RISC_ONLY(IGEN_LOAD_NATIVE_REG(trg_reg)) RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_NATIVE_REG(trg_reg);) if (opr->oprclass == TVAR_REF) { emit_base_offset(trg_reg, offsetof(ht_ent_mname, value)); NON_RISC_ONLY(IGEN_LOAD_NATIVE_REG(trg_reg)) RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_NATIVE_REG(trg_reg);) } inst_emitted = TRUE; } else { NON_RISC_ONLY(IGEN_LOAD_NATIVE_REG(GTM_REG_CODEGEN_TEMP)) RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_NATIVE_REG(GTM_REG_CODEGEN_TEMP);) emit_base_offset(GTM_REG_CODEGEN_TEMP, 0); } } break; case OCNT_REF: /* This ref's value is calculated in emit_call_xfer(). This value is related to TSIZ_REF in that it is used for the same reason to different calls (op_call, op_callsp, op_forlcldo, and their mprof counterparts). It is the offset needed to be added to the return address from the calls to these routines to bypass a generated jump sequence. In this case however, the jump sequence is being generated as part of the OC_CALL, OC_CALLSP or OC_FORLCLDO triple itself. There is no separate jump triple so the TSIZ_REF triple cannot be used. So this operand is the OFFSET from the CALL to the NEXT TRIPLE. The operation is that when this routine sees this type of reference, it will set a flag and record the operand address and go ahead and generate the value that it has. The next transfer table generation that occurs will see the set flag and will compute the address from the return address of that transfer table call to the next triple and update this triple's value. Since our originating triple has a JUMP type, it will be updated in shrink_jmp/shirnk_trips() until all necessary shrinkage is done so the final phase will have the correct value and we only have to generate an immediate value. */ immediate = opr->oprval.offset; EMIT_TRIP_ILIT_GEN; inst_emitted = TRUE; ocnt_ref_seen = TRUE; ocnt_ref_opr = opr; break; } if (!inst_emitted) { NON_RISC_ONLY(IGEN_GENERIC_REG(generic_inst, trg_reg)) RISC_ONLY(code_buf[code_idx++] |= IGEN_GENERIC_REG(generic_inst, trg_reg);) } break; # ifdef DEBUG case CGP_ASSEMBLY: offset = 0; switch (opr->oprclass) { case TRIP_REF: assert(ct->destination.oprclass == 0); assert(val_output); switch (ct->opcode) { case OC_LIT: assert(ct->operand[0].oprclass == MLIT_REF); offset = literal_offset(ct->operand[0].oprval.mlit->rt_addr); memcpy(obpt, &vdat_def[0], VDAT_DEF_SIZE); obpt += VDAT_DEF_SIZE; memcpy(obpt, &vdat_gtmliteral[0], VDAT_GTMLITERAL_SIZE); obpt += VDAT_GTMLITERAL_SIZE; *obpt++ = '+'; *obpt++ = '0'; *obpt++ = 'x'; obpt += i2hex_nofill(offset, (uchar_ptr_t)obpt, 8); if (run_time) reg = GTM_REG_PV; else reg = GTM_REG_LITERAL_BASE; X86_64_ONLY(force_32 = TRUE;) emit_base_offset(reg, offset); X86_64_ONLY(force_32 = FALSE;) NON_RISC_ONLY(IGEN_LOAD_ADDR_REG(trg_reg)) RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_ADDR_REG(trg_reg);) inst_emitted = TRUE; break; case OC_CDLIT: if (val_output) { memcpy(obpt, &vdat_gr[0], VDAT_GR_SIZE); obpt += VDAT_GR_SIZE; } memcpy(obpt, ct->operand[0].oprval.cdlt->addr, ct->operand[0].oprval.cdlt->len); obpt += ct->operand[0].oprval.cdlt->len; emit_base_offset(GTM_REG_PV, find_linkage(ct->operand[0].oprval.cdlt)); if (GENERIC_OPCODE_LDA == generic_inst) { RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_LINKAGE(trg_reg)); NON_RISC_ONLY(IGEN_LOAD_LINKAGE(trg_reg)); inst_emitted = TRUE; } else { RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_LINKAGE(GTM_REG_CODEGEN_TEMP);) NON_RISC_ONLY(IGEN_LOAD_LINKAGE(GTM_REG_CODEGEN_TEMP);) emit_base_offset(GTM_REG_CODEGEN_TEMP, 0); } break; case OC_ILIT: assert(generic_inst == GENERIC_OPCODE_LOAD); immediate = ct->operand[0].oprval.ilit; memcpy(obpt, &vdat_immed[0], VDAT_IMMED_SIZE); obpt += VDAT_IMMED_SIZE; obpt = i2asc((uchar_ptr_t)obpt, ct->operand[0].oprval.ilit); EMIT_TRIP_ILIT_GEN; inst_emitted = TRUE; break; case OC_TRIPSIZE: immediate = ct->operand[0].oprval.tsize->size; assert(0 < immediate); assert(MAX_BRANCH_CODEGEN_SIZE > immediate); EMIT_TRIP_ILIT_GEN; inst_emitted = TRUE; break; default: GTMASSERT; break; } break; case TINT_REF: case TVAL_REF: assert(val_output); offset = sa_temps_offset[opr->oprclass]; offset -= (sa_temps[opr->oprclass] - opr->oprval.temp) * sa_class_sizes[opr->oprclass]; NON_GTM64_ONLY( if (offset < 0 || offset > MAX_OFFSET) GTMASSERT; ) if (offset < 127) { memcpy(obpt, &vdat_bdisp[0], VDAT_BDISP_SIZE); obpt += VDAT_BDISP_SIZE; } else { memcpy(obpt, &vdat_wdisp[0], VDAT_WDISP_SIZE); obpt += VDAT_WDISP_SIZE; } obpt = i2asc((uchar_ptr_t)obpt, offset); memcpy(obpt, &vdat_r9[0], VDAT_R9_SIZE); obpt += VDAT_R9_SIZE; /* * for 64 bit platforms, By default the loads/stores * are of 8 bytes, but if the value being dealt with * is a word, then the opcode in generic_inst is * changed to ldw/stw(4 byte load/stores) */ GTM64_ONLY( if (sa_class_sizes[opr->oprclass] == 4) { next_ptr_offset = 4; REVERT_GENERICINST_TO_WORD(generic_inst); } ) emit_base_offset(GTM_REG_FRAME_TMP_PTR, offset); break; case TCAD_REF: case TVAD_REF: case TVAR_REF: offset = sa_temps_offset[opr->oprclass]; offset -= (sa_temps[opr->oprclass] - opr->oprval.temp) * sa_class_sizes[opr->oprclass]; if (val_output) { memcpy(obpt, &vdat_def[0], VDAT_DEF_SIZE); obpt += VDAT_DEF_SIZE; } if (offset < 127) { memcpy(obpt, &vdat_bdisp[0], VDAT_BDISP_SIZE); obpt += VDAT_BDISP_SIZE; } else { memcpy(obpt, &vdat_wdisp[0], VDAT_WDISP_SIZE); obpt += VDAT_WDISP_SIZE; } obpt = i2asc((uchar_ptr_t)obpt, offset); if (opr->oprclass == TVAR_REF) { memcpy(obpt, &vdat_r8[0], VDAT_R8_SIZE); obpt += VDAT_R8_SIZE; } else { memcpy(obpt, &vdat_r9[0], VDAT_R9_SIZE); obpt += VDAT_R9_SIZE; } NON_GTM64_ONLY( if (offset < 0 || offset > MAX_OFFSET) GTMASSERT; ) if (opr->oprclass == TVAR_REF) reg = GTM_REG_FRAME_VAR_PTR; else reg = GTM_REG_FRAME_TMP_PTR; GTM64_ONLY( if (sa_class_sizes[opr->oprclass] == 4) { next_ptr_offset = 4; REVERT_GENERICINST_TO_WORD(generic_inst); } ) emit_base_offset(reg, offset); if (val_output) /* indirection */ { if (GENERIC_OPCODE_LDA == generic_inst) { RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_NATIVE_REG(trg_reg);) NON_RISC_ONLY(IGEN_LOAD_NATIVE_REG(trg_reg)) if (opr->oprclass == TVAR_REF) { emit_base_offset(trg_reg, offsetof(ht_ent_mname, value)); NON_RISC_ONLY(IGEN_LOAD_NATIVE_REG(trg_reg)) RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_NATIVE_REG(trg_reg);) } inst_emitted = TRUE; } else { RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_NATIVE_REG(GTM_REG_CODEGEN_TEMP);) NON_RISC_ONLY(IGEN_LOAD_NATIVE_REG(GTM_REG_CODEGEN_TEMP)) emit_base_offset(GTM_REG_CODEGEN_TEMP, 0); } } break; case OCNT_REF: immediate = opr->oprval.offset; assert(0 < immediate); assert(MAX_BRANCH_CODEGEN_SIZE > immediate); EMIT_TRIP_ILIT_GEN; inst_emitted = TRUE; ocnt_ref_seen = TRUE; ocnt_ref_opr = opr; break; default: GTMASSERT; break; } if (!inst_emitted) { RISC_ONLY(code_buf[code_idx++] |= IGEN_GENERIC_REG(generic_inst, trg_reg);) NON_RISC_ONLY(IGEN_GENERIC_REG(generic_inst, trg_reg)) } *obpt++ = ','; *obpt++ = ' '; break; # endif case CGP_MACHINE: switch (opr->oprclass) { case TRIP_REF: assert(ct->destination.oprclass == 0); assert(val_output); switch (ct->opcode) { case OC_LIT: assert(ct->operand[0].oprclass == MLIT_REF); offset = literal_offset(ct->operand[0].oprval.mlit->rt_addr); if (run_time) reg = GTM_REG_PV; else reg = GTM_REG_LITERAL_BASE; X86_64_ONLY(force_32 = TRUE;) emit_base_offset(reg, offset); X86_64_ONLY(force_32 = FALSE;) RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_ADDR_REG(trg_reg);) NON_RISC_ONLY(IGEN_LOAD_ADDR_REG(trg_reg);) inst_emitted = TRUE; break; case OC_CDLIT: emit_base_offset(GTM_REG_PV, find_linkage(ct->operand[0].oprval.cdlt)); if (GENERIC_OPCODE_LDA == generic_inst) { RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_LINKAGE(trg_reg);) NON_RISC_ONLY(IGEN_LOAD_LINKAGE(trg_reg);) inst_emitted = TRUE; } else { RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_LINKAGE(GTM_REG_CODEGEN_TEMP);) NON_RISC_ONLY(IGEN_LOAD_LINKAGE(GTM_REG_CODEGEN_TEMP);) emit_base_offset(GTM_REG_CODEGEN_TEMP, 0); } break; case OC_ILIT: assert(GENERIC_OPCODE_LOAD == generic_inst); immediate = ct->operand[0].oprval.ilit; EMIT_TRIP_ILIT_GEN; inst_emitted = TRUE; break; case OC_TRIPSIZE: immediate = ct->operand[0].oprval.tsize->size; # if !defined(__osf__) && !defined(__hppa) /* Legitimate but odd call to next M line on Tru64 and HPUX-HPPA gives an * immediate value of zero because of how offsets are calculated on * these platforms so bypass the assert for them. */ assert(0 < immediate); # endif assert(MAX_BRANCH_CODEGEN_SIZE > immediate); EMIT_TRIP_ILIT_GEN; inst_emitted = TRUE; break; default: GTMASSERT; break; } break; case TINT_REF: case TVAL_REF: assert(val_output); offset = sa_temps_offset[opr->oprclass]; offset -= (sa_temps[opr->oprclass] - opr->oprval.temp) * sa_class_sizes[opr->oprclass]; GTM64_ONLY( if ( sa_class_sizes[opr->oprclass] == 4 ) { next_ptr_offset = 4; REVERT_GENERICINST_TO_WORD(generic_inst); } ) NON_GTM64_ONLY( if (offset < 0 || offset > MAX_OFFSET) GTMASSERT; ) emit_base_offset(GTM_REG_FRAME_TMP_PTR, offset); break; case TCAD_REF: case TVAD_REF: case TVAR_REF: offset = sa_temps_offset[opr->oprclass]; offset -= (sa_temps[opr->oprclass] - opr->oprval.temp) * sa_class_sizes[opr->oprclass]; GTM64_ONLY( if (sa_class_sizes[opr->oprclass] == 4) { next_ptr_offset = 4; REVERT_GENERICINST_TO_WORD(generic_inst); } ) NON_GTM64_ONLY( if (offset < 0 || offset > MAX_OFFSET) GTMASSERT; ) if (opr->oprclass == TVAR_REF) reg = GTM_REG_FRAME_VAR_PTR; else reg = GTM_REG_FRAME_TMP_PTR; emit_base_offset(reg, offset); if (val_output) /* indirection */ { if (GENERIC_OPCODE_LDA == generic_inst) { RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_NATIVE_REG(trg_reg);) NON_RISC_ONLY(IGEN_LOAD_NATIVE_REG(trg_reg)) if (opr->oprclass == TVAR_REF) { emit_base_offset(trg_reg, offsetof(ht_ent_mname, value)); NON_RISC_ONLY(IGEN_LOAD_NATIVE_REG(trg_reg)) RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_NATIVE_REG(trg_reg);) } inst_emitted = TRUE; } else { RISC_ONLY(code_buf[code_idx++] |= IGEN_LOAD_NATIVE_REG(GTM_REG_CODEGEN_TEMP);) NON_RISC_ONLY(IGEN_LOAD_NATIVE_REG(GTM_REG_CODEGEN_TEMP);) emit_base_offset(GTM_REG_CODEGEN_TEMP, 0); } } break; case OCNT_REF: immediate = opr->oprval.offset; assert(0 <= immediate); assert(MAX_BRANCH_CODEGEN_SIZE > immediate); EMIT_TRIP_ILIT_GEN; inst_emitted = TRUE; ocnt_ref_seen = TRUE; ocnt_ref_opr = opr; break; default: GTMASSERT; break; } /* If we haven't emitted a finished instruction already, finish it now */ if (!inst_emitted) { RISC_ONLY(code_buf[code_idx++] |= IGEN_GENERIC_REG(generic_inst, trg_reg);) NON_RISC_ONLY(IGEN_GENERIC_REG(generic_inst, trg_reg)) } break; default: GTMASSERT; break; } } /* get_arg_reg * * Determines the argument position of the current argument and returns the number of the register to use for the * value of the argument. If it's not one of the arguments passed in machine registers, get_arg_reg defaults to the * accumulator emulator register. * * NOTE: because shrink_jmps does not always process emulated VAX instructions that generate arguments, it is crucial * that get_arg_reg() and emit_push() predict the same number of instructions during the CGP_APPROX_ADDR phase as are * actually generated during subsequent phases. In order to ensure this, they emulate instruction generation backwards * during the CGP_APPROX_ADDR and CGP_ADDR_OPT phases relative to the other phases. For example: * * CGP_APPROX_ADDR and CGP_ADDR_OPT phases: * arg1 <- first argument, . . ., argN <- N th argument * if more than N, series of: * LOAD GTM_REG_ACCUM, next argument * STORE GTM_REG_ACCUM, STACK_WORD_SIZE*(i-N)(sp) * * other phases: * if more than N, series of: * LOAD GTM_REG_ACCUM, next argument * STORE GTM_REG_ACCUM, STACK_WORD_SIZE*(i-N)(sp) * argN <- N th argument, . . ., arg1 <- first argument * where STACK_WORD_SIZE is 8(Alpha) or 4(other platforms). * * While this technique correctly predicts the number of arguments, it does not guarantee to start any of the * individual argument instruction sequences, except the first, during the CGP_APPROX_ADDR phase at the same * code_reference address as it will for subsequent phases. This is because, although it predicts (or should) * the same number of instructions during the CGP_APPROX_ADDR phase for an overall sequence of argument pushes, * it does not do so in the same order as subsequent phases. Because we do not use PC-relative addressing for * data on this platform, this difference should be benign (the subsequent xfer table call should be synchronized * with respect to code_reference address across all phases). */ int get_arg_reg(void) { int arg_reg_i; switch (cg_phase) { case CGP_APPROX_ADDR: case CGP_ADDR_OPT: if (vax_pushes_seen < MACHINE_REG_ARGS) arg_reg_i = GET_ARG_REG(vax_pushes_seen); else arg_reg_i = GTM_REG_ACCUM; break; case CGP_ASSEMBLY: case CGP_MACHINE: if (vax_pushes_seen == 0) /* first push of a series */ vax_number_of_arguments = next_vax_push_list(); if (vax_number_of_arguments <= MACHINE_REG_ARGS) arg_reg_i = GET_ARG_REG(vax_number_of_arguments - 1); else arg_reg_i = GTM_REG_ACCUM; break; default: GTMASSERT; break; } return arg_reg_i; } /* VAX reg to local machine reg */ int gtm_reg(int vax_reg) { int reg; switch (vax_reg & 0x0f) /* mask out VAX register mode field */ { case 0: reg = GTM_REG_R0; break; case 1: reg = GTM_REG_R1; break; case 8: reg = GTM_REG_FRAME_VAR_PTR; break; case 9: reg = GTM_REG_FRAME_TMP_PTR; break; # ifdef TRUTH_IN_REG case 10: /* The value of $TEST is maintained in r10 for the VAX GT.M * implementation. On platforms with an insufficient number of * non-volatile (saved) registers, the value of $TEST is maintained * only in memory; when sufficient registers are available, though, * we keep $TEST in one of them. */ reg = GTM_REG_DOLLAR_TRUTH; break; # endif case 11: reg = GTM_REG_XFER_TABLE; break; case 12: reg = GTM_REG_FRAME_POINTER; break; /* VMS ap */ default: GTMASSERT; break; } return reg; } void emit_push(int reg) { int arg_reg_i; int stack_offset; switch (cg_phase) { case CGP_APPROX_ADDR: case CGP_ADDR_OPT: if (vax_pushes_seen >= MACHINE_REG_ARGS) { RISC_ONLY(code_idx++;) /* for STORE instruction */ NON_RISC_ONLY( assert(reg == GTM_REG_ACCUM); stack_offset = STACK_ARG_OFFSET((vax_number_of_arguments - MACHINE_REG_ARGS - 1)); GEN_STORE_ARG(reg, stack_offset); /* Store arg on stack */ ) } break; case CGP_ASSEMBLY: case CGP_MACHINE: if (vax_number_of_arguments <= MACHINE_REG_ARGS) assert(reg == GET_ARG_REG(vax_number_of_arguments - 1)); else { assert(reg == GTM_REG_ACCUM); stack_offset = STACK_ARG_OFFSET((vax_number_of_arguments - MACHINE_REG_ARGS - 1)); GEN_STORE_ARG(reg, stack_offset); /* Store arg on stack */ } break; default: GTMASSERT; break; } if (cg_phase == CGP_MACHINE || cg_phase == CGP_ASSEMBLY) { vax_number_of_arguments--; /* actually, it's the number of arguments remaining */ assert(vax_number_of_arguments >= 0); } vax_pushes_seen++; stack_depth++; return; } void emit_pop(int count) { int stack_adjust; assert(stack_depth >= count); stack_depth -= count; /* It's possible we lost count after a jsb (see VXI_JSB). */ if (stack_depth < 0) stack_depth = 0; return; } void add_to_vax_push_list(int pushes_seen) { /* Make sure there's enough room */ if (pushes_seen > MAX_ARGS) /* user-visible max args is MAX_ARGS - 3 */ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MAXARGCNT, 1, MAX_ARGS - 3); push_list_index++; if (push_list_index >= PUSH_LIST_SIZE) { push_list_index = 0; if (current_push_list_ptr->next == 0 ) { current_push_list_ptr->next = (struct push_list *)malloc(SIZEOF(*current_push_list_ptr)); current_push_list_ptr->next->next = 0; } current_push_list_ptr = current_push_list_ptr->next; } current_push_list_ptr->value[push_list_index] = pushes_seen; } int next_vax_push_list(void) { push_list_index++; if (push_list_index >= PUSH_LIST_SIZE) { push_list_index=0; if (current_push_list_ptr->next == 0 ) GTMASSERT; current_push_list_ptr = current_push_list_ptr->next; } return (current_push_list_ptr->value[push_list_index]); } void push_list_init(void) { push_list_index = -1; if (push_list_start_ptr == 0) { push_list_start_ptr = (struct push_list *)malloc(SIZEOF(*current_push_list_ptr)); push_list_start_ptr->next = 0; } current_push_list_ptr = push_list_start_ptr; } void reset_push_list_ptr(void) { push_list_index = -1; current_push_list_ptr = push_list_start_ptr; } void emit_call_xfer(int xfer) { int offset; unsigned char *c; # ifdef DEBUG if (CGP_ASSEMBLY == cg_phase) { memcpy(obpt, &vdat_def[0], VDAT_DEF_SIZE); obpt += VDAT_DEF_SIZE; if (xfer < 127) { memcpy(obpt, &vdat_bdisp[0], VDAT_BDISP_SIZE); obpt += VDAT_BDISP_SIZE; } else { memcpy(obpt, &vdat_wdisp[0], VDAT_WDISP_SIZE); obpt += VDAT_WDISP_SIZE; } offset = (int)(xfer / SIZEOF(char *)); for (c = (unsigned char *)xfer_name[offset]; *c ; ) *obpt++ = *c++; memcpy(obpt, &vdat_r11[0], VDAT_R11_SIZE); obpt += VDAT_R11_SIZE; *obpt++ = ','; *obpt++ = ' '; } # endif assert(0 == (xfer & 0x3)); offset = (int)(xfer / SIZEOF(char *)); # ifdef __x86_64__ /* Set RAX to 0 for variable argument function calls. This is part of the ABI. * The RAX represents the # of floating of values being passed */ if (GTM_C_VAR_ARGS_RTN == xfer_table_desc[offset]) { GEN_LOAD_IMMED(I386_REG_RAX, 0); } # endif /* __x86_64__ */ # ifdef __ia64 if (GTM_ASM_RTN == xfer_table_desc[offset]) { GEN_XFER_TBL_CALL_FAKE(xfer); } else { GEN_XFER_TBL_CALL_DIRECT(xfer); } # else GEN_XFER_TBL_CALL(xfer); # endif /* __ia64 */ /* In the normal case we will return */ if (!ocnt_ref_seen) return; /* fast test for return .. we hope */ /* If ocnt_ref_seen is set, then we need to compute the value to be used by a recent OCNT_REF parameter. This parameter is (currently as of 6/2003) used by op_call, op_callsp, op_forlcldo, and their mprof counterparts and is the number of bytes those entry points should add to the return address that they will store as the return point in the new stack frame that they create. This parameter is basically the size of the generated code for the jump that follows the call to the above routines that is generates by the associated triples OC_CALL, OC_CALLSP, and OC_FORLCLDO respectively. Since this jump can be variable in size and the only other way for these routines to know what form the jump takes is to parse the instructions at run time, this routine in the compiler will calculate that information and allow it to be passed in as a parameter. The OCNT_REF handler in emit_trip() has set the ocnt_ref_seen flag to bring us here. We now calculate the current PC address and subtract it from the PC address of the next triple. */ assert(OC_CALL == current_triple->opcode || OC_CALLSP == current_triple->opcode || OC_FORLCLDO == current_triple->opcode); offset = current_triple->exorder.fl->rtaddr - (code_reference + (code_idx * INST_SIZE)); /* If in assembly or machine (final) phases, make sure have reasonable offset. The offset may be negative in the early phases so don't check during them. For other phases, put a govenor on the values so we don't affect the codegen sizes which can mess up shrink_trips. During the triple shrink phase, the triple distances can vary widely and cause the codegen to change sizes. Note this still allows an assert fail for 0 if a negative number was being produced. */ if (CGP_MACHINE == cg_phase || CGP_ASSEMBLY == cg_phase) { assert(0 <= offset && MAX_BRANCH_CODEGEN_SIZE > offset); } else offset = MAX(0, MIN(128, offset)); ocnt_ref_opr->oprval.offset = offset; ocnt_ref_seen = FALSE; } fis-gtm-V6.0-003/sr_port/emit_code.h0000644000032200000250000000354212201176176016142 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef EMIT_CODE_INCLUDED #define EMIT_CODE_INCLUDED #include #ifdef DEBUG void emit_asmlist(triple *ct); void emit_eoi(void); #endif void trip_gen(triple *ct); short *emit_vax_inst(short *inst, oprtype **fst_opr, oprtype **lst_opr); void emit_jmp(uint4 branchop, short **instp, int reg); void emit_pcrel(void); void emit_trip(oprtype *opr, boolean_t val_output, uint4 alpha_inst, int ra_reg); void emit_push(int reg); void emit_pop(int count); void add_to_vax_push_list(int pushes_seen); int next_vax_push_list(void); void push_list_init(void); void reset_push_list_ptr(void); void emit_call_xfer(int xfer); int get_arg_reg(void); int gtm_reg(int vax_reg); #ifdef __x86_64__ # define NUM_BUFFERRED_INSTRUCTIONS 100 # define CODE_TYPE char #elif defined(__ia64) # define CODE_TYPE ia64_bundle # define NUM_BUFFERRED_INSTRUCTIONS 25 #elif defined(__MVS__) || defined(Linux390) # define CODE_TYPE uint2 # define NUM_BUFFERRED_INSTRUCTIONS 100 #else # define CODE_TYPE uint4 # define NUM_BUFFERRED_INSTRUCTIONS 25 #endif #define ASM_OUT_BUFF 256 #define PUSH_LIST_SIZE 500 #if defined(__vms) || defined(_AIX) || defined(__sparc) || defined(__hpux) || (defined(__linux__) && defined(__ia64)) \ || defined(__MVS__) # define TRUTH_IN_REG #elif defined(__osf__) || (defined(__linux__) && defined(__x86_64__)) || defined(Linux390) # undef TRUTH_IN_REG #else # error UNSUPPORTED PLATFORM #endif #endif fis-gtm-V6.0-003/sr_port/entryref.c0000644000032200000250000001513312201176176016042 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" #include "mlabel2xtern.h" #include "mrout2xtern.h" #include "gtmimagename.h" #include #include "stack_frame.h" GBLREF stack_frame *frame_pointer; GBLREF mident routine_name; error_def(ERR_LABELEXPECTED); error_def(ERR_RTNNAME); triple *entryref(opctype op1, opctype op2, mint commargcode, boolean_t can_commarg, boolean_t labref, boolean_t textname) { oprtype offset, label, routine, rte1; char rtn_text[SIZEOF(mident_fixed)], lab_text[SIZEOF(mident_fixed)]; mident rtnname, labname; mstr rtn_str, lbl_str; triple *ref, *next, *rettrip; boolean_t same_rout; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; rtnname.len = labname.len = 0; rtnname.addr = &rtn_text[0]; labname.addr = &lab_text[0]; /* These cases don't currently exist but if they start to exist, the code in this * routine needs to be revisited for proper operation as the textname conditions * were assumed not to happen if can_commarg was FALSE (which it is in the one * known use of textname TRUE - in m_zgoto). */ assert(!(can_commarg && textname)); switch (TREF(window_token)) { case TK_INTLIT: int_label(); /* caution: fall through */ case TK_IDENT: memcpy(labname.addr, (TREF(window_ident)).addr, (TREF(window_ident)).len); labname.len = (TREF(window_ident)).len; advancewindow(); if ((TK_PLUS != TREF(window_token)) && (TK_CIRCUMFLEX != TREF(window_token)) && !IS_MCODE_RUNNING && can_commarg) { rettrip = newtriple(op1); rettrip->operand[0] = put_mlab(&labname); return rettrip; } label.oprclass = NO_REF; break; case TK_ATSIGN: if(!indirection(&label)) return NULL; if ((TK_PLUS != TREF(window_token)) && (TK_CIRCUMFLEX != TREF(window_token)) && (TK_COLON != TREF(window_token)) && can_commarg) { rettrip = ref = maketriple(OC_COMMARG); ref->operand[0] = label; ref->operand[1] = put_ilit(commargcode); ins_triple(ref); return rettrip; } labname.len = 0; break; case TK_PLUS: stx_error(ERR_LABELEXPECTED); return NULL; default: labname.len = 0; label.oprclass = NO_REF; break; } if (!labref && (TK_PLUS == TREF(window_token))) { /* Have line offset specified */ advancewindow(); if (EXPR_FAIL == expr(&offset, MUMPS_INT)) return NULL; } else offset.oprclass = NO_REF; if (TK_CIRCUMFLEX == TREF(window_token)) { /* Have a routine name specified */ advancewindow(); switch (TREF(window_token)) { case TK_IDENT: MROUT2XTERN((TREF(window_ident)).addr, rtnname.addr, (TREF(window_ident)).len); rtn_str.len = rtnname.len = (TREF(window_ident)).len; rtn_str.addr = rtnname.addr; advancewindow(); if (!IS_MCODE_RUNNING) { /* Triples for indirect code */ same_rout = (MIDENT_EQ(&rtnname, &routine_name) && can_commarg); if (!textname) { /* Resolve routine and label names to addresses for most calls */ if (!label.oprclass && !offset.oprclass) { /* Routine only (no label or offset) */ if (same_rout) { rettrip = newtriple(op1); rettrip->operand[0] = put_mlab(&labname); } else { rettrip = maketriple(op2); if (rtnname.addr[0] == '%') rtnname.addr[0] = '_'; rettrip->operand[0] = put_cdlt(&rtn_str); mlabel2xtern(&lbl_str, &rtnname, &labname); rettrip->operand[1] = put_cdlt(&lbl_str); ins_triple(rettrip); } return rettrip; } else if (!same_rout) { rte1 = put_str(rtn_str.addr, rtn_str.len); if (rtnname.addr[0] == '%') rtnname.addr[0] = '_'; routine = put_cdlt(&rtn_str); ref = newtriple(OC_RHDADDR); ref->operand[0] = rte1; ref->operand[1] = routine; routine = put_tref(ref); } else routine = put_tref(newtriple(OC_CURRHD)); } else { /* Return the actual names used */ if (!label.oprclass && !offset.oprclass) { /* Routine only (no label or offset) */ rettrip = maketriple(op2); rettrip->operand[0] = put_str(rtn_str.addr, rtn_str.len); ref = newtriple(OC_PARAMETER); ref->operand[0] = put_str(labname.addr, labname.len); ref->operand[1] = put_ilit(0); rettrip->operand[1] = put_tref(ref); ins_triple(rettrip); return rettrip; } else routine = put_str(rtn_str.addr, rtn_str.len); } } else { /* Triples for normal compiled code */ routine = put_str(rtn_str.addr, rtn_str.len); if (!textname) { /* If not returning text name, convert text name to routine header address */ ref = newtriple(OC_RHDADDR1); ref->operand[0] = routine; routine = put_tref(ref); } } break; case TK_ATSIGN: if (!indirection(&routine)) return NULL; if (!textname) { /* If not returning text name, convert text name to routine header address */ ref = newtriple(OC_RHDADDR1); ref->operand[0] = routine; routine = put_tref(ref); } break; default: stx_error(ERR_RTNNAME); return NULL; } } else { if (!label.oprclass && (0 == labname.len)) { stx_error(ERR_LABELEXPECTED); return NULL; } if (!textname) routine = put_tref(newtriple(OC_CURRHD)); else { /* If we need a name, the mechanism to retrieve it differs between normal and indirect compilation */ if (!IS_MCODE_RUNNING) /* For normal compile, use routine name set when started compile */ routine = put_str(routine_name.addr, routine_name.len); else /* For an indirect compile, obtain the currently running routine header and pull the routine * name out of that. */ routine = put_str(frame_pointer->rvector->routine_name.addr, frame_pointer->rvector->routine_name.len); } } if (!offset.oprclass) offset = put_ilit(0); if (!label.oprclass) label = put_str(labname.addr, labname.len); ref = textname ? newtriple(OC_PARAMETER) : newtriple(OC_LABADDR); ref->operand[0] = label; next = newtriple(OC_PARAMETER); ref->operand[1] = put_tref(next); next->operand[0] = offset; if (!textname) next->operand[1] = routine; /* Not needed if giving text names */ rettrip = next = newtriple(op2); next->operand[0] = routine; next->operand[1] = put_tref(ref); return rettrip; } fis-gtm-V6.0-003/sr_port/err_check.c0000644000032200000250000000371612201176155016132 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "error.h" VMS_ONLY(LITREF)UNIX_ONLY(GBLREF) err_ctl merrors_ctl; VMS_ONLY(LITREF)UNIX_ONLY(GBLREF) err_ctl cmerrors_ctl; VMS_ONLY(LITREF)UNIX_ONLY(GBLREF) err_ctl cmierrors_ctl; VMS_ONLY(LITREF)UNIX_ONLY(GBLREF) err_ctl gdeerrors_ctl; #ifdef VMS LITREF err_ctl laerrors_ctl; /* Roger thinks that this one is obsolete */ LITREF err_ctl lperrors_ctl; /* Roger thinks that this one may be obsolete */ #endif STATICDEF const err_ctl *all_errors[] = { &merrors_ctl, &gdeerrors_ctl, &cmierrors_ctl, &cmerrors_ctl, #ifdef VMS &laerrors_ctl, &lperrors_ctl, #endif NULL }; /* Returns the error control struct corresponding to the errornum if it is valid, otherwise * returns NULL */ const err_ctl *err_check(int errnum) { /* errnum structure: * ___________________________________________ * | 1 FACILITY 1 MSG_IDX SEV| * |___________________________________________| * 31 27 15 3 0 * */ const err_ctl *fac; int errtype; int msg_id; /* Error message number once facility and severity are stripped */ if (0 > errnum) return NULL ; for (errtype = 0; all_errors[errtype]; errtype++) { fac = all_errors[errtype]; msg_id = MSGMASK(errnum, fac->facnum); /* These conditions ensure: The facility bits are identical, the message index * doesn't exceed the array size and is larger than zero */ if (((errnum >> MSGFAC) == (FACMASK(fac->facnum) >> MSGFAC)) && (msg_id <= fac->msg_cnt) && (1 <= msg_id)) return fac; } return NULL ; } fis-gtm-V6.0-003/sr_port/error.h0000644000032200000250000000640312201176155015337 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __ERROR_H__ #define __ERROR_H__ typedef struct err_msg_struct { char *tag; char *msg; int parm_count; } err_msg; typedef struct err_ctl_struct { int facnum; char *facname; const err_msg *fst_msg; /* For VMS, this pointer is not used, and its value will typically be NULL */ int msg_cnt; } err_ctl; #include "errorsp.h" #define ERROR_RETURN error_return #define FCNTL 1 #define MSGCNTL 27 #define MSGFAC 16 #define MSGNBIT 15 #define MSGSEVERITY 3 #define MSGNUM 3 #define FACMASK(fac) (FCNTL << MSGCNTL | 1 << MSGNBIT | (fac) << MSGFAC) #define MSGMASK(msg,fac) (((msg) & ~FACMASK(fac)) >> MSGSEVERITY) #define SEVMASK(msg) ((msg) & 7) /* to change default severity of msg to type */ #define MAKE_MSG_TYPE(msg, type) ((msg) & ~SEV_MSK | (type)) /* Macro used intermittently to trace various error handling invocations */ /* #define DEBUG_ERRHND */ #ifdef DEBUG_ERRHND # define DBGEHND(x) DBGFPF(x) # define DBGEHND_ONLY(x) x # include "gtm_stdio.h" # include "gtmio.h" #else # define DBGEHND(x) # define DBGEHND_ONLY(x) #endif const err_ctl *err_check(int err); CONDITION_HANDLER(ccp_ch); CONDITION_HANDLER(ccp_exi_ch); CONDITION_HANDLER(compiler_ch); CONDITION_HANDLER(cre_priv_ch); CONDITION_HANDLER(dbinit_ch); CONDITION_HANDLER(dse_dmp_handler); CONDITION_HANDLER(dse_f_blk_ch); CONDITION_HANDLER(exi_ch); CONDITION_HANDLER(fgncal_ch); CONDITION_HANDLER(fntext_ch); CONDITION_HANDLER(gds_rundown_ch); CONDITION_HANDLER(gtcm_ch); CONDITION_HANDLER(gtcm_exi_ch); CONDITION_HANDLER(gtm_env_xlate_ch); CONDITION_HANDLER(gtm_maxstr_ch); CONDITION_HANDLER(gtmrecv_ch); CONDITION_HANDLER(gtmrecv_fetchresync_ch); CONDITION_HANDLER(gtmsource_ch); CONDITION_HANDLER(gvcmy_open_ch); CONDITION_HANDLER(gvcmz_netopen_ch); CONDITION_HANDLER(gvzwrite_ch); CONDITION_HANDLER(hashtab_rehash_ch); CONDITION_HANDLER(io_init_ch); CONDITION_HANDLER(iob_io_error); CONDITION_HANDLER(iomt_ch); CONDITION_HANDLER(jnl_file_autoswitch_ch); CONDITION_HANDLER(job_init_ch); CONDITION_HANDLER(jobexam_dump_ch); CONDITION_HANDLER(lastchance1); CONDITION_HANDLER(lastchance2); CONDITION_HANDLER(lastchance3); CONDITION_HANDLER(mdb_condition_handler); CONDITION_HANDLER(mu_freeze_ch); CONDITION_HANDLER(mu_int_ch); CONDITION_HANDLER(mu_int_reg_ch); CONDITION_HANDLER(mu_rndwn_file_ch); CONDITION_HANDLER(mupip_load_ch); CONDITION_HANDLER(mupip_recover_ch); CONDITION_HANDLER(mupip_set_jnl_ch); CONDITION_HANDLER(mur_multi_rehash_ch); CONDITION_HANDLER(ojch); CONDITION_HANDLER(region_init_ch); CONDITION_HANDLER(replication_ch); CONDITION_HANDLER(stp_gcol_ch); CONDITION_HANDLER(t_ch); CONDITION_HANDLER(terminate_ch); CONDITION_HANDLER(tp_restart_ch); CONDITION_HANDLER(trans_code_ch); CONDITION_HANDLER(updproc_ch); CONDITION_HANDLER(util_base_ch); CONDITION_HANDLER(util_ch); CONDITION_HANDLER(zshow_ch); CONDITION_HANDLER(zyerr_ch); void mum_tstart(); #endif fis-gtm-V6.0-003/sr_port/error_trap.h0000644000032200000250000001512412201176155016365 0ustar librarygtc/**************************************************************** * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef ERROR_TRAP_H #define ERROR_TRAP_H #define IS_ETRAP (err_act == &dollar_etrap.str) #define ETRAP_IN_EFFECT (!ztrap_explicit_null && (0 == dollar_ztrap.str.len)) #define DOLLAR_ECODE_MAXINDEX 32 /* maximum of 32 ecodes in $ECODE */ #define DOLLAR_STACK_MAXINDEX 256 /* maximum of 256 levels will be stored for $STACK(level) */ #define DOLLAR_ECODE_ALLOC (1 << 15) /* 32K chunk memory malloced for $ECODE */ #define DOLLAR_STACK_ALLOC (1 << 15) /* 32K chunk memory malloced for $STACK(level) */ #define STACK_ZTRAP_EXPLICIT_NULL -1 /* used to indicate an explicit SET $ZTRAP = "" */ typedef void (*error_ret_fnptr)(void); typedef struct dollar_ecode { mstr ecode_str; } dollar_ecode_struct; typedef struct dollar_stack /* contents of a single $STACK(level) entry */ { mstr mode_str; /* $STACK(level) */ dollar_ecode_struct *ecode_ptr; /* $STACK(level,"ECODE") */ mstr mcode_str; /* $STACK(level,"MCODE") */ mstr place_str; /* $STACK(level,"PLACE") */ } dollar_stack_struct; typedef enum stack_mode { DOLLAR_STACK_INVALID, DOLLAR_STACK_ECODE, /* $STACK(level,"ECODE") */ DOLLAR_STACK_PLACE, /* $STACK(level,"PLACE") */ DOLLAR_STACK_MCODE, /* $STACK(level,"MCODE") */ DOLLAR_STACK_MODE /* $STACK(level) i.e. how this frame got created */ } stack_mode_t; typedef struct { char *begin; /* beginning of malloced memory holding the complete $ECODE */ char *end; /* pointer to where next $ECODE can be added */ char *top; /* allocated end of malloced memory holding the complete $ECODE */ dollar_ecode_struct *array; /* array of DOLLAR_ECODE_MAXINDEX dollar_ecode_struct structures */ uint4 index; /* current count of number of filled structures in array */ int4 error_last_ecode; /* last error code number */ unsigned char *error_last_b_line; /* ptr to beginning of line where error occurred */ struct stack_frame_struct *first_ecode_error_frame; /* "frame_pointer" at the time of adding the first ECODE */ unsigned char *error_rtn_addr; /* CODE_ADDRESS(ERROR_RTN) */ unsigned char *error_rtn_ctxt; /* GTM_CONTEXT(ERROR_RTN) */ error_ret_fnptr error_return_addr; /* CODE_ADDRESS(ERROR_RETURN) */ } dollar_ecode_type; typedef struct { char *begin; /* beginning of malloced memory holding all $STACK(level) detail */ char *end; /* pointer to where next $STACK(level) detail can be added */ char *top; /* allocated end of malloced memory holding all $STACK(level) detail */ dollar_stack_struct *array; /* array of DOLLAR_STACK_MAXINDEX dollar_stack_struct structures */ uint4 index; /* current count of number of filled structures in array */ boolean_t incomplete; /* TRUE if we were not able to fit in all $STACK info */ } dollar_stack_type; /* reset all $ECODE related variables to correspond to $ECODE = NULL state */ #define NULLIFY_DOLLAR_ECODE \ { \ GBLREF dollar_ecode_type dollar_ecode; \ GBLREF dollar_stack_type dollar_stack; \ \ dollar_ecode.end = dollar_ecode.begin; \ dollar_ecode.index = 0; \ dollar_stack.end = dollar_stack.begin; \ dollar_stack.index = 0; \ dollar_stack.incomplete = FALSE; \ dollar_ecode.first_ecode_error_frame = NULL; \ } /* nullify "error_frame" */ #define NULLIFY_ERROR_FRAME \ { \ GBLREF stack_frame *error_frame; \ \ DBGEHND((stderr, "%s: Nullifying previous error_frame (was 0x"lvaddr")\n", __FILE__, error_frame)); \ error_frame = NULL; \ } /* Set "error_frame" to point to "frame_pointer" and mark it as an error frame type. This is an indication that * whenever we unwind back to this frame, we need to transfer control to error_rtn_addr/ctxt (taken care of by getframe). */ #define SET_ERROR_FRAME(fp) \ { \ GBLREF stack_frame *error_frame; \ \ fp->flags |= SFF_ETRAP_ERR; \ error_frame = fp; \ DBGEHND((stderr, "%s: Setting error_frame as 0x"lvaddr"\n", __FILE__, fp)); \ } /* invoke the function error_return() if the necessity of error-rethrow is detected. Note the extra * "&" value on the various assert(FALSE) type statements. This allows us to know which of these asserts * failed. */ #define INVOKE_ERROR_RET_IF_NEEDED \ { \ GBLREF dollar_ecode_type dollar_ecode; \ GBLREF stack_frame *error_frame; \ \ if (NULL != error_frame) \ { \ if (error_frame == frame_pointer) \ { \ if (dollar_ecode.index) /* non-zero implies non-NULL $ECODE */ \ { /* this is an error frame and $ECODE is non-NULL during QUIT out of this frame. \ * rethrow the error at lower level */ \ (*dollar_ecode.error_return_addr)(); \ /* While error_return does not usually return in UNIX, it can if we are \ * unwinding a job-interrupt frame because error rethrowing terminates when a \ * job-interrupt frame is unwound which instead of re-throwing in the \ * interrupted frame sends an error to the operator log. But in VMS, we dont \ * do the latter so it is possible if the current frame is of type SFT_DM that \ * we don't rethrow and don't do a MUM_TSTART either. Assert accordingly. \ */ \ VMS_ONLY(assert(SFT_DM & frame_pointer->type);) \ } else \ { \ assert(FALSE & 2); \ NULLIFY_ERROR_FRAME; /* don't know how we reached here. reset it in PRO */ \ } \ } else if (error_frame < frame_pointer) \ { \ assert(FALSE & 3); \ NULLIFY_ERROR_FRAME; /* don't know how we reached here. reset it in PRO */ \ } \ } \ } void ecode_init(void); void ecode_get(int level, mval *result); /* return $ECODE (if "level" < 0) or $STACK(level,"ECODE") in "result" */ void ecode_set(int errnum); /* convert "errnum" to error-string and call ecode_add() */ boolean_t ecode_add(mstr *str); /* add "str" to $ECODE */ void error_return(void); #ifdef VMS void error_return_vms(void); #endif void get_dollar_stack_info(int level, stack_mode_t mode, mval *result); void get_frame_creation_info(int level, int cur_zlevel, mval *result); void get_frame_place_mcode(int level, stack_mode_t mode, int cur_zlevel, mval *result); #endif /* ERROR_TRAP_H */ fis-gtm-V6.0-003/sr_port/eval_expr.c0000644000032200000250000001510512201176155016165 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "mdq.h" #include "toktyp.h" #include "advancewindow.h" #include "compile_pattern.h" #include "fullbool.h" #include "show_source_line.h" GBLREF boolean_t run_time; error_def(ERR_EXPR); error_def(ERR_RHMISSING); error_def(ERR_SIDEEFFECTEVAL); LITREF octabstruct oc_tab[]; LITREF toktabtype tokentable[]; int eval_expr(oprtype *a) { boolean_t ind_pat, saw_local, saw_se, se_warn; int op_count, se_handling; opctype bin_opcode; oprtype optyp_1, optyp_2, *optyp_ptr; tbp *catbp, *tripbp; triple *argtrip, *parm, *ref, *ref1, *t1, *t2; unsigned short type; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (!expratom(&optyp_1)) { /* If didn't already add an error of our own, do so now with catch all expression error */ if (OC_RTERROR != (TREF(curtchain))->exorder.bl->exorder.bl->exorder.bl->opcode) stx_error(ERR_EXPR); return EXPR_FAIL; } se_handling = TREF(side_effect_handling); se_warn = (!run_time && (SE_WARN == se_handling)); while (bin_opcode = tokentable[TREF(window_token)].bo_type) /* NOTE assignment NOT condition */ { type = tokentable[TREF(window_token)].opr_type; if (oc_tab[bin_opcode].octype & OCT_BOOL) { if (!TREF(shift_side_effects)) { assert(FALSE == TREF(saw_side_effect)); for (ref = (TREF(curtchain))->exorder.bl; oc_tab[ref->opcode].octype & OCT_BOOL; ref = ref->exorder.bl) ; TREF(expr_start) = TREF(expr_start_orig) = ref; } switch (bin_opcode) { case OC_NAND: case OC_AND: case OC_NOR: case OC_OR: TREF(shift_side_effects) = TRUE; default: break; } } coerce(&optyp_1, type); if (OC_CAT == bin_opcode) { ref1 = ref = maketriple(OC_CAT); catbp = &ref->backptr; /* borrow backptr to track args */ saw_se = saw_local = FALSE; for (op_count = 2; ; op_count++) /* op_count = first operand plus destination */ { parm = newtriple(OC_PARAMETER); ref1->operand[1] = put_tref(parm); ref1 = parm; ref1->operand[0] = optyp_1; if (se_handling) { /* the following code deals with protecting lvn values from change by a following * side effect and thereby produces a standard evaluation order. It is similar to code in * expritem for function arguments, but has slightly different and easier circumstances */ assert(OLD_SE != TREF(side_effect_handling)); assert(0 < TREF(expr_depth)); t1 = optyp_1.oprval.tref; t2 = (oc_tab[t1->opcode].octype & OCT_COERCE) ? t1->operand[0].oprval.tref : t1; /* need to step back past coerce of side effects in order to detect them */ if (((OC_VAR == t2->opcode) || (OC_GETINDX == t2->opcode)) && (t1 == t2)) saw_local = TRUE; /* left operand is an lvn */ if (saw_local) { if ((TREF(side_effect_base))[TREF(expr_depth)]) saw_se = TRUE; if (saw_se || (OC_VAR == t2->opcode) || (OC_GETINDX == t2->opcode)) { /* chain stores args to manage later insert of temps to hold lvn */ tripbp = &ref1->backptr; assert((tripbp == tripbp->que.fl) && (tripbp == tripbp->que.bl)); tripbp->bpt = ref1; dqins(catbp, que, tripbp); } } } if (TK_UNDERSCORE != TREF(window_token)) { if (!saw_se) /* suppressed standard or lucked out on ordering */ saw_local = FALSE; /* just clear the backptrs - shut off other processing */ dqloop(catbp, que, tripbp) { /* work chained arguments which are in reverse order */ argtrip = tripbp->bpt; assert(NULL != argtrip); dqdel(tripbp, que); tripbp->bpt = NULL; if (!saw_local) continue; /* some need to insert temps */ for (optyp_ptr = &argtrip->operand[0]; INDR_REF == optyp_ptr->oprclass; optyp_ptr = optyp_ptr->oprval.indr) ; /* INDR_REFs used by e.g. extrinsics finally end up at a TRIP_REF */ t1 = optyp_ptr->oprval.tref; if ((OC_VAR == t1->opcode) || (OC_GETINDX == t1->opcode)) { /* have an lvn that needs a temp because threat from some side effect */ argtrip = maketriple(OC_STOTEMP); argtrip->operand[0] = put_tref(t1); dqins(t1, exorder, argtrip); /* NOTE: violates infomation hiding */ optyp_ptr->oprval.tref = argtrip; if (se_warn) ISSUE_SIDEEFFECTEVAL_WARNING(t1->src.column + 1); } } /* end of side effect processing */ assert((catbp == catbp->que.fl) && (catbp == catbp->que.bl) && (NULL == catbp->bpt)); assert(op_count > 1); ref->operand[0] = put_ilit(op_count); ins_triple(ref); break; } advancewindow(); if (!expratom(&optyp_1)) { stx_error(ERR_RHMISSING); return EXPR_FAIL; } coerce(&optyp_1, type); } } else { if ((TK_QUESTION == TREF(window_token)) || (TK_NQUESTION == TREF(window_token))) { ind_pat = FALSE; if (TK_ATSIGN == TREF(director_token)) { ind_pat = TRUE; advancewindow(); } if (!compile_pattern(&optyp_2, ind_pat)) return EXPR_FAIL; } else { advancewindow(); if (!expratom(&optyp_2)) { stx_error(ERR_RHMISSING); return EXPR_FAIL; } } coerce(&optyp_2, type); ref1 = optyp_1.oprval.tref; if (((OC_VAR == ref1->opcode) || (OC_GETINDX == ref1->opcode)) && (TREF(side_effect_base))[TREF(expr_depth)]) { /* this section is to protect lvns from changes by a following side effect extrinsic or function * by inserting a temporary to capture the lvn evaluation before it's changed by a "later" or * "to-the-right" side effect; a preexisting coerce or temporary might already to the job; * indirects may already have been shifted to evaluate early */ assert(OLD_SE != TREF(side_effect_handling)); ref = maketriple(OC_STOTEMP); ref->operand[0] = optyp_1; optyp_1 = put_tref(ref); dqins(ref1, exorder, ref); /* NOTE: another violation of information hiding */ if (se_warn) ISSUE_SIDEEFFECTEVAL_WARNING(ref1->src.column + 1); } ref = newtriple(bin_opcode); ref->operand[0] = optyp_1; ref->operand[1] = optyp_2; } optyp_1 = put_tref(ref); } *a = optyp_1; return (OC_INDGLVN == (TREF(curtchain))->exorder.bl->opcode) ? EXPR_INDR : EXPR_GOOD; } fis-gtm-V6.0-003/sr_port/ex_tail.c0000644000032200000250000000354712201176155015634 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "mdq.h" #include "opcode.h" #include "toktyp.h" #include "mmemory.h" void ex_tail(oprtype *opr) { LITREF octabstruct oc_tab[]; triple *t, *t1, *t2, *bitrip; oprtype *i; opctype c; unsigned short w; assert(TRIP_REF == opr->oprclass); t = opr->oprval.tref; c = t->opcode; w = oc_tab[c].octype; if (w & OCT_EXPRLEAF) return; assert(TRIP_REF == t->operand[0].oprclass); assert((TRIP_REF == t->operand[1].oprclass) || (NO_REF == t->operand[1].oprclass)); if (!(w & OCT_BOOL)) { for (i = t->operand; ARRAYTOP(t->operand) > i; i++) if (TRIP_REF == i->oprclass) ex_tail(i); if ((OC_COMINT == c) && (OC_BOOLINIT == (t1 = t->operand[0].oprval.tref)->opcode)) /* NOTE assignment */ opr->oprval.tref = t1; } else { for (t1 = t; ; t1 = t2) { assert(TRIP_REF == t1->operand[0].oprclass); t2 = t1->operand[0].oprval.tref; if (!(oc_tab[t2->opcode].octype & OCT_BOOL)) break; } bitrip = maketriple(OC_BOOLINIT); dqins(t1->exorder.bl, exorder, bitrip); t2 = t->exorder.fl; assert(&t2->operand[0] == opr); assert((OC_COMVAL == t2->opcode) || (OC_COMINT == t2->opcode)); if (OC_COMINT == t2->opcode) dqdel(t2, exorder); t1 = maketriple(OC_BOOLFINI); t1->operand[0] = put_tref(bitrip); opr->oprval.tref = bitrip; dqins(t, exorder, t1); i = (oprtype *)mcalloc(SIZEOF(oprtype)); bx_tail(t, FALSE, i); *i = put_tnxt(t1); } return; } fis-gtm-V6.0-003/sr_port/exfun_frame.c0000644000032200000250000000461312201176176016504 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #include #include "stack_frame.h" #include "mprof.h" #include "error.h" #include "glvn_pool.h" GBLREF stack_frame *frame_pointer; GBLREF unsigned char *msp, *stackbase, *stackwarn, *stacktop; error_def(ERR_STACKCRIT); error_def(ERR_STACKOFLOW); void exfun_frame (void) { register stack_frame *sf; unsigned char *msp_save; msp_save = msp; sf = (stack_frame *)(msp -= SIZEOF(stack_frame)); /* Note imbedded assignment */ assert(sf < frame_pointer); if (msp <= stackwarn) { if (msp <= stacktop) { msp = msp_save; rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKOFLOW); } else rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKCRIT); } assert (msp < stackbase); assert((frame_pointer < frame_pointer->old_frame_pointer) || (NULL == frame_pointer->old_frame_pointer)); *sf = *frame_pointer; msp -= sf->rvector->temp_size; if (msp <= stackwarn) { if (msp <= stacktop) { msp = msp_save; rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKOFLOW); } else rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKCRIT); } sf->temps_ptr = msp; assert(msp < stackbase); memset(msp, 0, sf->rvector->temp_size); SET_GLVN_INDX(sf, GLVN_POOL_UNTOUCHED); sf->ret_value = NULL; sf->dollar_test = -1; sf->old_frame_pointer = frame_pointer; sf->type &= SFT_ZINTR_OFF; /* Don't propagate special type - normally can't propagate but if $ZINTERRUPT frame is * rewritten by ZGOTO to a "regular" frame, this frame type *can* propagate. */ frame_pointer = sf; assert((frame_pointer < frame_pointer->old_frame_pointer) || (NULL == frame_pointer->old_frame_pointer)); DBGEHND((stderr, "exfun_frame: Added stackframe at addr 0x"lvaddr" old-msp: 0x"lvaddr" new-msp: 0x"lvaddr"\n", sf, msp_save, msp)); return; } void exfun_frame_sp(void) { exfun_frame(); new_prof_frame (TRUE); } void exfun_frame_push_dummy_frame(void) { exfun_frame(); new_prof_frame (FALSE); } fis-gtm-V6.0-003/sr_port/exfunc.c0000644000032200000250000001137412201176155015474 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "mdq.h" #include "advancewindow.h" #define INDIR_DUMMY -1 error_def(ERR_ACTOFFSET); int exfunc(oprtype *a, boolean_t alias_target) { triple *calltrip, *calltrip_opr1_tref, *counttrip, *funret, *labelref, *masktrip; triple *oldchain, *ref0, *routineref, tmpchain, *triptr; # if defined(USHBIN_SUPPORTED) || defined(VMS) triple *tripsize; # endif DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(TK_DOLLAR == TREF(window_token)); advancewindow(); dqinit(&tmpchain, exorder); oldchain = setcurtchain(&tmpchain); calltrip = entryref(OC_EXFUN, OC_EXTEXFUN, INDIR_DUMMY, TRUE, TRUE, FALSE); setcurtchain(oldchain); if (!calltrip) return FALSE; if (OC_EXFUN == calltrip->opcode) { assert(MLAB_REF == calltrip->operand[0].oprclass); # if defined(USHBIN_SUPPORTED) || defined(VMS) ref0 = newtriple(OC_PARAMETER); ref0->operand[0] = put_tsiz(); /* Need size of following code gen triple here */ calltrip->operand[1] = put_tref(ref0); tripsize = ref0->operand[0].oprval.tref; assert(OC_TRIPSIZE == tripsize->opcode); # else ref0 = calltrip; # endif } else { assert(TRIP_REF == calltrip->operand[1].oprclass); calltrip_opr1_tref = calltrip->operand[1].oprval.tref; if (OC_EXTEXFUN == calltrip->opcode) { if (OC_CDLIT == calltrip_opr1_tref->opcode) assert(CDLT_REF == calltrip_opr1_tref->operand[0].oprclass); else { assert(OC_LABADDR == calltrip_opr1_tref->opcode); assert(TRIP_REF == calltrip_opr1_tref->operand[1].oprclass); assert(OC_PARAMETER == calltrip_opr1_tref->operand[1].oprval.tref->opcode); assert(TRIP_REF == calltrip_opr1_tref->operand[1].oprval.tref->operand[0].oprclass); assert(OC_ILIT == calltrip_opr1_tref->operand[1].oprval.tref->operand[0].oprval.tref->opcode); assert(ILIT_REF == calltrip_opr1_tref->operand[1].oprval.tref->operand[0].oprval.tref->operand[0].oprclass); if (0 != calltrip_opr1_tref->operand[1].oprval.tref->operand[0].oprval.tref->operand[0].oprval.ilit) { stx_error(ERR_ACTOFFSET); return FALSE; } } } else /* indirect: $$@(glvn)[(actuallist)]; note disabiguating parens around glvn specifying dlabel*/ { assert(OC_COMMARG == calltrip->opcode); assert(TRIP_REF == calltrip->operand[1].oprclass); assert(OC_ILIT == calltrip_opr1_tref->opcode); assert(ILIT_REF == calltrip_opr1_tref->operand[0].oprclass); assert(INDIR_DUMMY == calltrip_opr1_tref->operand[0].oprval.ilit); assert(calltrip->exorder.fl == &tmpchain); routineref = maketriple(OC_CURRHD); labelref = maketriple(OC_LABADDR); ref0 = maketriple(OC_PARAMETER); dqins(calltrip->exorder.bl, exorder, routineref); dqins(calltrip->exorder.bl, exorder, labelref); dqins(calltrip->exorder.bl, exorder, ref0); labelref->operand[0] = calltrip->operand[0]; labelref->operand[1] = put_tref(ref0); ref0->operand[0] = calltrip->operand[1]; ref0->operand[0].oprval.tref->operand[0].oprval.ilit = 0; ref0->operand[1] = put_tref(routineref); calltrip->operand[0] = put_tref(routineref); calltrip->operand[1] = put_tref(labelref); calltrip->opcode = OC_EXTEXFUN; } ref0 = newtriple(OC_PARAMETER); ref0->operand[0] = calltrip->operand[1]; calltrip->operand[1] = put_tref(ref0); } if (TK_LPAREN != TREF(window_token)) { masktrip = newtriple(OC_PARAMETER); counttrip = newtriple(OC_PARAMETER); masktrip->operand[0] = put_ilit(0); counttrip->operand[0] = put_ilit(0); masktrip->operand[1] = put_tref(counttrip); ref0->operand[1] = put_tref(masktrip); } else if (!actuallist(&ref0->operand[1])) return FALSE; triptr = oldchain->exorder.bl; dqadd(triptr, &tmpchain, exorder); /*this is a violation of info hiding*/ if (OC_EXFUN == calltrip->opcode) { assert(MLAB_REF == calltrip->operand[0].oprclass); triptr = newtriple(OC_JMP); triptr->operand[0] = put_mfun(&calltrip->operand[0].oprval.lab->mvname); calltrip->operand[0].oprclass = ILIT_REF; /* dummy placeholder */ # if defined(USHBIN_SUPPORTED) || defined(VMS) tripsize->operand[0].oprval.tsize->ct = triptr; # endif } /* If target is an alias, use special container-expecting routine OC_EXFUNRETALS, else regular OC_EXFUNRET */ funret = newtriple((alias_target ? OC_EXFUNRETALS : OC_EXFUNRET)); funret->operand[0] = *a = put_tref(calltrip); return TRUE; } fis-gtm-V6.0-003/sr_port/exp.mpt0000644000032200000250000000146612201176155015357 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1989,2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %EXP ;GT.M %EXP utility - raise 1st argument to the power of the 2nd ;invoke with %I and %J (%I**%J) to obtain result in %I ;invoke at INT to execute interactively ;invoke at FUNC as an extrinsic function ; s %I=$$FUNC(%I,%J) q INT n %I,%J r !,"Power: ",%J r !,"Number: ",%I w !,%I," raised to ",%J," is ",$$FUNC(%I,%J),! q FUNC(i,j) n f,w i i<0,j#1 q "" q i**j fis-gtm-V6.0-003/sr_port/expr.c0000644000032200000250000000262712201176155015163 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" /* needed by INCREMENT_EXPR_DEPTH */ #include "compiler.h" #include "opcode.h" #include "fullbool.h" int expr(oprtype *a, int m_type) { int rval; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; INCREMENT_EXPR_DEPTH; if (EXPR_FAIL == (rval = eval_expr(a))) /* NOTE assignment */ { DECREMENT_EXPR_DEPTH; return FALSE; } coerce(a, (MUMPS_INT == m_type) ? OCT_MINT : OCT_MVAL); ex_tail(a); if (TREF(expr_start) != TREF(expr_start_orig) && (OC_NOOP != (TREF(expr_start))->opcode)) { assert((OC_GVSAVTARG == (TREF(expr_start))->opcode)); if ((OC_GVSAVTARG == (TREF(expr_start))->opcode) && ((GTM_BOOL == TREF(gtm_fullbool)) || !TREF(saw_side_effect))) { if ((OC_GVRECTARG != (TREF(curtchain))->exorder.bl->opcode) || ((TREF(curtchain))->exorder.bl->operand[0].oprval.tref != TREF(expr_start))) newtriple(OC_GVRECTARG)->operand[0] = put_tref(TREF(expr_start)); } } DECREMENT_EXPR_DEPTH; return rval; } fis-gtm-V6.0-003/sr_port/expratom.c0000644000032200000250000000135612201176155016042 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" int expratom(oprtype *a) { DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; switch(TREF(window_token)) { case TK_IDENT: case TK_CIRCUMFLEX: case TK_ATSIGN: return glvn(a); default: return expritem(a); } } fis-gtm-V6.0-003/sr_port/expritem.c0000644000032200000250000005637212201176155016050 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "mdq.h" #include "opcode.h" #include "toktyp.h" #include "svnames.h" #include "nametabtyp.h" #include "funsvn.h" #include "advancewindow.h" #include "stringpool.h" #include "namelook.h" #include "fullbool.h" #include "show_source_line.h" GBLREF bool devctlexp; GBLREF boolean_t run_time; error_def(ERR_BOOLSIDEFFECT); error_def(ERR_EXPR); error_def(ERR_FCNSVNEXPECTED); error_def(ERR_FNOTONSYS); error_def(ERR_INVFCN); error_def(ERR_INVSVN); error_def(ERR_RPARENMISSING); error_def(ERR_SIDEEFFECTEVAL); error_def(ERR_VAREXPECTED); LITREF toktabtype tokentable[]; LITREF mval literal_null; LITREF octabstruct oc_tab[]; #ifndef UNICODE_SUPPORTED #define f_char f_zchar #endif /* note that svn_index array provides indexes into this array for each letter of the * alphabet so changes here should be reflected there. */ LITDEF nametabent svn_names[] = { { 1, "D" }, { 6, "DEVICE" } ,{ 2, "EC" }, { 5, "ECODE" } ,{ 2, "ES" }, { 6, "ESTACK" } ,{ 2, "ET" }, { 5, "ETRAP" } ,{ 1, "H" }, { 7, "HOROLOG" } ,{ 1, "I" }, { 2, "IO" } ,{ 1, "J" }, { 3, "JOB" } ,{ 1, "K" }, { 3, "KEY" } ,{ 1, "P" }, { 8, "PRINCIPA*" } ,{ 1, "Q" }, { 4, "QUIT" } ,{ 1, "R" }, { 8, "REFERENC*" } ,{ 2, "ST" }, { 5, "STACK" } ,{ 1, "S" }, { 7, "STORAGE" } ,{ 2, "SY" }, { 6, "SYSTEM" } ,{ 1, "T" }, { 4, "TEST" } ,{ 2, "TL"}, { 6, "TLEVEL"} ,{ 2, "TR"}, { 8, "TRESTART"} ,{ 1, "X" } ,{ 1, "Y" } ,{ 2, "ZA" } ,{ 3, "ZAL*"} ,{ 2, "ZB" } ,{ 2, "ZC" } ,{ 3, "ZCH" }, { 6, "ZCHSET" } ,{ 3, "ZCM*" } ,{ 3, "ZCO*" } ,{ 3, "ZCS*" } ,{ 3, "ZDA*" } ,{ 2, "ZD*" } ,{ 2, "ZE" } ,{ 3, "ZED*" } ,{ 3, "ZEO*" } ,{ 3, "ZER*" } ,{ 2, "ZG*" } ,{ 4, "ZINI*"} ,{ 4, "ZINT*"} ,{ 3, "ZIO" } ,{ 2, "ZJ" }, { 4, "ZJOB" } ,{ 2, "ZL*" } ,{ 8, "ZMAXTPTI*" } ,{ 3, "ZMO*" } ,{ 5, "ZONLN*"} ,{ 5, "ZPATN" }, {8, "ZPATNUME*" } ,{ 4, "ZPOS*" } ,{ 5, "ZPROC*" } ,{ 5, "ZPROM*" } ,{ 2, "ZQ*" } ,{ 3, "ZRE*" } ,{ 3, "ZRO*" } ,{ 3, "ZSO*" } ,{ 2, "ZS" }, { 4, "ZSTA*" } ,{ 5, "ZSTEP"} ,{ 3, "ZSY*"} ,{ 4, "ZTCO*"} ,{ 4, "ZTDA*"} ,{ 3, "ZTE" }, { 4, "ZTEX*"} ,{ 4, "ZTLE*"} ,{ 4, "ZTNA*"} ,{ 4, "ZTOL*"} ,{ 4, "ZTRI*"} ,{ 4, "ZTSL*"} ,{ 4, "ZTUP*"} ,{ 4, "ZTVA*"} ,{ 4, "ZTWO*"} ,{ 2, "ZT*" } ,{ 3, "ZUS*" } ,{ 2, "ZV*" } ,{ 4, "ZYER*" } }; /* Indexes into svn_names array for each letter of the alphabet */ LITDEF unsigned char svn_index[27] = { 0, 0, 0, 0, 2, 8, 8, 8, 10, /* a b c d e f g h i */ 12, 14 ,16, 16, 16, 16, 16, 18, 20, /* j k l m n o p q r */ 22, 28, 34 ,34, 34, 34, 35, 36, 90 /* s t u v w x y z ~ */ }; /* These entries correspond to the entries in the svn_names array */ LITDEF svn_data_type svn_data[] = { { SV_DEVICE, FALSE, ALL_SYS }, { SV_DEVICE, FALSE, ALL_SYS } ,{ SV_ECODE, TRUE, ALL_SYS }, { SV_ECODE, TRUE, ALL_SYS } ,{ SV_ESTACK, FALSE, ALL_SYS }, { SV_ESTACK, FALSE, ALL_SYS } ,{ SV_ETRAP, TRUE, ALL_SYS }, { SV_ETRAP, TRUE, ALL_SYS } ,{ SV_HOROLOG, FALSE, ALL_SYS }, { SV_HOROLOG, FALSE, ALL_SYS } ,{ SV_IO, FALSE, ALL_SYS }, { SV_IO, FALSE, ALL_SYS } ,{ SV_JOB, FALSE, ALL_SYS }, { SV_JOB, FALSE, ALL_SYS } ,{ SV_KEY, FALSE, ALL_SYS }, { SV_KEY, FALSE, ALL_SYS } ,{ SV_PRINCIPAL, FALSE, ALL_SYS }, { SV_PRINCIPAL, FALSE, ALL_SYS } ,{ SV_QUIT, FALSE, ALL_SYS }, { SV_QUIT, FALSE, ALL_SYS } ,{ SV_REFERENCE, FALSE, ALL_SYS }, { SV_REFERENCE, FALSE, ALL_SYS } ,{ SV_STACK, FALSE, ALL_SYS }, { SV_STACK, FALSE, ALL_SYS } ,{ SV_STORAGE, FALSE, ALL_SYS }, { SV_STORAGE, FALSE, ALL_SYS } ,{ SV_SYSTEM, FALSE, ALL_SYS }, { SV_SYSTEM, FALSE, ALL_SYS } ,{ SV_TEST, FALSE, ALL_SYS }, { SV_TEST, FALSE, ALL_SYS } ,{ SV_TLEVEL, FALSE, ALL_SYS }, { SV_TLEVEL, FALSE, ALL_SYS } ,{ SV_TRESTART, FALSE, ALL_SYS }, { SV_TRESTART, FALSE, ALL_SYS } ,{ SV_X, TRUE, ALL_SYS } ,{ SV_Y, TRUE, ALL_SYS } ,{ SV_ZA, FALSE, ALL_SYS } ,{ SV_ZALLOCSTOR, FALSE, ALL_SYS } ,{ SV_ZB, FALSE, ALL_SYS } ,{ SV_ZC, FALSE, ALL_SYS } ,{ SV_ZCHSET, FALSE, ALL_SYS }, { SV_ZCHSET, FALSE, ALL_SYS } ,{ SV_ZCMDLINE, FALSE, ALL_SYS } ,{ SV_ZCOMPILE, TRUE, ALL_SYS } ,{ SV_ZCSTATUS, FALSE, ALL_SYS} ,{ SV_ZDATE_FORM, TRUE, ALL_SYS } ,{ SV_ZDIR, TRUE, ALL_SYS } ,{ SV_ZERROR, TRUE, ALL_SYS } ,{ SV_ZEDITOR, FALSE, ALL_SYS } ,{ SV_ZEOF, FALSE, ALL_SYS } ,{ SV_ZERROR, TRUE, ALL_SYS } ,{ SV_ZGBLDIR, TRUE, ALL_SYS } ,{ SV_ZININTERRUPT, FALSE, ALL_SYS} ,{ SV_ZINTERRUPT, TRUE, ALL_SYS} ,{ SV_ZIO, FALSE, ALL_SYS } ,{ SV_ZJOB, FALSE, ALL_SYS }, { SV_ZJOB, FALSE, ALL_SYS } ,{ SV_ZLEVEL, FALSE, ALL_SYS } ,{ SV_ZMAXTPTIME, TRUE, ALL_SYS } ,{ SV_ZMODE, FALSE, ALL_SYS } ,{ SV_ZONLNRLBK, FALSE, UNIX_OS } ,{ SV_ZPATNUMERIC, FALSE, ALL_SYS }, { SV_ZPATNUMERIC, FALSE, ALL_SYS } ,{ SV_ZPOS, FALSE, ALL_SYS } ,{ SV_ZPROC, FALSE, ALL_SYS } ,{ SV_PROMPT, TRUE, ALL_SYS } ,{ SV_ZQUIT, TRUE, ALL_SYS } ,{ SV_ZREALSTOR, FALSE, ALL_SYS } ,{ SV_ZROUTINES, TRUE, ALL_SYS } ,{ SV_ZSOURCE, TRUE, ALL_SYS } ,{ SV_ZSTATUS, TRUE, ALL_SYS }, { SV_ZSTATUS, TRUE, ALL_SYS } ,{ SV_ZSTEP, TRUE, ALL_SYS } ,{ SV_ZSYSTEM, FALSE, ALL_SYS } ,{ SV_ZTCODE, FALSE, TRIGGER_OS } ,{ SV_ZTDATA, FALSE, TRIGGER_OS } ,{ SV_ZTEXIT, TRUE, ALL_SYS }, { SV_ZTEXIT, TRUE, ALL_SYS } ,{ SV_ZTLEVEL, FALSE, TRIGGER_OS} ,{ SV_ZTNAME, FALSE, TRIGGER_OS } ,{ SV_ZTOLDVAL, FALSE, TRIGGER_OS } ,{ SV_ZTRIGGEROP, FALSE, TRIGGER_OS} ,{ SV_ZTSLATE, TRUE, TRIGGER_OS} ,{ SV_ZTUPDATE, FALSE, TRIGGER_OS } ,{ SV_ZTVALUE, TRUE, TRIGGER_OS } ,{ SV_ZTWORMHOLE, TRUE, TRIGGER_OS } ,{ SV_ZTRAP, TRUE, ALL_SYS } ,{ SV_ZUSEDSTOR, FALSE, ALL_SYS } ,{ SV_ZVERSION, FALSE, ALL_SYS } ,{ SV_ZYERROR, TRUE, ALL_SYS } }; /* note that fun_index array provides indexes into this array for each letter of the * alphabet so changes here should be reflected there. * "*" is used below only after 8 characters. */ LITDEF nametabent fun_names[] = { {1, "A"}, {5, "ASCII"} ,{1, "C"}, {4, "CHAR"} ,{1, "D"}, {4, "DATA"} ,{1, "E"}, {7, "EXTRACT"} ,{1, "F"}, {4, "FIND"} ,{2, "FN"}, {7, "FNUMBER"} ,{1, "G"}, {3, "GET"} ,{1, "I"}, {4, "INCR"}, {8, "INCREMEN*"} ,{1, "J"}, {7, "JUSTIFY"} ,{1, "L"}, {6, "LENGTH"} ,{1, "N"} ,{2, "NA"}, {4, "NAME"} ,{4, "NEXT"} ,{1, "O"}, {5, "ORDER"} ,{1, "P"}, {5, "PIECE"} ,{2, "QL"}, {7, "QLENGTH"} ,{2, "QS"}, {8, "QSUBSCRI*"} ,{1, "Q"}, {5, "QUERY"} ,{1, "R"}, {6, "RANDOM"} ,{2, "RE"}, {7, "REVERSE"} ,{1, "S"}, {6, "SELECT"} ,{2, "ST"}, {5, "STACK"} ,{1, "T"}, {4, "TEXT"} ,{2, "TR"}, {8, "TRANSLAT*"} ,{1, "V*"} ,{2, "ZA"}, {6, "ZASCII"} ,{3, "ZAH"}, {8, "ZAHANDLE"} ,{7, "ZBITAND"} ,{8, "ZBITCOUN*"} ,{8, "ZBITFIND"} ,{7, "ZBITGET"} ,{7, "ZBITLEN"} ,{7, "ZBITNOT"} ,{6, "ZBITOR"} ,{7, "ZBITSET"} ,{7, "ZBITSTR"} ,{7, "ZBITXOR"} ,{2, "ZC"}, {5, "ZCALL"} ,{3, "ZCH"}, {5, "ZCHAR"} ,{3, "ZCO"}, {8, "ZCONVERT"} ,{2, "ZD"} ,{5, "ZDATA"} ,{5, "ZDATE"} ,{2, "ZE"}, {8, "ZEXTRACT"} ,{2, "ZF"}, {5, "ZFIND"} ,{5, "ZFILE"}, {8, "ZFILEATT*"} ,{7, "ZGETDVI"} ,{7, "ZGETJPI"} ,{7, "ZGETLKI"} ,{7, "ZGETSYI"} ,{5, "ZINCR"}, {8, "ZINCREME*"} ,{2, "ZJ"}, {8, "ZJUSTIFY"} ,{8, "ZJOBEXAM"} ,{2, "ZL"}, {7, "ZLENGTH"} ,{5, "ZLKID"} ,{2, "ZM"}, {8, "ZMESSAGE"} ,{2, "ZP"}, {8, "ZPREVIOU*"} ,{6, "ZPARSE"} ,{5, "ZPEEK"} ,{3, "ZPI"}, {6, "ZPIECE"} ,{4, "ZPID"} ,{5, "ZPRIV"}, {8, "ZPRIVILE*"} ,{2, "ZQ"}, {8, "ZQGBLMOD"} ,{7, "ZSEARCH"} ,{7, "ZSETPRV"} ,{8, "ZSIGPROC"} ,{4, "ZSUB"}, {7, "ZSUBSTR"} ,{3, "ZTR"}, {8, "ZTRANSLA*"} ,{4, "ZTRI"}, {8, "ZTRIGGER"} ,{7, "ZTRNLNM"} ,{2, "ZW"}, {6, "ZWIDTH"} ,{3, "ZWR"}, {6, "ZWRITE"} }; /* Index into fun_names array where entries that start with each letter of the alphabet begin. */ LITDEF unsigned char fun_index[27] = { 0, 2, 2, 4, 6, 8, 12, 14, 14, /* a b c d e f g h i */ 17, 19, 19, 21, 21, 25, 27, 29, 35, /* j k l m n o p q r */ 39, 43, 47, 47, 48, 48, 48, 48, 116 /* s t u v w x y z ~ */ }; /* Each entry corresponds to an entry in fun_names */ LITDEF fun_data_type fun_data[] = { { OC_FNASCII, ALL_SYS }, { OC_FNASCII, ALL_SYS } ,{ OC_FNCHAR, ALL_SYS }, { OC_FNCHAR, ALL_SYS } ,{ OC_FNDATA, ALL_SYS }, { OC_FNDATA, ALL_SYS } ,{ OC_FNEXTRACT, ALL_SYS }, { OC_FNEXTRACT, ALL_SYS } ,{ OC_FNFIND, ALL_SYS }, { OC_FNFIND, ALL_SYS } ,{ OC_FNFNUMBER, ALL_SYS }, { OC_FNFNUMBER, ALL_SYS } ,{ OC_FNGET, ALL_SYS }, { OC_FNGET, ALL_SYS } ,{ OC_FNINCR, ALL_SYS }, { OC_FNINCR, ALL_SYS }, { OC_FNINCR, ALL_SYS } ,{ OC_FNJ2, ALL_SYS }, { OC_FNJ2, ALL_SYS } ,{ OC_FNLENGTH, ALL_SYS }, { OC_FNLENGTH, ALL_SYS } ,{ OC_FNNEXT, ALL_SYS } ,{ OC_FNNAME, ALL_SYS }, { OC_FNNAME, ALL_SYS } ,{ OC_FNNEXT, ALL_SYS } ,{ OC_FNORDER, ALL_SYS }, {OC_FNORDER, ALL_SYS } ,{ OC_FNPIECE, ALL_SYS }, { OC_FNPIECE, ALL_SYS } ,{ OC_FNQLENGTH, ALL_SYS }, { OC_FNQLENGTH, ALL_SYS } ,{ OC_FNQSUBSCR, ALL_SYS }, { OC_FNQSUBSCR, ALL_SYS } ,{ OC_FNQUERY, ALL_SYS }, { OC_FNQUERY, ALL_SYS } ,{ OC_FNRANDOM, ALL_SYS }, { OC_FNRANDOM, ALL_SYS } ,{ OC_FNREVERSE, ALL_SYS }, { OC_FNREVERSE, ALL_SYS } ,{ OC_PASSTHRU, ALL_SYS }, { OC_PASSTHRU, ALL_SYS } ,{ OC_FNSTACK1, ALL_SYS }, { OC_FNSTACK1, ALL_SYS } ,{ OC_FNTEXT, ALL_SYS }, { OC_FNTEXT, ALL_SYS } ,{ OC_FNTRANSLATE, ALL_SYS }, { OC_FNTRANSLATE, ALL_SYS } ,{ OC_FNVIEW, ALL_SYS } ,{ OC_FNZASCII, ALL_SYS }, { OC_FNZASCII, ALL_SYS } ,{ OC_FNZAHANDLE, ALL_SYS }, { OC_FNZAHANDLE, ALL_SYS } ,{ OC_FNZBITAND, ALL_SYS } ,{ OC_FNZBITCOUN, ALL_SYS } ,{ OC_FNZBITFIND, ALL_SYS } ,{ OC_FNZBITGET, ALL_SYS } ,{ OC_FNZBITLEN, ALL_SYS } ,{ OC_FNZBITNOT, ALL_SYS } ,{ OC_FNZBITOR, ALL_SYS } ,{ OC_FNZBITSET, ALL_SYS } ,{ OC_FNZBITSTR, ALL_SYS } ,{ OC_FNZBITXOR, ALL_SYS } # ifdef __sun ,{ OC_FNZCALL,UNIX_OS}, { OC_FNZCALL,UNIX_OS} # else ,{ OC_FNZCALL, VMS_OS }, { OC_FNZCALL, VMS_OS } # endif ,{ OC_FNZCHAR, ALL_SYS }, { OC_FNZCHAR, ALL_SYS } ,{ OC_FNZCONVERT2, UNIX_OS }, { OC_FNZCONVERT2, UNIX_OS } ,{ OC_FNZDATE, ALL_SYS } ,{ OC_FNZDATA, ALL_SYS } ,{ OC_FNZDATE, ALL_SYS } ,{ OC_FNZEXTRACT, ALL_SYS }, { OC_FNZEXTRACT, ALL_SYS } ,{ OC_FNZFIND, ALL_SYS }, { OC_FNZFIND, ALL_SYS } ,{ OC_FNZFILE, VMS_OS }, { OC_FNZFILE, VMS_OS } ,{ OC_FNZGETDVI, VMS_OS } ,{ OC_FNZGETJPI, ALL_SYS } ,{ OC_FNZGETLKI, VMS_OS } ,{ OC_FNZGETSYI, VMS_OS } ,{ OC_FNINCR, ALL_SYS }, { OC_FNINCR, ALL_SYS } ,{ OC_FNZJ2, ALL_SYS }, { OC_FNZJ2, ALL_SYS } ,{ OC_FNZJOBEXAM, ALL_SYS } ,{ OC_FNZLENGTH, ALL_SYS }, { OC_FNZLENGTH, ALL_SYS } ,{ OC_FNZLKID, VMS_OS} ,{ OC_FNZM, ALL_SYS }, { OC_FNZM, ALL_SYS } ,{ OC_FNZPREVIOUS, ALL_SYS }, { OC_FNZPREVIOUS, ALL_SYS } ,{ OC_FNZPARSE, ALL_SYS } ,{ OC_FNZPEEK, UNIX_OS } ,{ OC_FNZPIECE, ALL_SYS }, { OC_FNZPIECE, ALL_SYS } ,{ OC_FNZPID, VMS_OS } ,{ OC_FNZPRIV, VMS_OS }, { OC_FNZPRIV, VMS_OS } ,{ OC_FNZQGBLMOD, ALL_SYS }, { OC_FNZQGBLMOD, ALL_SYS } ,{ OC_FNZSEA, ALL_SYS } ,{ OC_FNZSETPRV, VMS_OS } ,{ OC_FNZSIGPROC, ALL_SYS } ,{ OC_FNZSUBSTR, ALL_SYS }, { OC_FNZSUBSTR, ALL_SYS } ,{ OC_FNZTRANSLATE, ALL_SYS }, { OC_FNZTRANSLATE, ALL_SYS } ,{ OC_FNZTRIGGER, TRIGGER_OS }, { OC_FNZTRIGGER, TRIGGER_OS } ,{ OC_FNZTRNLNM, ALL_SYS } ,{ OC_FNZWIDTH, ALL_SYS }, { OC_FNZWIDTH, ALL_SYS } ,{ OC_FNZWRITE, ALL_SYS }, { OC_FNZWRITE, ALL_SYS } }; /* Each entry corresponds to an entry in fun_names */ GBLDEF int (*fun_parse[])(oprtype *, opctype) = /* contains addresses so can't be a LITDEF */ { f_ascii, f_ascii, f_char, f_char, f_data, f_data, f_extract, f_extract, f_find, f_find, f_fnumber, f_fnumber, f_get, f_get, f_incr, f_incr, f_incr, f_justify, f_justify, f_length, f_length, f_next, f_name, f_name, f_next, f_order, f_order, f_piece, f_piece, f_qlength, f_qlength, f_qsubscript, f_qsubscript, f_query, f_query, f_mint, f_mint, f_reverse, f_reverse, f_select, f_select, f_stack, f_stack, f_text, f_text, f_translate, f_translate, f_view, f_ascii, f_ascii, f_zahandle, f_zahandle, f_two_mval, f_one_mval, f_fnzbitfind, f_fnzbitget, f_one_mval, f_one_mval, f_two_mval, f_fnzbitset, f_fnzbitstr, f_two_mval, f_zcall, f_zcall, f_zchar, f_zchar, f_zconvert, f_zconvert, f_zdate, f_data, /* $ZDATA reuses parser for $DATA since only runtime execution differs */ f_zdate, f_extract, f_extract, f_find, f_find, f_two_mstrs, f_two_mstrs, f_two_mstrs, f_mint_mstr, f_two_mstrs, f_zgetsyi, f_incr, f_incr, f_justify, f_justify, f_zjobexam, f_length, f_length, f_mint, f_mint, f_mint, f_zprevious, f_zprevious, f_zparse, f_zpeek, f_piece, f_piece, f_mint, f_mstr, f_mstr, f_zqgblmod, f_zqgblmod, f_zsearch, f_mstr, f_zsigproc, f_extract, f_extract, /* $ZSUBSTR */ f_translate, f_translate, f_ztrigger, f_ztrigger, f_ztrnlnm, f_zwidth, f_zwidth, f_zwrite, f_zwrite }; int expritem(oprtype *a) { boolean_t parse_warn, saw_local, saw_se, se_warn; oprtype *j, *k, x1; int i, index, sv_opcode; tbp argbp, *funcbp, *tripbp; triple *argtrip, *functrip, *ref, *t1, *t2, *t3; unsigned char type; unsigned int argcnt; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(svn_index[26] == (SIZEOF(svn_names)/SIZEOF(nametabent))); assert(SIZEOF(svn_names)/SIZEOF(nametabent) == SIZEOF(svn_data)/SIZEOF(svn_data_type)); /* are all SVNs covered? */ assert(fun_index[26] == (SIZEOF(fun_names)/SIZEOF(nametabent))); assert(SIZEOF(fun_names)/SIZEOF(nametabent) == SIZEOF(fun_data)/SIZEOF(fun_data_type)); /* are all functions covered? */ if (i = tokentable[TREF(window_token)].uo_type) /* NOTE assignment */ { type = tokentable[TREF(window_token)].opr_type; advancewindow(); if ((OC_NEG == i) && ((TK_NUMLIT == TREF(window_token)) || (TK_INTLIT == TREF(window_token)))) { assert(MV_IS_NUMERIC(&(TREF(window_mval)))); if ((TREF(window_mval)).mvtype & MV_INT) (TREF(window_mval)).m[1] = -(TREF(window_mval)).m[1]; else (TREF(window_mval)).sgn = 1; if (TK_NUMLIT == TREF(window_token)) n2s(&(TREF(window_mval))); } else { if (!expratom(&x1)) return FALSE; coerce(&x1, type); ref = newtriple((opctype)i); ref->operand[0] = x1; *a = put_tref(ref); return TRUE; } } switch (i = TREF(window_token)) /* NOTE assignment */ { case TK_INTLIT: n2s(&(TREF(window_mval))); case TK_NUMLIT: case TK_STRLIT: *a = put_lit(&(TREF(window_mval))); advancewindow(); return TRUE; case TK_LPAREN: advancewindow(); if (eval_expr(a) && TK_RPAREN == TREF(window_token)) { advancewindow(); return TRUE; } stx_error(ERR_RPARENMISSING); return FALSE; case TK_DOLLAR: parse_warn = saw_se = FALSE; if ((TK_DOLLAR == TREF(director_token)) || (TK_AMPERSAND == TREF(director_token))) { ENCOUNTERED_SIDE_EFFECT; TREF(temp_subs) = TRUE; saw_se = TRUE; advancewindow(); if ((TK_DOLLAR == TREF(window_token)) ? (EXPR_FAIL == exfunc(a, FALSE)) : (EXPR_FAIL == extern_func(a))) return FALSE; } else { advancewindow(); if (TK_IDENT != TREF(window_token)) { stx_error(ERR_FCNSVNEXPECTED); return FALSE; } if (TK_LPAREN == TREF(director_token)) { index = namelook(fun_index, fun_names, (TREF(window_ident)).addr, (TREF(window_ident)).len); if (index < 0) { STX_ERROR_WARN(ERR_INVFCN); /* sets "parse_warn" to TRUE */ } else { assert(SIZEOF(fun_names) / SIZEOF(fun_data_type) > index); if (!VALID_FUN(index)) { STX_ERROR_WARN(ERR_FNOTONSYS); /* sets "parse_warn" to TRUE */ } else if ((OC_FNINCR == fun_data[index].opcode) || (OC_FNZCALL == fun_data[index].opcode)) { /* $INCR is used. This can operate on undefined local variables * and make them defined. If used in a SET where the left and right * side of the = operator use this variable (as a subscript on the left * and as input to the $INCR function on the right), we want an UNDEF * error to show up which means we need to set "temp_subs" to TRUE. */ ENCOUNTERED_SIDE_EFFECT; TREF(temp_subs) = TRUE; saw_se = TRUE; } } advancewindow(); advancewindow(); if (!parse_warn) { assert(OPCODE_COUNT > fun_data[index].opcode); if (!(boolean_t)((*fun_parse[index])(a, fun_data[index].opcode))) return FALSE; } else { *a = put_lit((mval *)&literal_null); /* Parse the remaining arguments until the corresponding RIGHT-PAREN/SPACE/EOL is reached */ if (!parse_until_rparen_or_space()) return FALSE; } if (TK_RPAREN != TREF(window_token)) { stx_error(ERR_RPARENMISSING); return FALSE; } advancewindow(); } else { index = namelook(svn_index, svn_names, (TREF(window_ident)).addr, (TREF(window_ident)).len); if (0 > index) { STX_ERROR_WARN(ERR_INVSVN); /* sets "parse_warn" to TRUE */ } else { assert(SIZEOF(svn_names) / SIZEOF(svn_data_type) > index); if (!VALID_SVN(index)) { STX_ERROR_WARN(ERR_FNOTONSYS); /* sets "parse_warn" to TRUE */ } } advancewindow(); if (!parse_warn) { sv_opcode = svn_data[index].opcode; assert(SV_NUM_SV > sv_opcode); if (SV_TEST == sv_opcode) *a = put_tref(newtriple(OC_GETTRUTH)); else { if (sv_opcode == SV_X || sv_opcode == SV_Y) devctlexp = TRUE; ref = newtriple(OC_SVGET); ref->operand[0] = put_ilit(sv_opcode); *a = put_tref(ref); } } else *a = put_lit((mval *)&literal_null); return TRUE; } } if (saw_se && (OLD_SE != TREF(side_effect_handling))) { assert(0 < TREF(expr_depth)); assert(TREF(expr_depth) <= TREF(side_effect_depth)); (TREF(side_effect_base))[TREF(expr_depth)] = TRUE; } functrip = t1 = a->oprval.tref; if (parse_warn || !(TREF(side_effect_base))[TREF(expr_depth)] || (NO_REF == functrip->operand[1].oprclass)) return TRUE; /* 1 argument gets a pass */ assert(0 < TREF(expr_depth)); switch (functrip->opcode) { case OC_EXFUN: /* relies on protection from actuallist */ case OC_EXTEXFUN: /* relies on protection from actuallist */ case OC_FNFGNCAL: /* relies on protection from actuallist */ case OC_FNGET: /* $get() gets a pass because protects itself */ case OC_FNINCR: /* $increment() gets a pass because its ordering needs no protection */ case OC_FNNEXT: /* only has 1 arg, but uses 2 for lvn interface */ case OC_FNORDER: /* may have 1 or 2 args, internally uses 1 extra for lvn arg, but protects itself */ case OC_FNZPREVIOUS: /* only has 1 arg, but uses 2 for lvn interface */ case OC_INDINCR: /* $increment() gets a pass because its ordering needs no protection */ return TRUE; } /* default falls through */ /* This block protects lvn evaluations in earlier arguments from changes caused by side effects in later * arguments by capturing the prechange value in a temporary; coerce or preexisting temporary might already * do the job and indirect local evaluations may already have shifted to occur earlier. This algorithm is similar * to one in eval_expr for concatenation, but it must deal with possible arguments in both operands for * both the initial triple and the last parameter triple, and the possibility of empty operand[0] in some * functions so they have not been combined. We should have least one side effect (see compiler.h) and two * arguments to bother - to know side effect, we have an array malloc'd and high water marked to avoid a limit * on expression nesting depth, anchored by TREF(side_effect_base) and indexed by TREF(expr_depth) so * ENCOUNTERED_SIDE_EFFECT can mark the prior level; f_select mallocs and free its own array */ assert(OLD_SE != TREF(side_effect_handling)); funcbp = &functrip->backptr; /* borrow backptr to track args */ tripbp = &argbp; dqinit(tripbp, que); tripbp->bpt = NULL; assert(NULL == funcbp->bpt); assert((funcbp == funcbp->que.fl) && (funcbp == funcbp->que.bl)); saw_se = saw_local = FALSE; for (argtrip = t1; ; argtrip = t1) { /* work functrip,oprval.tref arguments forward */ if (argtrip != functrip) tripbp = &argtrip->backptr; assert(NULL == tripbp->bpt); for (j = argtrip->operand; j < ARRAYTOP(argtrip->operand); j++) { /* process all (two) operands */ t1 = j->oprval.tref; if (NO_REF == j->oprclass) continue; /* some functions leave holes in their arguments */ if (((ARRAYTOP(argtrip->operand) - 1) == j) && (TRIP_REF == j->oprclass) && (OC_PARAMETER == t1->opcode)) break; /* only need to deal with last operand[1] */ for (k = j; INDR_REF == k->oprclass; k = k->oprval.indr) ; /* INDR_REFs used by e.g. extrinsics finally end up at a TRIP_REF */ if (TRIP_REF != k->oprclass) continue; /* something else - not to worry */ /* may need to step back past coerce of side effects */ t3 = k->oprval.tref; t2 = (oc_tab[t3->opcode].octype & OCT_COERCE) ? t3->operand[0].oprval.tref : t3; if ((OC_VAR == t2->opcode) || (OC_GETINDX == t2->opcode)) { /* it's an lvn */ if ((t3 != t2) || ((ARRAYTOP(argtrip->operand) - 1) == (&(argtrip->operand[i])))) continue; /* but if it's the last or there's a coerce */ saw_local = TRUE; /* left operand may need protection */ } if (!saw_local) continue; /* no local yet to worry about */ saw_se = TRUE; if (NULL != tripbp->bpt) { /* this one's already flagged */ assert((ARRAYTOP(argtrip->operand) - 1) == j); continue; } /* chain stores args to manage later insert of temps to hold left values */ assert((tripbp == tripbp->que.fl) && (tripbp == tripbp->que.bl)); tripbp->bpt = argtrip; dqins(funcbp, que, tripbp); } if ((NULL == t1) || (OC_PARAMETER != t1->opcode)) break; /* end of arg list */ assert(argtrip->operand[1].oprval.tref == t1); } if (!saw_se) /* might have lucked out on ordering */ saw_local = FALSE; /* just clear the backptrs - shut off other processing */ saw_se = FALSE; se_warn = (!run_time && (SE_WARN == TREF(side_effect_handling))); dqloop(funcbp, que, tripbp) { /* work chained arguments which are in reverse order */ argtrip = tripbp->bpt; assert(NULL != argtrip); dqdel(tripbp, que); tripbp->bpt = NULL; if (!saw_local) continue; /* found some need to insert temps */ for (j = &argtrip->operand[1]; j >= argtrip->operand; j--) { /* match to the operand - usually 0 but have to cover 1 as well */ for (k = j; INDR_REF == k->oprclass; k = k->oprval.indr) ; /* INDR_REFs used by e.g. extrinsics finally end up at a TRIP_REF */ assert((TRIP_REF == k->oprclass) || (NO_REF == k->oprclass)); t1 = k->oprval.tref; if ((NO_REF == k->oprclass) || (OC_PARAMETER == t1->opcode) || (oc_tab[t1->opcode].octype & OCT_COERCE)) continue; if ((OC_VAR == t1->opcode) || (OC_GETINDX == t1->opcode)) { /* have an operand that needs a temp because threat from some side effect */ ref = maketriple(OC_STOTEMP); ref->operand[0] = put_tref(t1); dqins(t1, exorder, ref); /* NOTE:this violates infomation hiding */ k->oprval.tref = ref; if (se_warn) ISSUE_SIDEEFFECTEVAL_WARNING(t1->src.column + 1); } else saw_se = TRUE; } } assert((funcbp == funcbp->que.fl) && (funcbp == funcbp->que.bl) && (NULL == funcbp->bpt)); return TRUE; /* end of order of evaluation processing for functions*/ case TK_COLON: stx_error(ERR_EXPR); return FALSE; } /* case default: intentionally omitted as it simply uses the below return FALSE */ return FALSE; } fis-gtm-V6.0-003/sr_port/ext2jnl.c0000644000032200000250000002114712201176155015571 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include /* for offsetof() macro */ #include "gtm_ctype.h" #include "mlkdef.h" #include "gtm_string.h" #include "subscript.h" #include "gdsroot.h" /* for filestruct.h */ #include "gdsbt.h" /* for gdsfhead.h */ #include "gtm_facility.h" /* for fileinfo.h */ #include "fileinfo.h" /* for gdsfhead.h */ #include "gdsfhead.h" /* for filestruct.h */ #include "filestruct.h" /* for jnl.h */ #include "jnl.h" #include "repl_dbg.h" #include "copy.h" #include "zshow.h" #include "mvalconv.h" #include "str2gvkey.h" GBLREF char *ext_stop; GBLREF gv_key *gv_currkey; static boolean_t in_tp; static int4 num_records; /* callers please set up the proper condition-handlers */ /* expects a null-terminated ext_buff. does the equivalent but inverse of jnl2ext */ char *ext2jnlcvt(char *ext_buff, int4 ext_len, jnl_record *rec, seq_num saved_jnl_seqno, seq_num saved_strm_seqno) { char *ext_next; jnl_record *temp_rec; temp_rec = rec; for ( ; (NULL != (ext_next = strchr(ext_buff, '\n'))); ) { *ext_next++ = '\0'; rec = (jnl_record *)ext2jnl(ext_buff, rec, saved_jnl_seqno, saved_strm_seqno); assert(0 == (INTPTR_T)rec % JNL_REC_START_BNDRY); if (ext_stop == ext_buff) break; ext_buff = ext_next; } assert(rec != temp_rec); ext_stop = ext_buff; return (char *)rec; } /* expects a single null-terminated ptr (equivalent to one line in the extract-file) */ char *ext2jnl(char *ptr, jnl_record *rec, seq_num saved_jnl_seqno, seq_num saved_strm_seqno) { unsigned char *pool_save, ch, chtmp; char *val_off; int keylength, keystate, len, i, reclen, temp_reclen, val_len; bool keepgoing; mstr src, des; jnl_record *temp_rec; muextract_type exttype; enum jnl_record_type rectype; jrec_suffix *suffix; uint4 nodeflags; DEBUG_ONLY(uint4 tcom_num = 0;) ext_stop = ptr + strlen(ptr) + 1; temp_rec = rec; exttype = (muextract_type)MUEXTRACT_TYPE(ptr); assert((exttype >= 0) && (exttype < MUEXT_MAX_TYPES)); switch(exttype) { case MUEXT_SET: if (in_tp) { if (0 == num_records) rec->prefix.jrec_type = JRT_TSET; else rec->prefix.jrec_type = JRT_USET; num_records++; } else rec->prefix.jrec_type = JRT_SET; break; case MUEXT_KILL: if (in_tp) { if (0 == num_records) rec->prefix.jrec_type = JRT_TKILL; else rec->prefix.jrec_type = JRT_UKILL; num_records++; } else rec->prefix.jrec_type = JRT_KILL; break; case MUEXT_ZKILL: if (in_tp) { if (0 == num_records) rec->prefix.jrec_type = JRT_TZKILL; else rec->prefix.jrec_type = JRT_UZKILL; num_records++; } else rec->prefix.jrec_type = JRT_ZKILL; break; # ifdef GTM_TRIGGER case MUEXT_ZTWORM: if (in_tp) { if (0 == num_records) rec->prefix.jrec_type = JRT_TZTWORM; else rec->prefix.jrec_type = JRT_UZTWORM; num_records++; } else GTMASSERT; /* ZTWORMHOLE should always been seen only inside a TP fence */ break; case MUEXT_ZTRIG: if (in_tp) { if (0 == num_records) rec->prefix.jrec_type = JRT_TZTRIG; else rec->prefix.jrec_type = JRT_UZTRIG; num_records++; } else GTMASSERT; /* ZTRIGGER should always been seen only inside a TP fence */ break; # endif case MUEXT_TSTART: in_tp = TRUE; num_records = 0; return (char *)rec; break; case MUEXT_TCOMMIT: rec->prefix.jrec_type = JRT_TCOM; DEBUG_ONLY( /* External filter format has only ONE TSTART..TCOM. The journal record received from the external filter * SHOULD also have only ONE TSTART..TCOM */ tcom_num++; assert(1 == tcom_num); ) rec->jrec_tcom.num_participants = 1; /* Only ONE TSTART..TCOM in the external filter format */ in_tp = FALSE; break; case MUEXT_PINI: case MUEXT_PFIN: case MUEXT_EOF: case MUEXT_ZTSTART: case MUEXT_ZTCOMMIT: assert(FALSE); ext_stop = ptr; return (char *)rec; break; case MUEXT_NULL: rec->prefix.jrec_type = JRT_NULL; break; default: assert(FALSE); ext_stop = ptr; return (char *)rec; break; } rectype = (enum jnl_record_type)rec->prefix.jrec_type; ptr = strtok(ptr, "\\"); /* get the rec-type field */ assert(NULL != ptr); ptr = strtok(NULL, "\\"); /* get the time field */ assert(NULL != ptr); ptr = strtok(NULL, "\\"); /* get the tn field */ assert(NULL != ptr); rec->prefix.tn = asc2i((uchar_ptr_t)ptr, STRLEN(ptr)); ptr = strtok(NULL, "\\"); /* get the pid field */ assert(NULL != ptr); ptr = strtok(NULL, "\\"); /* get the client pid field */ assert(NULL != ptr); ptr = strtok(NULL, "\\"); /* get the token/jnl_seqno field */ assert(NULL != ptr); rec->jrec_null.jnl_seqno = saved_jnl_seqno; ptr = strtok(NULL, "\\"); /* get the strm_num field */ assert(NULL != ptr); ptr = strtok(NULL, "\\"); /* get the strm_seqno field */ assert(NULL != ptr); rec->jrec_null.strm_seqno = saved_strm_seqno; switch(exttype) { case MUEXT_NULL: rec->jrec_null.prefix.forwptr = rec->jrec_null.suffix.backptr = NULL_RECLEN; rec->jrec_null.suffix.suffix_code = JNL_REC_SUFFIX_CODE; return ((char_ptr_t)rec) + NULL_RECLEN; case MUEXT_TCOMMIT: ptr = strtok(NULL, "\\"); /* get the participants */ ptr = strtok(NULL, "\\"); /* get the jnl_tid */ rec->jrec_tcom.jnl_tid[0] = 0; if (NULL != ptr) strcpy(rec->jrec_tcom.jnl_tid, ptr); num_records = 0; rec->jrec_tcom.prefix.forwptr = rec->jrec_tcom.suffix.backptr = TCOM_RECLEN; rec->jrec_tcom.suffix.suffix_code = JNL_REC_SUFFIX_CODE; return ((char_ptr_t)rec) + TCOM_RECLEN; } assert(IS_SET_KILL_ZKILL_ZTRIG_ZTWORM(rectype)); ptr = strtok(NULL, "\\"); /* get the update_num field */ assert(NULL != ptr); assert(OFFSETOF(struct_jrec_upd, update_num) == OFFSETOF(struct_jrec_ztworm, update_num)); rec->jrec_set_kill.update_num = num_records; if (MUEXT_ZTWORM != exttype) { ptr = strtok(NULL, "\\"); /* get the nodeflags field */ assert(NULL != ptr); rec->jrec_set_kill.mumps_node.nodeflags = asc2i((uchar_ptr_t)ptr, STRLEN(ptr)); } ptr += (strlen(ptr) + 1); /* get the key-value and data also; can't use strtok since there might be '\\' in the subscript */ assert(NULL != ptr); if (MUEXT_ZTWORM != exttype) { assert(IS_SET_KILL_ZKILL_ZTRIG(rectype)); len = STRLEN(ptr); val_off = ptr; keylength = zwrkeyvallen(ptr, len, &val_off, &val_len, NULL, NULL); /* determine length of key */ REPL_DPRINT2("ext2jnl source:KEY=DATA:%s\n", ptr); assert(keylength <= len); str2gvkey_nogvfunc(ptr, keylength, gv_currkey); rec->jrec_set_kill.mumps_node.length = gv_currkey->end; memcpy(rec->jrec_set_kill.mumps_node.text, gv_currkey->base, gv_currkey->end); temp_reclen = (int)(FIXED_UPD_RECLEN + rec->jrec_set_kill.mumps_node.length + SIZEOF(jnl_str_len_t)); if (IS_KILL_ZKILL_ZTRIG(rectype)) { temp_reclen += JREC_SUFFIX_SIZE; reclen = ROUND_UP2(temp_reclen, JNL_REC_START_BNDRY); memset((char_ptr_t)rec + temp_reclen - JREC_SUFFIX_SIZE, 0, reclen - temp_reclen); suffix = (jrec_suffix *)((char_ptr_t)rec + reclen - JREC_SUFFIX_SIZE); rec->prefix.forwptr = suffix->backptr = reclen; suffix->suffix_code = JNL_REC_SUFFIX_CODE; return (char_ptr_t)rec + reclen; } /* we have to get the data value now */ src.len = val_len; src.addr = val_off; } else { /* ZTWORMHOLE */ assert(IS_ZTWORM(rectype)); src.addr = ptr; src.len = STRLEN(ptr); temp_reclen = (int)(FIXED_ZTWORM_RECLEN); } des.len = 0; des.addr = (char_ptr_t)rec + temp_reclen + SIZEOF(jnl_str_len_t); REPL_DPRINT3("ext2jnl JNL Format (before zwr2format): src : Len %d :: DATA:%s\n", src.len, src.addr); REPL_DPRINT3("ext2jnl JNL Format (before zwr2format): des : Len %d :: DATA:%s\n", des.len, des.addr); if (!zwr2format(&src, &des)) { assert(FALSE); return (char_ptr_t)rec; } REPL_DPRINT3("ext2jnl JNL Format : src : Len %d :: DATA:%s\n", src.len, src.addr); REPL_DPRINT3("ext2jnl JNL Format : des : Len %d :: DATA:%s\n", des.len, des.addr); PUT_MSTR_LEN((char_ptr_t)rec + temp_reclen, des.len); temp_reclen += SIZEOF(jnl_str_len_t) + des.len + JREC_SUFFIX_SIZE; reclen = ROUND_UP2(temp_reclen, JNL_REC_START_BNDRY); memset((char_ptr_t)rec + temp_reclen - JREC_SUFFIX_SIZE, 0, reclen - temp_reclen); suffix = (jrec_suffix *)((char_ptr_t)rec + reclen - JREC_SUFFIX_SIZE); rec->prefix.forwptr = suffix->backptr = reclen; suffix->suffix_code = JNL_REC_SUFFIX_CODE; return (char_ptr_t)rec + reclen; } fis-gtm-V6.0-003/sr_port/extern_func.c0000644000032200000250000001020412201176155016513 0ustar librarygtc/**************************************************************** * * * Copyright 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" #ifdef VMS #include "vaxsym.h" #include "mmemory.h" #endif GBLREF char *lexical_ptr; GBLREF unsigned char *source_buffer; error_def(ERR_RTNNAME); /* Maximum size of external routine reference of the form label^routine */ #ifdef UNIX #define MAX_EXTREF (2 * MAX_MIDENT_LEN + STR_LIT_LEN("^")) #endif /* compiler parse to AVT module for external functions ($&) */ int extern_func(oprtype *a) { boolean_t have_ident; char *extref; int cnt, actcnt; mstr extentry, package; oprtype *nxtopr; triple *calltrip, *ref; # ifdef VMS char *extsym, *extern_symbol; oprtype tabent; # endif DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert (TK_AMPERSAND == TREF(window_token)); advancewindow(); cnt = 0; extref = (char *)&source_buffer[TREF(last_source_column) - 1]; package.len = 0; package.addr = NULL; if (have_ident = (TK_IDENT == TREF(window_token))) /* NOTE assignment */ { if (TK_PERIOD == TREF(director_token)) { /* if ident is a package reference, then take it off */ package.addr = extref; package.len = INTCAST(lexical_ptr - extref - 1); VMS_ONLY(package.len = ((MAX_EXTREF < package.len) ? MAX_EXTREF : package.len)); extref = lexical_ptr; advancewindow(); /* get to . */ advancewindow(); /* to next token */ if (have_ident = (TK_IDENT == TREF(window_token))) /* NOTE assignment */ advancewindow(); } else advancewindow(); } if (TK_CIRCUMFLEX == TREF(window_token)) { advancewindow(); if (TK_IDENT == TREF(window_token)) { have_ident = TRUE; advancewindow(); } } if (!have_ident) { stx_error(ERR_RTNNAME); return FALSE; } extentry.len = INTCAST((char *)&source_buffer[TREF(last_source_column) - 1] - extref); extentry.len = INTCAST(extentry.len > MAX_EXTREF ? MAX_EXTREF : extentry.len); extentry.addr = extref; # ifdef VMS_CASE_SENSITIVE_MACROS if (!run_time) { /* this code is disabled because the * external call table macros are not case sensitive */ extern_symbol = mcalloc(MAX_SYMREF); extsym = extern_symbol; MEMCPY_LIT(extsym, ZCSYM_PREFIX); extsym += SIZEOF(ZCSYM_PREFIX) - 1; memcpy(extsym, package.addr, package.len); if ('%' == *extsym) *extsym = '_'; extsym += package.len; *extsym++ = '.'; memcpy(extsym, extentry.addr, extentry.len); if ('%' == *extsym) *extsym = '_'; extsym += extentry.len; extentry.addr = extern_symbol; extentry.len = extsym - extern_symbol; tabent = put_cdlt(&extentry); } else { # endif # ifdef VMS ref = newtriple(OC_FGNLOOKUP); ref->operand[0] = put_str(package.addr, package.len); ref->operand[1] = put_str(extentry.addr, extentry.len); tabent = put_tref(ref); # endif # ifdef VMS_CASE_SENSITIVE_MACROS } # endif calltrip = maketriple(a ? OC_FNFGNCAL : OC_FGNCAL); nxtopr = &calltrip->operand[1]; ref = newtriple(OC_PARAMETER); ref->operand[0] = UNIX_ONLY(put_str(package.addr, package.len)) VMS_ONLY(tabent); *nxtopr = put_tref(ref); nxtopr = &ref->operand[1]; cnt++; # ifdef UNIX ref = newtriple(OC_PARAMETER); ref->operand[0] = put_str(extentry.addr, extentry.len); *nxtopr = put_tref(ref); nxtopr = &ref->operand[1]; cnt++; # endif if (TK_LPAREN != TREF(window_token)) { ref = newtriple(OC_PARAMETER); ref->operand[0] = put_ilit(0); *nxtopr = put_tref(ref); nxtopr = &ref->operand[1]; cnt++; ref = newtriple(OC_PARAMETER); ref->operand[0] = put_ilit(0); *nxtopr = put_tref(ref); nxtopr = &ref->operand[1]; cnt++; } else { if (!(actcnt = actuallist(nxtopr))) return FALSE; cnt += actcnt; } cnt++; /* dst mval, or 0 */ calltrip->operand[0] = put_ilit(cnt); ins_triple(calltrip); if (a) *a = put_tref(calltrip); return TRUE; } fis-gtm-V6.0-003/sr_port/f_ascii.c0000644000032200000250000000166712201176155015605 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "toktyp.h" #include "advancewindow.h" int f_ascii(oprtype *a, opctype op) { triple *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR)) return FALSE; if (TK_COMMA != TREF(window_token)) r->operand[1] = put_ilit(1); else { advancewindow(); if (EXPR_FAIL == expr(&(r->operand[1]), MUMPS_INT)) return FALSE; } ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_data.c0000644000032200000250000000325312201176155015417 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "mdq.h" #include "fullbool.h" error_def(ERR_VAREXPECTED); int f_data(oprtype *a, opctype op) { triple *oldchain, *r; save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(OC_FNDATA == op || OC_FNZDATA == op); r = maketriple(op); switch (TREF(window_token)) { case TK_IDENT: if (!lvn(&(r->operand[0]), OC_SRCHINDX, 0)) return FALSE; ins_triple(r); break; case TK_CIRCUMFLEX: if (!gvn()) return FALSE; r->opcode = OC_GVDATA; ins_triple(r); break; case TK_ATSIGN: if (SHIFT_SIDE_EFFECTS) { START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&(r->operand[0]))) { setcurtchain(oldchain); return FALSE; } r->operand[1] = put_ilit((mint)(OC_FNDATA == op ? indir_fndata : indir_fnzdata)); ins_triple(r); PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(&(r->operand[0]))) return FALSE; r->operand[1] = put_ilit((mint)(OC_FNDATA == op ? indir_fndata : indir_fnzdata)); ins_triple(r); } r->opcode = OC_INDFUN; break; default: stx_error(ERR_VAREXPECTED); return FALSE; } *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_extract.c0000644000032200000250000000305012201176155016153 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" /* $EXTRACT, $ZEXTRACT, and $ZSUBSTR use this compiler routine as all have similar function and identical invocation signatures */ int f_extract(oprtype *a, opctype op) { triple *first, *last, *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR)) return FALSE; first = newtriple(OC_PARAMETER); last = newtriple(OC_PARAMETER); r->operand[1] = put_tref(first); first->operand[1] = put_tref(last); if (TK_COMMA != TREF(window_token)) { first->operand[0] = put_ilit(1); last->operand[0] = put_ilit((OC_FNZSUBSTR == op) ? MAXPOSINT4 : 1); } else { advancewindow(); if (EXPR_FAIL == expr(&(first->operand[0]), MUMPS_INT)) return FALSE; if (TK_COMMA != TREF(window_token)) last->operand[0] = (OC_FNZSUBSTR == op) ? put_ilit(MAXPOSINT4) : first->operand[0]; else { advancewindow(); if (EXPR_FAIL == expr(&(last->operand[0]), MUMPS_INT)) return FALSE; } } ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_find.c0000644000032200000250000000250712201176155015427 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" error_def(ERR_COMMA); int f_find(oprtype *a, opctype op) { triple *delimiter, *r, *start; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR)) return FALSE; if (TK_COMMA != TREF(window_token)) { stx_error(ERR_COMMA); return FALSE; } advancewindow(); delimiter = newtriple(OC_PARAMETER); start = newtriple(OC_PARAMETER); r->operand[1] = put_tref(delimiter); delimiter->operand[1] = put_tref(start); if (EXPR_FAIL == expr(&(delimiter->operand[0]), MUMPS_STR)) return FALSE; if (TK_COMMA != TREF(window_token)) start->operand[0] = put_ilit(1); else { advancewindow(); if (EXPR_FAIL == expr(&(start->operand[0]), MUMPS_INT)) return FALSE; } ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_fnumber.c0000644000032200000250000000272512201176155016147 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "mdq.h" #include "advancewindow.h" error_def(ERR_COMMA); int f_fnumber(oprtype *a, opctype op) { triple *r, *ref, *ref1; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&r->operand[0], MUMPS_NUM)) return FALSE; if (TK_COMMA != TREF(window_token)) { stx_error(ERR_COMMA); return FALSE; } advancewindow(); ref = newtriple(OC_PARAMETER); r->operand[1] = put_tref(ref); if (EXPR_FAIL == expr(&ref->operand[0], MUMPS_STR)) return FALSE; ref1 = newtriple(OC_PARAMETER); ref->operand[1] = put_tref(ref1); if (TK_COMMA == TREF(window_token)) { advancewindow(); if (EXPR_FAIL == expr(&ref1->operand[1], MUMPS_INT)) return FALSE; ref1->operand[0] = put_ilit((mint)(1)); /* flag that the 3rd argument is real */ } else ref1->operand[0] = ref1->operand[1] = put_ilit((mint)0); /* flag no 3rd argument and give it default value */ ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_fnzbitfind.c0000644000032200000250000000243712201176155016646 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" error_def(ERR_COMMA); int f_fnzbitfind(oprtype *a, opctype op) { triple *r, *parm; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_EXPR)) /* bitstring */ return FALSE; if (TK_COMMA != TREF(window_token)) { stx_error(ERR_COMMA); return FALSE; } parm = newtriple(OC_PARAMETER); r->operand[1] = put_tref(parm); advancewindow(); if (EXPR_FAIL == expr(&(parm->operand[0]), MUMPS_INT)) /* truthval */ return FALSE; if (TK_COMMA != TREF(window_token)) parm->operand[1] = put_ilit(1); else { advancewindow(); if (EXPR_FAIL == expr(&(parm->operand[1]), MUMPS_INT)) /* position */ return FALSE; } ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_fnzbitget.c0000644000032200000250000000177312201176155016507 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "toktyp.h" #include "advancewindow.h" error_def(ERR_COMMA); int f_fnzbitget(oprtype *a, opctype op) { triple *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_EXPR)) /* bitstring */ return FALSE; if (TK_COMMA != TREF(window_token)) { stx_error(ERR_COMMA); return FALSE; } advancewindow(); if (EXPR_FAIL == expr(&(r->operand[1]), MUMPS_INT)) /* position */ return FALSE; ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_fnzbitset.c0000644000032200000250000000243312201176155016515 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" error_def(ERR_COMMA); int f_fnzbitset(oprtype *a, opctype op) { triple *r, *parm; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_EXPR)) /* bitstring */ return FALSE; if (TK_COMMA != TREF(window_token)) { stx_error(ERR_COMMA); return FALSE; } parm = newtriple(OC_PARAMETER); r->operand[1] = put_tref(parm); advancewindow(); if (EXPR_FAIL == expr(&(parm->operand[0]), MUMPS_INT)) /* position */ return FALSE; if (TK_COMMA != TREF(window_token)) { stx_error(ERR_COMMA); return FALSE; } advancewindow(); if (EXPR_FAIL == expr(&(parm->operand[1]), MUMPS_INT)) /* truthval */ return FALSE; ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_fnzbitstr.c0000644000032200000250000000174512201176155016537 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "toktyp.h" #include "advancewindow.h" int f_fnzbitstr(oprtype *a, opctype op) { triple *r, *parm; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_INT)) /* size */ return FALSE; if (TK_COMMA != TREF(window_token)) r->operand[1] = put_ilit(0); else { advancewindow(); if (EXPR_FAIL == expr(&(r->operand[1]), MUMPS_INT)) /* position */ return FALSE; } ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_get.c0000644000032200000250000000623312201176155015266 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "mmemory.h" #include "mdq.h" #include "advancewindow.h" #include "fullbool.h" #include "glvn_pool.h" #include "show_source_line.h" GBLREF boolean_t run_time; GBLREF short int source_column; error_def(ERR_SIDEEFFECTEVAL); error_def(ERR_VAREXPECTED); int f_get(oprtype *a, opctype op) { boolean_t ok, used_glvn_slot; oprtype control_slot, def_opr, *def_oprptr, indir; short int column; triple *oldchain, *opptr, *r, *triptr; save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; oldchain = NULL; used_glvn_slot = FALSE; r = maketriple(OC_NOOP); /* We'll fill in the opcode later, when we figure out what it is */ switch (TREF(window_token)) { case TK_IDENT: r->opcode = OC_FNGET; ok = lvn(&r->operand[0], OC_SRCHINDX, 0); break; case TK_CIRCUMFLEX: r->opcode = OC_FNGVGET; ok = gvn(); break; case TK_ATSIGN: r->opcode = OC_INDGET2; if (SHIFT_SIDE_EFFECTS) START_GVBIND_CHAIN(&save_state, oldchain); if (ok = indirection(&indir)) /* NOTE: assignment */ { used_glvn_slot = TRUE; INSERT_INDSAVGLVN(control_slot, indir, ANY_SLOT, 1); r->operand[0] = control_slot; } break; default: ok = FALSE; break; } if (!ok) { if (NULL != oldchain) setcurtchain(oldchain); stx_error(ERR_VAREXPECTED); return FALSE; } opptr = r; ins_triple(r); if (used_glvn_slot) { /* house cleaning for the indirection */ triptr = newtriple(OC_GLVNPOP); triptr->operand[0] = control_slot; } if (TK_COMMA == TREF(window_token)) { /* two argument form with a specified default value */ advancewindow(); column = source_column; def_oprptr = (oprtype *)mcalloc(SIZEOF(oprtype)); def_opr = put_indr(def_oprptr); DISABLE_SIDE_EFFECT_AT_DEPTH; /* doing this here let's us know specifically if direction had SE threat */ if (EXPR_FAIL == expr(def_oprptr, MUMPS_EXPR)) { if (NULL != oldchain) setcurtchain(oldchain); return FALSE; } if (SE_WARN_ON && (TREF(side_effect_base))[TREF(expr_depth)]) ISSUE_SIDEEFFECTEVAL_WARNING(column - 1); if (OC_FNGET == r->opcode) r->opcode = OC_FNGET1; else if (OC_FNGVGET == r->opcode) r->opcode = OC_FNGVGET1; else assert(OC_INDGET2 == r->opcode); r = newtriple(OC_FNGET2); r->operand[0] = put_tref(opptr); r->operand[1] = def_opr; } else if (OC_INDGET2 == r->opcode) { /* indirect always acts like a two argument form so force that along with an empty string default */ r = newtriple(OC_FNGET2); r->operand[0] = put_tref(opptr); r->operand[1] = put_str(0, 0); } if (NULL != oldchain) PLACE_GVBIND_CHAIN(&save_state, oldchain); /* shift chain back to "expr_start" */ *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_get1.c0000644000032200000250000000331112201176155015341 0ustar librarygtc/**************************************************************** * * * Copyright 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "toktyp.h" #include "opcode.h" #include "indir_enum.h" #include "mdq.h" #include "op.h" #include "fullbool.h" error_def(ERR_VAREXPECTED); int f_get1(oprtype *a, opctype op) { triple *oldchain, *r; save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(OC_NOOP); /* We'll fill in the opcode later, when we figure out what it is */ switch (TREF(window_token)) { case TK_IDENT: r->opcode = OC_FNGET1; if (!lvn(&r->operand[0], OC_SRCHINDX, 0)) return FALSE; break; case TK_CIRCUMFLEX: r->opcode = OC_FNGVGET1; if (!gvn()) return FALSE; break; case TK_ATSIGN: r->opcode = OC_INDFUN; r->operand[1] = put_ilit((mint)indir_get); if (SHIFT_SIDE_EFFECTS) { /* with short-circuited booleans move indirect processing to expr_start */ START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&r->operand[0])) { setcurtchain(oldchain); return FALSE; } ins_triple(r); PLACE_GVBIND_CHAIN(&save_state, oldchain); *a = put_tref(r); return TRUE; } if (!indirection(&(r->operand[0]))) return FALSE; break; default: stx_error(ERR_VAREXPECTED); return FALSE; } ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_incr.c0000644000032200000250000001065412201176155015444 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "mdq.h" #include "advancewindow.h" #include "fullbool.h" #include "show_source_line.h" error_def(ERR_VAREXPECTED); int f_incr(oprtype *a, opctype op) { boolean_t ok; oprtype *increment; triple incrchain, *oldchain, *r, *savptr, targchain, tmpexpr, *triptr; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); /* may need to evaluate the increment (2nd arg) early and use result later: prepare to juggle triple chains */ dqinit(&targchain, exorder); /* a place for the operation and the target */ dqinit(&tmpexpr, exorder); /* a place to juggle the shifted chain in case it's active */ triptr = TREF(expr_start); savptr = TREF(expr_start_orig); /* but make sure expr_start_orig == expr_start since this is a new chain */ TREF(expr_start_orig) = TREF(expr_start) = &tmpexpr; oldchain = setcurtchain(&targchain); /* save the result of the first argument 'cause it evaluates 2nd */ switch (TREF(window_token)) { case TK_IDENT: /* $INCREMENT() performs an implicit $GET() on a first argument lvn so we use OC_PUTINDX because * we know only at runtime whether to signal an UNDEF error (depending on whether we have * VIEW "NOUNDEF" or "UNDEF" state; op_putindx creates the local variable unconditionally, even if * we have "UNDEF" state, in which case any error in op_fnincr causes an op_kill of that local variable */ ok = (lvn(&(r->operand[0]), OC_PUTINDX, 0)); break; case TK_CIRCUMFLEX: ok = gvn(); r->opcode = OC_GVINCR; r->operand[0] = put_ilit(0); /* dummy fill since emit_code does not like empty operand[0] */ break; case TK_ATSIGN: ok = indirection(&r->operand[0]); r->opcode = OC_INDINCR; break; default: ok = FALSE; break; } if (!ok) { setcurtchain(oldchain); return FALSE; } TREF(expr_start) = triptr; /* restore original shift chain */ TREF(expr_start_orig) = savptr; increment = &r->operand[1]; if (TK_COMMA != TREF(window_token)) *increment = put_ilit(1); /* default optional increment to 1 */ else { dqinit(&incrchain, exorder); /* a place for the increment */ setcurtchain(&incrchain); /* increment expr must evaluate before the glvn in $INCR(glvn,expr) */ advancewindow(); if (EXPR_FAIL == expr(increment, MUMPS_NUM)) { setcurtchain(oldchain); return FALSE; } dqadd(&targchain, &incrchain, exorder); /* dir before targ - this is a violation of info hiding */ setcurtchain(&targchain); } coerce(increment, OCT_MVAL); ins_triple(r); if (&tmpexpr != tmpexpr.exorder.bl) { /* one or more OC_GVNAME may have shifted so add to the end of the shift chain */ assert(TREF(shift_side_effects)); dqadd(TREF(expr_start), &tmpexpr, exorder); /* this is a violation of info hiding */ TREF(expr_start) = tmpexpr.exorder.bl; assert(OC_GVSAVTARG == (TREF(expr_start))->opcode); triptr = newtriple(OC_GVRECTARG); /* restore the result of the last gvn to preserve $referece (the naked) */ triptr->operand[0] = put_tref(TREF(expr_start)); } if (!TREF(shift_side_effects) || (GTM_BOOL != TREF(gtm_fullbool)) || (OC_INDINCR != r->opcode)) { /* put it on the end of the main chain as there's no reason to play more with the ordering */ setcurtchain(oldchain); triptr = (TREF(curtchain))->exorder.bl; dqadd(triptr, &targchain, exorder); /* this is a violation of info hiding */ } else /* need full side effects or indirect 1st argument so put everything on the shift chain */ { /* add the chain after "expr_start" which may be much before "curtchain" */ newtriple(OC_GVSAVTARG); setcurtchain(oldchain); assert(NULL != TREF(expr_start)); dqadd(TREF(expr_start), &targchain, exorder); /* this is a violation of info hiding */ TREF(expr_start) = targchain.exorder.bl; triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(TREF(expr_start)); } /* $increment() args need to avoid side effect processing but that's handled in expritem so eval_expr gets $i()'s SE flag */ *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_justify.c0000644000032200000250000000234712201176155016206 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" error_def(ERR_COMMA); int f_justify(oprtype *a, opctype op) { triple *r, *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&r->operand[0], MUMPS_STR)) return FALSE; if (TK_COMMA != TREF(window_token)) { stx_error(ERR_COMMA); return FALSE; } advancewindow(); if (EXPR_FAIL == expr(&r->operand[1], MUMPS_INT)) return FALSE; if (TK_COMMA == TREF(window_token)) { r->opcode = OC_FNJ3; ref = newtriple(OC_PARAMETER); ref->operand[0] = r->operand[1]; r->operand[1] = put_tref(ref); advancewindow(); if (EXPR_FAIL == expr(&ref->operand[1], MUMPS_INT)) return FALSE; } ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_length.c0000644000032200000250000000211412201176155015762 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" int f_length(oprtype *a, opctype op) { triple *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert((OC_FNLENGTH == op) || (OC_FNZLENGTH == op)); r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR)) return FALSE; if (TK_COMMA == TREF(window_token)) { advancewindow(); r->opcode = (OC_FNLENGTH == op) ? OC_FNPOPULATION : OC_FNZPOPULATION; /* Not good information hiding */ if (EXPR_FAIL == expr(&(r->operand[1]), MUMPS_STR)) return FALSE; } ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_mint.c0000644000032200000250000000125312201176155015453 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" int f_mint(oprtype *a, opctype op) { triple *r; r = maketriple(op); if (EXPR_FAIL == expr(&r->operand[0], MUMPS_INT)) return FALSE; ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_mint_mstr.c0000644000032200000250000000174212201176155016523 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" error_def(ERR_COMMA); int f_mint_mstr(oprtype *a, opctype op) { triple *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&r->operand[0], MUMPS_INT)) return FALSE; if (TK_COMMA != TREF(window_token)) { stx_error(ERR_COMMA); return FALSE; } advancewindow(); if (EXPR_FAIL == expr(&r->operand[1], MUMPS_STR)) return FALSE; ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_mstr.c0000644000032200000250000000125312201176155015471 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" int f_mstr(oprtype *a, opctype op) { triple *r; r = maketriple(op); if (EXPR_FAIL == expr(&r->operand[0], MUMPS_STR)) return FALSE; ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_name.c0000644000032200000250000000470612201176155015432 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "indir_enum.h" #include "advancewindow.h" #include "subscript.h" #include "fullbool.h" #include "show_source_line.h" GBLREF boolean_t run_time; GBLREF short int source_column; error_def(ERR_SIDEEFFECTEVAL); error_def(ERR_VAREXPECTED); int f_name(oprtype *a, opctype op) { boolean_t gbl; oprtype *depth; short int column; triple *r, *s; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); gbl = FALSE; switch (TREF(window_token)) { case TK_CIRCUMFLEX: gbl = TRUE; advancewindow(); /* caution fall through */ case TK_IDENT: if (!name_glvn(gbl, &r->operand[1])) return FALSE; depth = &r->operand[0]; break; case TK_ATSIGN: r->opcode = OC_INDFNNAME2; /* chomps extra subscripts of resulting string */ s = maketriple(OC_INDFNNAME); if (!indirection(&(s->operand[0]))) return FALSE; s->operand[1] = put_ilit(MAX_LVSUBSCRIPTS + 1); /* first, get all the subscripts. r will chomp them */ coerce(&s->operand[1], OCT_MVAL); ins_triple(s); depth = &r->operand[0]; r->operand[1] = put_tref(s); break; default: stx_error(ERR_VAREXPECTED); return FALSE; } /* allow for optional default value */ if (TK_COMMA != TREF(window_token)) { *depth = put_ilit(MAX_LVSUBSCRIPTS + 1); /* default to maximum number of subscripts allowed by law */ /* ideally this should be MAX(MAX_LVSUBSCRIPTS, MAX_GVSUBSCRIPTS) but they are the same so take the easy path */ assert(MAX_LVSUBSCRIPTS == MAX_GVSUBSCRIPTS); /* add assert to ensure our assumption is valid */ } else { DISABLE_SIDE_EFFECT_AT_DEPTH; /* doing this here let's us know specifically if direction had SE threat */ advancewindow(); column = source_column; if (EXPR_FAIL == expr(depth, MUMPS_STR)) return FALSE; if (!run_time && (OC_INDFNNAME2 == r->opcode) && (SE_WARN == TREF(side_effect_handling))) ISSUE_SIDEEFFECTEVAL_WARNING(column - 1); } coerce(depth, OCT_MVAL); ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_next.c0000644000032200000250000000407712201176155015471 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "mdq.h" #include "fullbool.h" error_def(ERR_GVNEXTARG); error_def(ERR_LVORDERARG); error_def(ERR_VAREXPECTED); int f_next(oprtype *a, opctype op) { triple *oldchain, *ref, *r; save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); switch (TREF(window_token)) { case TK_IDENT: if (TK_LPAREN != TREF(director_token)) { stx_error(ERR_LVORDERARG); return FALSE; } if (!lvn(&(r->operand[0]), OC_SRCHINDX,r)) return FALSE; ins_triple(r); break; case TK_CIRCUMFLEX: ref = TREF(shift_side_effects) ? TREF(expr_start) : (TREF(curtchain))->exorder.bl; if (!gvn()) return FALSE; /* the following assumes OC_LIT and OC_GVNAME are all one gets for an unsubscripted global variable reference */ if ((TREF(shift_side_effects) ? TREF(expr_start) : TREF(curtchain))->exorder.bl->exorder.bl->exorder.bl == ref) { stx_error(ERR_GVNEXTARG); return FALSE; } r->opcode = OC_GVNEXT; ins_triple(r); break; case TK_ATSIGN: if (SHIFT_SIDE_EFFECTS) { START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&(r->operand[0]))) { setcurtchain(oldchain); return FALSE; } r->operand[1] = put_ilit((mint)indir_fnnext); ins_triple(r); PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(&(r->operand[0]))) return FALSE; r->operand[1] = put_ilit((mint)indir_fnnext); ins_triple(r); } r->opcode = OC_INDFUN; break; default: stx_error(ERR_VAREXPECTED); return FALSE; } *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_one_mval.c0000644000032200000250000000136612201176155016311 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "toktyp.h" int f_one_mval(oprtype *a, opctype op) { triple *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_EXPR)) return FALSE; ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_order.c0000644000032200000250000001645112201176155015625 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "fnorder.h" #include "mdq.h" #include "mmemory.h" #include "advancewindow.h" #include "mvalconv.h" #include "fullbool.h" #include "glvn_pool.h" #include "show_source_line.h" GBLREF boolean_t run_time; GBLREF short int source_column; error_def(ERR_ORDER2); error_def(ERR_SIDEEFFECTEVAL); error_def(ERR_VAREXPECTED); LITDEF opctype order_opc[LAST_OBJECT][LAST_DIRECTION] = { /* FORWARD BACKWARD TBD */ { OC_GVORDER, OC_ZPREVIOUS, OC_GVO2 }, /* GLOBAL */ { OC_FNORDER, OC_FNZPREVIOUS, OC_FNO2 }, /* LOCAL */ { OC_FNLVNAME, OC_FNLVPRVNAME, OC_FNLVNAMEO2 }, /* LOCAL_NAME */ { OC_INDFUN, OC_INDFUN, OC_INDO2 } /* INDIRECT */ }; int f_order(oprtype *a, opctype op) { boolean_t ok, used_glvn_slot; enum order_dir direction; enum order_obj object; int4 intval; opctype gv_oc; oprtype control_slot, dir_opr, *dir_oprptr, *next_oprptr; short int column; triple *oldchain, *r, *sav_dirref, *sav_gv1, *sav_gvn, *sav_lvn, *sav_ref, *share, *triptr; triple *chain2, *obp, tmpchain2; save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; oldchain = sav_dirref = NULL; /* default to no direction and no shifting indirection */ used_glvn_slot = FALSE; sav_gv1 = TREF(curtchain); r = maketriple(OC_NOOP); /* We'll fill in the opcode later, when we figure out what it is */ switch (TREF(window_token)) { case TK_IDENT: if (TK_LPAREN == TREF(director_token)) { object = LOCAL; ok = lvn(&r->operand[0], OC_SRCHINDX, r); /* 2nd arg causes us to mess below with return from lvn */ } else { object = LOCAL_NAME; ok = TRUE; r->operand[0] = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); advancewindow(); } next_oprptr = &r->operand[1]; break; case TK_CIRCUMFLEX: object = GLOBAL; ok = gvn(); sav_gvn = (TREF(curtchain))->exorder.bl; next_oprptr = &r->operand[0]; break; case TK_ATSIGN: object = INDIRECT; if (SHIFT_SIDE_EFFECTS) START_GVBIND_CHAIN(&save_state, oldchain); ok = indirection(&r->operand[0]); next_oprptr = &r->operand[1]; break; default: ok = FALSE; break; } if (!ok) { if (NULL != oldchain) setcurtchain(oldchain); stx_error(ERR_VAREXPECTED); return FALSE; } if (TK_COMMA != TREF(window_token)) direction = FORWARD; /* default direction */ else { /* two argument form: ugly logic for direction */ advancewindow(); column = source_column; dir_oprptr = (oprtype *)mcalloc(SIZEOF(oprtype)); dir_opr = put_indr(dir_oprptr); sav_ref = newtriple(OC_GVSAVTARG); DISABLE_SIDE_EFFECT_AT_DEPTH; /* doing this here let's us know specifically if direction had SE threat */ if (EXPR_FAIL == expr(dir_oprptr, MUMPS_EXPR)) { if (NULL != oldchain) setcurtchain(oldchain); return FALSE; } assert(TRIP_REF == dir_oprptr->oprclass); triptr = dir_oprptr->oprval.tref; if (OC_LIT == triptr->opcode) { /* if direction is a literal - pick it up and stop flailing about */ if (MV_IS_TRUEINT(&triptr->operand[0].oprval.mlit->v, &intval) && (1 == intval || -1 == intval)) { direction = (1 == intval) ? FORWARD : BACKWARD; sav_ref->opcode = OC_NOOP; sav_ref = NULL; } else { /* bad direction */ if (NULL != oldchain) setcurtchain(oldchain); stx_error(ERR_ORDER2); return FALSE; } } else { direction = TBD; sav_dirref = newtriple(OC_GVSAVTARG); /* $R reflects direction eval even if we revisit 1st arg */ triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(sav_ref); switch (object) { case GLOBAL: /* The direction may have had a side effect, so take copies of subscripts */ *next_oprptr = *dir_oprptr; for (; sav_gvn != sav_gv1; sav_gvn = sav_gvn->exorder.bl) { /* hunt down the gv opcode */ gv_oc = sav_gvn->opcode; if ((OC_GVNAME == gv_oc) || (OC_GVNAKED == gv_oc) || (OC_GVEXTNAM == gv_oc)) break; } assert((OC_GVNAME == gv_oc) || (OC_GVNAKED == gv_oc) || (OC_GVEXTNAM == gv_oc)); TREF(temp_subs) = TRUE; create_temporaries(sav_gvn, gv_oc); break; case LOCAL: /* Additionally need to move srchindx triple to after potential side effect */ triptr = newtriple(OC_PARAMETER); triptr->operand[0] = *next_oprptr; triptr->operand[1] = *(&dir_opr); *next_oprptr = put_tref(triptr); sav_lvn = r->operand[0].oprval.tref; assert((OC_SRCHINDX == sav_lvn->opcode) || (OC_VAR == sav_lvn->opcode)); if (OC_SRCHINDX == sav_lvn->opcode) { dqdel(sav_lvn, exorder); ins_triple(sav_lvn); TREF(temp_subs) = TRUE; create_temporaries(sav_lvn, OC_SRCHINDX); } assert(&r->operand[1] == next_oprptr); assert(TRIP_REF == next_oprptr->oprclass); assert(OC_PARAMETER == next_oprptr->oprval.tref->opcode); assert(TRIP_REF == next_oprptr->oprval.tref->operand[0].oprclass); sav_lvn = next_oprptr->oprval.tref->operand[0].oprval.tref; if ((OC_VAR == sav_lvn->opcode) || (OC_GETINDX == sav_lvn->opcode)) { /* lvn excludes the last subscript from srchindx and attaches it to the "parent" * now we find it is an lvn and needs protection too */ triptr = maketriple(OC_STOTEMP); triptr->operand[0] = put_tref(sav_lvn); dqins(sav_lvn, exorder, triptr); /* NOTE: violation of info hiding */ next_oprptr->oprval.tref->operand[0].oprval.tref = triptr; } break; case INDIRECT: /* Save and restore the variable lookup for true left-to-right evaluation */ *next_oprptr = *dir_oprptr; used_glvn_slot = TRUE; dqinit(&tmpchain2, exorder); chain2 = setcurtchain(&tmpchain2); INSERT_INDSAVGLVN(control_slot, r->operand[0], ANY_SLOT, 1); setcurtchain(chain2); obp = sav_ref->exorder.bl; /* insert before second arg */ dqadd(obp, &tmpchain2, exorder); r->operand[0] = control_slot; break; case LOCAL_NAME: /* left argument is a string - side effect can't screw it up */ *next_oprptr = *dir_oprptr; break; default: assert(FALSE); } ins_triple(r); if (used_glvn_slot) { triptr = newtriple(OC_GLVNPOP); triptr->operand[0] = control_slot; } if (SE_WARN_ON && (TREF(side_effect_base))[TREF(expr_depth)]) ISSUE_SIDEEFFECTEVAL_WARNING(column - 1); DISABLE_SIDE_EFFECT_AT_DEPTH; /* usual side effect processing doesn't work for $ORDER() */ } } if (TBD != direction) ins_triple(r); if (NULL != sav_dirref) { triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(sav_dirref); } r->opcode = order_opc[object][direction]; /* finally - the op code */ if (NULL != oldchain) PLACE_GVBIND_CHAIN(&save_state, oldchain); /* shift chain back to "expr_start" */ if (OC_FNLVNAME == r->opcode) *next_oprptr = put_ilit(0); /* Flag not to return aliases with no value */ if (OC_INDFUN == r->opcode) *next_oprptr = put_ilit((mint)((FORWARD == direction) ? indir_fnorder1 : indir_fnzprevious)); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_order1.c0000644000032200000250000000357412201176155015710 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "mdq.h" #include "advancewindow.h" #include "fullbool.h" error_def(ERR_VAREXPECTED); int f_order1(oprtype *a, opctype op) { triple *oldchain, *r; save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); switch (TREF(window_token)) { case TK_IDENT: if (TK_LPAREN != TREF(director_token)) { r->opcode = OC_FNLVNAME; r->operand[0] = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); r->operand[1] = put_ilit(0); /* FALSE - do not return aliased vars with no value */ ins_triple(r); advancewindow(); break; } if (!lvn(&(r->operand[0]), OC_SRCHINDX, r)) return FALSE; ins_triple(r); break; case TK_CIRCUMFLEX: if (!gvn()) return FALSE; r->opcode = OC_GVORDER; ins_triple(r); break; case TK_ATSIGN: if (SHIFT_SIDE_EFFECTS) { START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&(r->operand[0]))) { setcurtchain(oldchain); return FALSE; } r->operand[1] = put_ilit((mint)indir_fnorder1); ins_triple(r); PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(&(r->operand[0]))) return FALSE; r->operand[1] = put_ilit((mint)indir_fnorder1); ins_triple(r); } r->opcode = OC_INDFUN; break; default: stx_error(ERR_VAREXPECTED); return FALSE; } *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_qlength.c0000644000032200000250000000141012201176155016141 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" int f_qlength(oprtype *a, opctype op) { triple *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR)) return FALSE; ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_qsubscript.c0000644000032200000250000000166212201176155016707 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" int f_qsubscript(oprtype *a, opctype op) { triple *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR)) return FALSE; if (TK_COMMA != TREF(window_token)) return FALSE; advancewindow(); if (EXPR_FAIL == expr(&(r->operand[1]), MUMPS_INT)) return FALSE; ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_query.c0000644000032200000250000000623012201176155015651 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "mdq.h" #include "fullbool.h" error_def(ERR_VAREXPECTED); int f_query(oprtype *a, opctype op) { triple *oldchain, *r, *r0, *r1; save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (TK_IDENT == TREF(window_token)) { if (!lvn(a, OC_FNQUERY, 0)) return FALSE; assert(TRIP_REF == a->oprclass); if (OC_FNQUERY == a->oprval.tref->opcode) { assert(OC_FNQUERY == a->oprval.tref->opcode); assert(TRIP_REF == a->oprval.tref->operand[0].oprclass); assert(OC_ILIT == a->oprval.tref->operand[0].oprval.tref->opcode); assert(ILIT_REF == a->oprval.tref->operand[0].oprval.tref->operand[0].oprclass); assert(0 < a->oprval.tref->operand[0].oprval.tref->operand[0].oprval.ilit); a->oprval.tref->operand[0].oprval.tref->operand[0].oprval.ilit += 2; assert(TRIP_REF == a->oprval.tref->operand[1].oprclass); assert(OC_PARAMETER == a->oprval.tref->operand[1].oprval.tref->opcode); assert(TRIP_REF == a->oprval.tref->operand[1].oprval.tref->operand[0].oprclass); r0 = a->oprval.tref->operand[1].oprval.tref->operand[0].oprval.tref; assert(OC_VAR == r0->opcode); assert(MVAR_REF == r0->operand[0].oprclass); r1 = maketriple(OC_PARAMETER); r1->operand[0] = put_str(r0->operand[0].oprval.vref->mvname.addr, r0->operand[0].oprval.vref->mvname.len); r1->operand[1] = a->oprval.tref->operand[1]; a->oprval.tref->operand[1] = put_tref (r1); dqins (a->oprval.tref->exorder.fl, exorder, r1); } else { assert(OC_VAR == a->oprval.tref->opcode); r0 = newtriple(OC_FNQUERY); r0->operand[0] = put_ilit (3); r0->operand[1] = put_tref(newtriple(OC_PARAMETER)); r0->operand[1].oprval.tref->operand[0] = put_str(a->oprval.tref->operand[0].oprval.vref->mvname.addr, a->oprval.tref->operand[0].oprval.vref->mvname.len); r1 = r0->operand[1].oprval.tref; r1->operand[1] = *a; *a = put_tref (r0); } } else { r = maketriple(op); switch (TREF(window_token)) { case TK_CIRCUMFLEX: if (!gvn()) return FALSE; r->opcode = OC_GVQUERY; ins_triple(r); break; case TK_ATSIGN: if (SHIFT_SIDE_EFFECTS) { START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&(r->operand[0]))) { setcurtchain(oldchain); return FALSE; } r->operand[1] = put_ilit((mint)indir_fnquery); ins_triple(r); PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(&(r->operand[0]))) return FALSE; r->operand[1] = put_ilit((mint)indir_fnquery); ins_triple(r); } r->opcode = OC_INDFUN; break; default: stx_error(ERR_VAREXPECTED); return FALSE; } *a = put_tref(r); } return TRUE; } fis-gtm-V6.0-003/sr_port/f_reverse.c0000644000032200000250000000142012201176155016153 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" /* #include "opcode.h" */ #include "toktyp.h" int f_reverse(oprtype *a, opctype op) { triple *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR)) return FALSE; ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_select.c0000644000032200000250000001057612201176155015773 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "mdq.h" #include "mmemory.h" #include "advancewindow.h" #include "fullbool.h" error_def(ERR_COLON); error_def(ERR_SELECTFALSE); LITREF octabstruct oc_tab[]; #define SELECT_CLEANUP \ { \ free(TREF(side_effect_base)); \ TREF(side_effect_base) = save_se_base; \ TREF(side_effect_depth) = save_se_depth; \ TREF(expr_depth) = save_expr_depth; \ } int f_select(oprtype *a, opctype op) { boolean_t first_time, save_saw_side, *save_se_base, save_shift, shifting; opctype old_op; oprtype *cnd, endtrip, target, tmparg; triple *oldchain, *r, *ref, *save_start, *save_start_orig, tmpchain, *triptr; uint4 save_expr_depth, save_se_depth; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; save_expr_depth = TREF(expr_depth); save_start = TREF(expr_start); save_start_orig = TREF(expr_start_orig); save_saw_side = TREF(saw_side_effect); save_shift = TREF(shift_side_effects); save_se_base = TREF(side_effect_base); save_se_depth = TREF(side_effect_depth); TREF(expr_depth) = 0; TREF(expr_start) = TREF(expr_start_orig) = NULL; TREF(saw_side_effect) = FALSE; TREF(shift_side_effects) = FALSE; TREF(side_effect_depth) = INITIAL_SIDE_EFFECT_DEPTH; TREF(side_effect_base) = malloc(SIZEOF(boolean_t) * TREF(side_effect_depth)); memset((char *)(TREF(side_effect_base)), 0, SIZEOF(boolean_t) * TREF(side_effect_depth)); if (shifting = (save_shift && (!save_saw_side || (GTM_BOOL == TREF(gtm_fullbool))))) /* NOTE assignment */ { dqinit(&tmpchain, exorder); oldchain = setcurtchain(&tmpchain); } r = maketriple(op); first_time = TRUE; endtrip = put_tjmp(r); for (;;) { cnd = (oprtype *)mcalloc(SIZEOF(oprtype)); if (!bool_expr(FALSE, cnd)) { SELECT_CLEANUP; if (shifting) setcurtchain(oldchain); return FALSE; } if (TK_COLON != TREF(window_token)) { SELECT_CLEANUP; if (shifting) setcurtchain(oldchain); stx_error(ERR_COLON); return FALSE; } advancewindow(); if (EXPR_FAIL == expr(&tmparg, MUMPS_EXPR)) { SELECT_CLEANUP; if (shifting) setcurtchain(oldchain); return FALSE; } assert(TRIP_REF == tmparg.oprclass); old_op = tmparg.oprval.tref->opcode; if (first_time) { if ((OC_LIT == old_op) || (oc_tab[old_op].octype & OCT_MVADDR)) { ref = newtriple(OC_STOTEMP); ref->operand[0] = tmparg; tmparg = put_tref(ref); } r->operand[0] = target = tmparg; first_time = FALSE; } else { ref = newtriple(OC_STO); ref->operand[0] = target; ref->operand[1] = tmparg; if (OC_PASSTHRU == tmparg.oprval.tref->opcode) { assert(TRIP_REF == tmparg.oprval.tref->operand[0].oprclass); ref = newtriple(OC_STO); ref->operand[0] = target; ref->operand[1] = put_tref(tmparg.oprval.tref->operand[0].oprval.tref); } } ref = newtriple(OC_JMP); ref->operand[0] = endtrip; tnxtarg(cnd); if (TK_COMMA != TREF(window_token)) break; advancewindow(); } tmparg = put_ilit(ERR_SELECTFALSE); ref = newtriple(OC_RTERROR); ref->operand[0] = tmparg; ref->operand[1] = put_ilit(FALSE); /* Not a subroutine reference */ ins_triple(r); assert(!TREF(expr_depth)); TREF(expr_start) = save_start; TREF(expr_start_orig) = save_start_orig; TREF(saw_side_effect) = save_saw_side; TREF(shift_side_effects) = save_shift; SELECT_CLEANUP; TREF(expr_depth) = save_expr_depth; if (shifting) { shifting = ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)); newtriple(shifting ? OC_GVSAVTARG : OC_NOOP); /* must have one of these two at expr_start */ setcurtchain(oldchain); dqadd(TREF(expr_start), &tmpchain, exorder); TREF(expr_start) = tmpchain.exorder.bl; if (shifting) { /* only play this game if something else started it */ assert(OC_GVSAVTARG == (TREF(expr_start))->opcode); triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(TREF(expr_start)); } } *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_stack.c0000644000032200000250000000176212201176155015616 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" int f_stack(oprtype *a, opctype op) { triple *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_INT)) return FALSE; if (TK_COMMA == TREF(window_token)) { advancewindow(); r->opcode = OC_FNSTACK2; /*This isn't very good information hiding*/ if (EXPR_FAIL == expr(&(r->operand[1]), MUMPS_STR)) return FALSE; } ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_text.c0000644000032200000250000000750512201176155015476 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "cmd_qlf.h" #include "advancewindow.h" #include "gtm_caseconv.h" static readonly mstr zero_mstr; GBLREF boolean_t run_time; GBLREF mident routine_name; GBLREF command_qualifier cmd_qlf; error_def(ERR_RTNNAME); error_def(ERR_TEXTARG); int f_text(oprtype *a, opctype op) { int implicit_offset = 0; triple *label, *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); switch (TREF(window_token)) { case TK_CIRCUMFLEX: implicit_offset = 1; /* CAUTION - fall-through */ case TK_PLUS: r->operand[0] = put_str(zero_mstr.addr, 0); /* Null label - top of routine */ break; case TK_INTLIT: int_label(); /* CAUTION - fall through */ case TK_IDENT: if (!(cmd_qlf.qlf & CQ_LOWER_LABELS)) lower_to_upper((uchar_ptr_t)(TREF(window_ident)).addr, (uchar_ptr_t)(TREF(window_ident)).addr, (TREF(window_ident)).len); r->operand[0] = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); advancewindow(); break; case TK_ATSIGN: if (!indirection(&(r->operand[0]))) return FALSE; r->opcode = OC_INDTEXT; break; default: stx_error(ERR_TEXTARG); return FALSE; } /* The assert below can be useful when working on $TEXT parsing issues but causes problems in debug builds with * bad syntax asserts. Hence it is normally commented out. Uncomment to re-enable for $TEXT parsing issues. */ /* assert((TK_PLUS == TREF(window_token)) || (TK_CIRCUMFLEX == TREF(window_token)) || (TK_RPAREN == TREF(window_token)) * || (TK_EOL == TREF(window_token))); */ if ((OC_INDTEXT != r->opcode) || (TK_PLUS == TREF(window_token)) || (TK_CIRCUMFLEX == TREF(window_token))) { /* Need another parm chained in to deal with offset and routine name except for the case where an * indirect specifies the entire argument. */ label = newtriple(OC_PARAMETER); r->operand[1] = put_tref(label); } if (TK_PLUS != TREF(window_token)) { if ((OC_INDTEXT != r->opcode) || (TK_CIRCUMFLEX == TREF(window_token))) /* Set default offset (0 or 1 as computed above) when offset not specified */ label->operand[0] = put_ilit(implicit_offset); else { /* Fill in indirect text for case where indirect specifies entire operand */ r->opcode = OC_INDFUN; r->operand[1] = put_ilit((mint)indir_fntext); } } else { /* Process offset */ advancewindow(); if (EXPR_FAIL == expr(&(label->operand[0]), MUMPS_INT)) return FALSE; } if (TK_CIRCUMFLEX != TREF(window_token)) { /* No routine specified - default to current routine */ if (OC_INDFUN != r->opcode) { if (!run_time) label->operand[1] = put_str(routine_name.addr, routine_name.len); else label->operand[1] = put_tref(newtriple(OC_CURRTN)); } } else { /* Routine has been specified - pull it */ advancewindow(); switch (TREF(window_token)) { case TK_IDENT: # ifdef GTM_TRIGGER if (TK_HASH == TREF(director_token)) /* Coagulate tokens as necessary (and available) to allow '#' in the routine name */ advwindw_hash_in_mname_allowed(); # endif label->operand[1] = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); advancewindow(); break; case TK_ATSIGN: if (!indirection(&label->operand[1])) return FALSE; r->opcode = OC_INDTEXT; break; default: stx_error(ERR_RTNNAME); return FALSE; } } ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_translate.c0000644000032200000250000000244212201176155016502 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" LITREF mval literal_null; int f_translate(oprtype *a, opctype op) { boolean_t more_args; int i; triple *args[3]; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; args[0] = maketriple(op); if (EXPR_FAIL == expr(&(args[0]->operand[0]), MUMPS_EXPR)) return FALSE; for (i = 1 , more_args = TRUE ; i < 3 ; i++) { args[i] = newtriple(OC_PARAMETER); if (more_args) { if (TK_COMMA != TREF(window_token)) more_args = FALSE; else { advancewindow(); if (EXPR_FAIL == expr(&(args[i]->operand[0]), MUMPS_EXPR)) return FALSE; } } if (!more_args) args[i]->operand[0] = put_lit((mval *)&literal_null); args[i - 1]->operand[1] = put_tref(args[i]); } ins_triple(args[0]); *a = put_tref(args[0]); return TRUE; } fis-gtm-V6.0-003/sr_port/f_two_mstrs.c0000644000032200000250000000174212201176155016550 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" error_def(ERR_COMMA); int f_two_mstrs(oprtype *a, opctype op) { triple *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&r->operand[0], MUMPS_STR)) return FALSE; if (TK_COMMA != TREF(window_token)) { stx_error(ERR_COMMA); return FALSE; } advancewindow(); if (EXPR_FAIL == expr(&r->operand[1], MUMPS_STR)) return FALSE; ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_two_mval.c0000644000032200000250000000172312201176155016336 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "toktyp.h" #include "advancewindow.h" error_def(ERR_COMMA); int f_two_mval(oprtype *a, opctype op) { triple *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_EXPR)) return FALSE; if (TK_COMMA != TREF(window_token)) { stx_error(ERR_COMMA); return FALSE; } advancewindow(); if (EXPR_FAIL == expr(&(r->operand[1]), MUMPS_EXPR)) return FALSE; ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_view.c0000644000032200000250000000271312201176155015460 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" error_def(ERR_FCHARMAXARGS); int f_view(oprtype *a, opctype op) { int argc; oprtype *argp, argv[CHARMAXARGS]; triple *curr, *last, *root; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; argp = &argv[0]; argc = 0; if (EXPR_FAIL == expr(argp, MUMPS_EXPR)) return FALSE; assert(TRIP_REF == argp->oprclass); argc++; argp++; for (;;) { if (TK_COMMA != TREF(window_token)) break; advancewindow(); if (EXPR_FAIL == expr(argp, MUMPS_EXPR)) return FALSE; assert(TRIP_REF == argp->oprclass); argc++; argp++; if (argc >= CHARMAXARGS - 1) { stx_error(ERR_FCHARMAXARGS); return FALSE; } } root = last = maketriple(op); root->operand[0] = put_ilit(argc + 1); argp = &argv[0]; for (; argc > 0 ;argc--, argp++) { curr = newtriple(OC_PARAMETER); curr->operand[0] = *argp; last->operand[1] = put_tref(curr); last = curr; } ins_triple(root); *a = put_tref(root); return TRUE; } fis-gtm-V6.0-003/sr_port/f_zahandle.c0000644000032200000250000000307212201176155016273 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "mdq.h" #include "fullbool.h" error_def(ERR_NAMEEXPECTED); error_def(ERR_VAREXPECTED); int f_zahandle(oprtype *a, opctype op) { triple *oldchain, *r; save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); switch (TREF(window_token)) { case TK_IDENT: if (!lvn(&(r->operand[0]), OC_GETINDX, 0)) return FALSE; ins_triple(r); break; case TK_CIRCUMFLEX: stx_error(ERR_NAMEEXPECTED); return FALSE; case TK_ATSIGN: if (SHIFT_SIDE_EFFECTS) { START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&(r->operand[0]))) { setcurtchain(oldchain); return FALSE; } r->operand[1] = put_ilit((mint)indir_fnzahandle); ins_triple(r); PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(&(r->operand[0]))) return FALSE; r->operand[1] = put_ilit((mint)indir_fnzahandle); ins_triple(r); } r->opcode = OC_INDFUN; break; default: stx_error(ERR_VAREXPECTED); return FALSE; } *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_zcall.c0000644000032200000250000000315012201176155015607 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" error_def(ERR_FCHARMAXARGS); int f_zcall(oprtype *a, opctype op) { int argc; oprtype *argp, argv[CHARMAXARGS]; triple *curr,*ref, *last, *root; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; argp = &argv[0]; argc = 0; if (EXPR_FAIL == expr(argp, MUMPS_EXPR)) return FALSE; assert(TRIP_REF == argp->oprclass); argc++; argp++; for (;;) { if (TK_COMMA != TREF(window_token)) break; advancewindow(); if (TK_COMMA == TREF(window_token) || TK_RPAREN == TREF(window_token)) { ref = newtriple(OC_NULLEXP); *argp = put_tref(ref); } else { if (EXPR_FAIL == expr(argp, MUMPS_EXPR)) return FALSE; assert(TRIP_REF == argp->oprclass); } argc++; argp++; if (argc >= CHARMAXARGS) { stx_error(ERR_FCHARMAXARGS); return FALSE; } } root = last = maketriple(op); root->operand[0] = put_ilit(argc + 1); argp = &argv[0]; for (; argc > 0 ;argc--, argp++) { curr = newtriple(OC_PARAMETER); curr->operand[0] = *argp; last->operand[1] = put_tref(curr); last = curr; } ins_triple(root); *a = put_tref(root); return TRUE; } fis-gtm-V6.0-003/sr_port/f_zchar.c0000644000032200000250000000425312201176155015616 0ustar librarygtc/**************************************************************** * * * Copyright 2010, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "stringpool.h" #include "gtm_iconv.h" #include "io.h" #include "iosp.h" #ifdef __MVS__ #include "gtm_unistd.h" #endif #include "advancewindow.h" GBLREF spdesc stringpool; error_def(ERR_FCHARMAXARGS); error_def(ERR_TEXT); int f_zchar(oprtype *a, opctype op) { boolean_t all_lits; char *c; unsigned char *tmp_ptr; int argc, i; unsigned int tmp_len; mval v; oprtype argv[CHARMAXARGS], *argp; triple *curr, *last, *root; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; all_lits = TRUE; argp = &argv[0]; argc = 0; for (;;) { if (EXPR_FAIL == expr(argp, MUMPS_INT)) return FALSE; assert(TRIP_REF == argp->oprclass); if (OC_ILIT != argp->oprval.tref->opcode) all_lits = FALSE; argc++; argp++; if (TK_COMMA != TREF(window_token)) break; advancewindow(); if (argc >= CHARMAXARGS) { stx_error(ERR_FCHARMAXARGS); return FALSE; } } if (all_lits) { ENSURE_STP_FREE_SPACE(argc + 1); v.mvtype = MV_STR; v.str.addr = c = (char *)stringpool.free; argp = &argv[0]; for (; argc > 0 ;argc--, argp++) { i = argp->oprval.tref->operand[0].oprval.ilit; if ((i >= 0) && (i < 256)) /* only true for single byte character set */ *c++ = i; } *c = '\0'; v.str.len = INTCAST(c - v.str.addr); stringpool.free = (unsigned char *)c; s2n(&v); *a = put_lit(&v); return TRUE; } root = maketriple(op); root->operand[0] = put_ilit(argc + 1); last = root; argp = &argv[0]; for (; argc > 0; argc--, argp++) { curr = newtriple(OC_PARAMETER); curr->operand[0] = *argp; last->operand[1] = put_tref(curr); last = curr; } ins_triple(root); *a = put_tref(root); return TRUE; } fis-gtm-V6.0-003/sr_port/f_zconvert.c0000644000032200000250000000601512201176155016357 0ustar librarygtc/**************************************************************** * * * Copyright 2006, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #ifdef UNICODE_SUPPORTED #include "toktyp.h" #include "opcode.h" #include "advancewindow.h" #include "gtm_conv.h" error_def(ERR_BADCASECODE); error_def(ERR_BADCHSET); error_def(ERR_COMMA); /* $ZCONVERT(): 3 parameters (3rd optional) - all are string expressions. * For 2 argument $ZCONVERT, if 2nd argument is a literal, must be one of * "U", "L", or "T" (case independent) or else raise BADCASECODE error. * For 3 argument $ZCONVERT, if 2nd or 3rd arguments are literals, they * must be one of "UTF-8", "UTF-16LE", or "UTF-16BE" (case independent) * or else raise BADCHSET error. */ int f_zconvert(oprtype *a, opctype op) { triple *r, *mode, *mode2; mstr *tmpstr; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR)) return FALSE; if (TK_COMMA != TREF(window_token)) { stx_error(ERR_COMMA); return FALSE; } advancewindow(); /* 2nd parameter (required) */ mode = newtriple(OC_PARAMETER); r->operand[1] = put_tref(mode); if (EXPR_FAIL == expr(&(mode->operand[0]), MUMPS_STR)) return FALSE; /* Check for 3rd parameter */ if (TK_COMMA != TREF(window_token)) { /* 3rd parameter does not exist. Do checks for 2 arument $zconvert */ if (mode->operand[0].oprval.tref->opcode == OC_LIT && -1 == verify_case((tmpstr = &mode->operand[0].oprval.tref->operand[0].oprval.mlit->v.str))) { stx_error(ERR_BADCASECODE, 2, tmpstr->len, tmpstr->addr); return FALSE; } } else { /* 3rd parameter exists .. reel it in after error checking 2nd parm */ r->opcode = OC_FNZCONVERT3; if (mode->operand[0].oprval.tref->opcode == OC_LIT && 0 >= verify_chset((tmpstr = &mode->operand[0].oprval.tref->operand[0].oprval.mlit->v.str))) { stx_error(ERR_BADCHSET, 2, tmpstr->len, tmpstr->addr); return FALSE; } advancewindow(); mode2 = newtriple(OC_PARAMETER); mode->operand[1] = put_tref(mode2); if (EXPR_FAIL == expr(&(mode2->operand[0]), MUMPS_STR)) return FALSE; if (mode2->operand[0].oprval.tref->opcode == OC_LIT && 0 >= verify_chset((tmpstr = &mode2->operand[0].oprval.tref->operand[0].oprval.mlit->v.str))) { stx_error(ERR_BADCHSET, 2, tmpstr->len, tmpstr->addr); return FALSE; } } ins_triple(r); *a = put_tref(r); return TRUE; } #else /* Unicode is not supported */ int f_zconvert(oprtype *a, opctype op) { GTMASSERT; } #endif fis-gtm-V6.0-003/sr_port/f_zdate.c0000644000032200000250000000247412201176155015621 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" LITREF mval literal_null ; int f_zdate(oprtype *a, opctype op) /* op is not used */ { boolean_t more_args; int i; triple *args[4]; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; args[0] = maketriple(OC_FNZDATE); if (EXPR_FAIL == expr(&(args[0]->operand[0]), MUMPS_EXPR)) return FALSE; for (i = 1 , more_args = TRUE ; i < 4 ; i++) { args[i] = newtriple(OC_PARAMETER); if (more_args) { if (TK_COMMA != TREF(window_token)) more_args = FALSE; else { advancewindow(); if (EXPR_FAIL == expr(&(args[i]->operand[0]), MUMPS_EXPR)) return FALSE; } } if (!more_args) args[i]->operand[0] = put_lit((mval *)&literal_null); args[i - 1]->operand[1] = put_tref(args[i]); } ins_triple(args[0]); *a = put_tref(args[0]); return TRUE; } fis-gtm-V6.0-003/sr_port/f_zgetsyi.c0000644000032200000250000000171512201176155016205 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" int f_zgetsyi(oprtype *a, opctype op) { triple *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR)) return FALSE; if (TK_COMMA != TREF(window_token)) r->operand[1] = put_str("",0); else { advancewindow(); if (EXPR_FAIL == expr(&r->operand[1], MUMPS_STR)) return FALSE; } ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_zjobexam.c0000644000032200000250000000170212201176155016322 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" int f_zjobexam(oprtype *a, opctype op) { triple *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (TK_RPAREN == TREF(window_token)) { /* No argument specified - default to null */ r->operand[0] = put_str("",0); } else if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR)) return FALSE; /* Improper string argument */ ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_zparse.c0000644000032200000250000000237512201176155016016 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" int f_zparse(oprtype *a, opctype op) { boolean_t again; int i; triple *last, *r, *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; last = r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR)) return FALSE; again = TRUE; for (i = 0; i < 4 ;i++) { ref = newtriple(OC_PARAMETER); last->operand[1] = put_tref(ref); if (again && TK_COMMA == TREF(window_token)) { advancewindow(); if (TK_COMMA == TREF(window_token)) ref->operand[0] = put_str("", 0); else if (EXPR_FAIL == expr(&ref->operand[0], MUMPS_STR)) return FALSE; } else { again = FALSE; ref->operand[0] = put_str("", 0); } last = ref; } ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_zpeek.c0000644000032200000250000000425512201176155015627 0ustar librarygtc/**************************************************************** * * * Copyright 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" error_def(ERR_COMMA); #ifdef UNIX /* Compile 4 parameter $ZPEEK(baseadr,offset,length<,format>) function where: * * structid - A string containing a set of mnemonics that identify the structure to fetch from (see op_fnzpeek.c) * offset - Offset into the block (error if negative). * length - Length to return (error if negative or > MAX_STRLEN). * format - Option parm contains single char formatting code (see op_fnzpeek.c) */ int f_zpeek(oprtype *a, opctype op) { oprtype x; triple *offset, *length, *format, *r; mval mv; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR)) /* Structure identifier string */ return FALSE; if (TK_COMMA != TREF(window_token)) { stx_error(ERR_COMMA); return FALSE; } advancewindow(); offset = newtriple(OC_PARAMETER); r->operand[1] = put_tref(offset); if (EXPR_FAIL == expr(&(offset->operand[0]), MUMPS_INT)) return FALSE; if (TK_COMMA != TREF(window_token)) { stx_error(ERR_COMMA); return FALSE; } advancewindow(); length = newtriple(OC_PARAMETER); offset->operand[1] = put_tref(length); if (EXPR_FAIL == expr(&(length->operand[0]), MUMPS_INT)) return FALSE; format = newtriple(OC_PARAMETER); length->operand[1] = put_tref(format); if (TK_COMMA != TREF(window_token)) format->operand[0] = put_str("C", 1); /* Default format if none specified */ else { advancewindow(); if (EXPR_FAIL == expr(&(format->operand[0]), MUMPS_STR)) return FALSE; } ins_triple(r); *a = put_tref(r); return TRUE; } #else /* VMS - function not supported here */ int f_zpeek(oprtype *a, opctype op) { GTMASSERT; } #endif fis-gtm-V6.0-003/sr_port/f_zprevious.c0000644000032200000250000000346312201176155016557 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "mdq.h" #include "advancewindow.h" #include "fullbool.h" error_def(ERR_VAREXPECTED); int f_zprevious(oprtype *a, opctype op) { triple *oldchain, *r; save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); switch (TREF(window_token)) { case TK_IDENT: if (TK_LPAREN != TREF(director_token)) { r->opcode = OC_FNLVPRVNAME; r->operand[0] = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); ins_triple(r); advancewindow(); break; } if (!lvn(&(r->operand[0]), OC_SRCHINDX, r)) return FALSE; ins_triple(r); break; case TK_CIRCUMFLEX: if (!gvn()) return FALSE; r->opcode = OC_ZPREVIOUS; ins_triple(r); break; case TK_ATSIGN: if (SHIFT_SIDE_EFFECTS) { START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&(r->operand[0]))) { setcurtchain(oldchain); return FALSE; } r->operand[1] = put_ilit((mint)indir_fnzprevious); ins_triple(r); PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(&(r->operand[0]))) return FALSE; r->operand[1] = put_ilit((mint)indir_fnzprevious); ins_triple(r); } r->opcode = OC_INDFUN; break; default: stx_error(ERR_VAREXPECTED); return FALSE; } *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_zqgblmod.c0000644000032200000250000000273412201176155016330 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "mdq.h" #include "fullbool.h" error_def(ERR_VAREXPECTED); int f_zqgblmod(oprtype *a, opctype op) { triple *oldchain, *r; save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); switch (TREF(window_token)) { case TK_CIRCUMFLEX: if (!gvn()) return FALSE; r->opcode = OC_FNZQGBLMOD; ins_triple(r); break; case TK_ATSIGN: r->opcode = OC_INDFUN; if (SHIFT_SIDE_EFFECTS) { START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&(r->operand[0]))) { setcurtchain(oldchain); return FALSE; } r->operand[1] = put_ilit((mint)indir_fnzqgblmod); ins_triple(r); PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(&(r->operand[0]))) return FALSE; r->operand[1] = put_ilit((mint)indir_fnzqgblmod); ins_triple(r); } break; default: stx_error(ERR_VAREXPECTED); return FALSE; } *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_zsearch.c0000644000032200000250000000171512201176155016146 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" int f_zsearch(oprtype *a, opctype op) { triple *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR)) return FALSE; if (TK_COMMA != TREF(window_token)) r->operand[1] = put_ilit(0); else { advancewindow(); if (EXPR_FAIL == expr(&(r->operand[1]), MUMPS_INT)) return FALSE; } ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_zsigproc.c0000644000032200000250000000226112201176155016344 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" error_def(ERR_COMMA); int f_zsigproc(oprtype *a, opctype op) { triple *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); /* First argument is integer process id */ if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_INT)) return FALSE; /* Improper process id argument */ if (TK_COMMA != TREF(window_token)) { /* 2nd argument (for now) required */ stx_error(ERR_COMMA); return FALSE; } advancewindow(); /* 2nd argument is the signal number to send */ if (EXPR_FAIL == expr(&(r->operand[1]), MUMPS_INT)) return FALSE; /* Improper signal number argument */ ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_ztrigger.c0000644000032200000250000000267512201176155016352 0ustar librarygtc/**************************************************************** * * * Copyright 2010, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "toktyp.h" #include "opcode.h" #include "advancewindow.h" LITREF mval literal_null ; int f_ztrigger(oprtype *a, opctype op) { triple *r, *arg1, *arg2; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); arg1 = newtriple(OC_PARAMETER); arg2 = newtriple(OC_PARAMETER); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR)) return FALSE; if (TK_COMMA == TREF(window_token)) { /* Looking for a 2nd argument */ advancewindow(); if (EXPR_FAIL == expr(&(arg1->operand[0]), MUMPS_STR)) return FALSE; if (TK_COMMA == TREF(window_token)) { advancewindow(); if (EXPR_FAIL == expr(&(arg2->operand[0]), MUMPS_STR)) return FALSE; } else arg2->operand[0] = put_lit((mval *)&literal_null); } else { arg1->operand[0] = put_lit((mval *)&literal_null); arg2->operand[0] = put_lit((mval *)&literal_null); } r->operand[1] = put_tref(arg1); arg1->operand[1] = put_tref(arg2); ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_ztrnlnm.c0000644000032200000250000000400712201176155016210 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" int f_ztrnlnm(oprtype *a, opctype op) { boolean_t again; int i; triple *last, *r, *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; last = r = maketriple(op); if (EXPR_FAIL == expr(&r->operand[0], MUMPS_STR)) return FALSE; ref = newtriple(OC_PARAMETER); last->operand[1] = put_tref(ref); if (TK_COMMA == TREF(window_token)) { advancewindow(); if ((TK_COMMA == TREF(window_token)) || (TK_RPAREN == TREF(window_token))) ref->operand[0] = put_str("", 0); else if (EXPR_FAIL == expr(&ref->operand[0], MUMPS_STR)) return FALSE; } else ref->operand[0] = put_str("", 0); last = ref; ref = newtriple(OC_PARAMETER); last->operand[1] = put_tref(ref); if (TK_COMMA == TREF(window_token)) { advancewindow(); if ((TK_COMMA == TREF(window_token)) || (TK_RPAREN == TREF(window_token))) ref->operand[0] = put_ilit(0); else if (EXPR_FAIL == expr(&ref->operand[0], MUMPS_INT)) return FALSE; } else ref->operand[0] = put_ilit(0); last = ref; again = TRUE; for (i = 0; i < 3; i++) { ref = newtriple(OC_PARAMETER); last->operand[1] = put_tref(ref); if (again && (TK_COMMA == TREF(window_token))) { advancewindow(); if ((TK_COMMA == TREF(window_token)) || (TK_RPAREN == TREF(window_token))) ref->operand[0] = put_str("",0); else if (EXPR_FAIL == expr(&ref->operand[0], MUMPS_STR)) return FALSE; } else { again = FALSE; ref->operand[0] = put_str("",0); } last = ref; } ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_zwidth.c0000644000032200000250000000200212201176155016006 0ustar librarygtc/**************************************************************** * * * Copyright 2006, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "advancewindow.h" /* $ZWIDTH(): Single parameter - string expression */ int f_zwidth(oprtype *a, opctype op) { triple *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR)) return FALSE; ins_triple(r); *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/f_zwrite.c0000644000032200000250000000315312201176155016031 0ustar librarygtc/**************************************************************** * * * Copyright 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "mdq.h" #include "fullbool.h" /* $ZWRITE(): Single parameter - string expression */ int f_zwrite(oprtype *a, opctype op) { triple *oldchain, *r; save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (TK_ATSIGN != TREF(window_token)) { r = maketriple(op); if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR)) return FALSE; ins_triple(r); } else { r = maketriple(OC_INDFUN); if (SHIFT_SIDE_EFFECTS) { START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&(r->operand[0]))) { setcurtchain(oldchain); return FALSE; } r->operand[1] = put_ilit((mint)indir_fnzwrite); ins_triple(r); PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(&(r->operand[0]))) return FALSE; r->operand[1] = put_ilit((mint)indir_fnzwrite); ins_triple(r); } } *a = put_tref(r); return TRUE; } fis-gtm-V6.0-003/sr_port/fao_parm.h0000644000032200000250000000110312201176155015762 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ typedef struct { unsigned short len; unsigned char fill1; unsigned char fill2; char *addr; }desc_struct; #define MAX_FAO_PARMS 20 fis-gtm-V6.0-003/sr_port/fgn_glopref.c0000644000032200000250000000171412201176176016474 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* fgn_glopref : prefixes the global variable name with ^ for locks. */ #include "mdef.h" #include "gtm_string.h" #include "stringpool.h" #include #include "lv_val.h" /* needed by "fgncal.h" */ #include "fgncal.h" GBLREF spdesc stringpool ; void fgn_glopref(mval *v) { unsigned char *p; ENSURE_STP_FREE_SPACE(v->str.len + 1); p = stringpool.free; *stringpool.free++ = '^'; memcpy(stringpool.free,v->str.addr,v->str.len); stringpool.free += v->str.len ; v->str.addr = (char *)p; v->str.len++; } fis-gtm-V6.0-003/sr_port/fgncal.h0000644000032200000250000000113312201176156015434 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __FGNCAL_H__ #define __FGNCAL_H__ mval *fgncal_lookup(mval *x); void fgncal_unwind(void); void fgncal_rundown(void); #include "fgncalsp.h" #endif fis-gtm-V6.0-003/sr_port/fgncal_lookup.c0000644000032200000250000000224212201176176017024 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "toktyp.h" #include "lv_val.h" /* needed by "fgncal.h" */ #include "fgncal.h" #include "valid_mname.h" #include GBLREF symval *curr_symval; mval *fgncal_lookup(mval *x) { mval *ret_val; ht_ent_mname *tabent; var_tabent targ_key; mident ident; MV_FORCE_DEFINED(x); assert(MV_IS_STRING(x)); ret_val = NULL; ident = x->str; if (ident.len > MAX_MIDENT_LEN) ident.len = MAX_MIDENT_LEN; if (valid_mname(&ident)) { targ_key.var_name = ident; COMPUTE_HASH_MNAME(&targ_key); targ_key.marked = FALSE; if (add_hashtab_mname_symval(&curr_symval->h_symtab, &targ_key, NULL, &tabent)) lv_newname(tabent, curr_symval); ret_val = (mval *) tabent->value; } return ret_val; } fis-gtm-V6.0-003/sr_port/fgncal_unwind.c0000644000032200000250000000331212201176176017016 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "stack_frame.h" #include "tp_frame.h" #include "error.h" #include "error_trap.h" #include "mv_stent.h" #include "op.h" #include "fgncal.h" #ifdef GTM_TRIGGER #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gv_trigger.h" #include "gtm_trigger.h" #endif GBLDEF unsigned char *fgncal_stack; GBLREF unsigned char *stackbase, *stacktop, *stackwarn, *msp; GBLREF mv_stent *mv_chain; GBLREF stack_frame *frame_pointer; error_def(ERR_STACKUNDERFLO); void fgncal_unwind(void) { mv_stent *mvc; assert((msp <= stackbase) && (msp > stacktop)); assert((mv_chain <= (mv_stent *)stackbase) && (mv_chain > (mv_stent *)stacktop)); assert((frame_pointer <= (stack_frame*)stackbase) && (frame_pointer > (stack_frame *)stacktop)); while (frame_pointer && (frame_pointer < (stack_frame *)fgncal_stack)) { # ifdef GTM_TRIGGER if (SFT_TRIGR & frame_pointer->type) gtm_trigger_fini(TRUE, FALSE); else # endif op_unwind(); } for (mvc = mv_chain; mvc < (mv_stent *)fgncal_stack; ) { unw_mv_ent(mvc); mvc = (mv_stent *)(mvc->mv_st_next + (char *) mvc); } mv_chain = mvc; msp = fgncal_stack; if (msp > stackbase) rts_error(VARLSTCNT(1) ERR_STACKUNDERFLO); } fis-gtm-V6.0-003/sr_port/file_head_read.h0000644000032200000250000000114612201176156017101 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2005 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef FILE_HEAD_READ_INCLUDED #define FILE_HEAD_READ_INCLUDED boolean_t file_head_read(char *, sgmnt_data_ptr_t, int4); #endif /* FILE_HEAD_READ_INCLUDED */ fis-gtm-V6.0-003/sr_port/file_head_write.h0000644000032200000250000000125412201176156017320 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef FILE_HEAD_WRITE_INCLUDED #define FILE_HEAD_WRITE_INCLUDED boolean_t file_head_write(char *, sgmnt_data_ptr_t, int4); boolean_t file_head_write_secshr(char *, sgmnt_data_ptr_t, int4); #endif /* FILE_HEAD_WRITE_INCLUDED */ fis-gtm-V6.0-003/sr_port/fileinfo.h0000644000032200000250000000206212201176156015777 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __FILE_INFO_H__ #define __FILE_INFO_H__ #define FI_USR_SZ 31 #define FI_TRM_SZ 7 typedef struct { gtm_facility fac; /* facility */ short dat[4]; /* date (quadword) */ char usr[FI_USR_SZ]; /* user name */ char trm[FI_TRM_SZ]; /* terminal identification */ char filler[2]; /* used for longword alignment */ }file_info; #define FI_NUM_ENT 5 typedef struct { int4 cnt; /* number of entries inserted into ent. * ent is a circular queue so * ent[ cnt % FI_NUM_ENT] * is always the next location to insert. */ file_info ent[FI_NUM_ENT]; /* entries */ }file_log; #endif fis-gtm-V6.0-003/sr_port/find_line_addr.c0000644000032200000250000000451212201176176017124 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include #include "cmd_qlf.h" #include "gtm_caseconv.h" #include "min_max.h" GBLREF command_qualifier cmd_qlf; error_def(ERR_LABELONLY); int4* find_line_addr(rhdtyp *routine, mstr *label, int4 offset, mident **lent_name) { lab_tabent *base, *top, *ptr; rhdtyp *real_routine; mident_fixed target_label; mident lname; lnr_tabent *line_table, *first_line; int stat, n; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (!routine) return NULL; real_routine = CURRENT_RHEAD_ADR(routine); first_line = LNRTAB_ADR(real_routine); if (!label->len || !*label->addr) { /* No label specified. Return the first line */ base = LABTAB_ADR(real_routine); /* Get the null label entry and note whether it has a formallist. */ (TREF(lab_proxy)).has_parms = base->has_parms; assert(0 == base->lab_name.len); if (lent_name) *lent_name = &base->lab_name; line_table = first_line; } else { lname.len = (label->len <= MAX_MIDENT_LEN) ? label->len : MAX_MIDENT_LEN; if (cmd_qlf.qlf & CQ_LOWER_LABELS) lname.addr = label->addr; else { lower_to_upper((uchar_ptr_t)&target_label.c[0], (uchar_ptr_t)label->addr, lname.len); lname.addr = &target_label.c[0]; } ptr = base = LABTAB_ADR(real_routine); top = base + real_routine->labtab_len; for ( ; ; ) { n = (int)(top - base) / 2; ptr = base + n; MIDENT_CMP(&lname, &ptr->lab_name, stat); if (0 == stat) { /* Note whether the label has a formallist. */ (TREF(lab_proxy)).has_parms = ptr->has_parms; if (lent_name) *lent_name = &ptr->lab_name; line_table = LABENT_LNR_ENTRY(real_routine, ptr); break; } else if (0 < stat) base = ptr; else top = ptr; if (n < 1) return NULL; } } line_table += offset; if ((first_line > line_table) || (first_line + real_routine->lnrtab_len <= line_table)) return NULL; return line_table; } fis-gtm-V6.0-003/sr_port/find_line_start.c0000644000032200000250000000405212201176176017346 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include GBLREF unsigned char *stackbase, *stacktop; unsigned char *find_line_start(unsigned char *in_addr, rhdtyp *routine) { unsigned char *result; lab_tabent *max_label, *label_table, *last_label; lnr_tabent *line_table, *last_line; int4 in_addr_offset; result = (unsigned char *)0; if (!ADDR_IN_CODE(in_addr, routine)) return result; routine = CURRENT_RHEAD_ADR(routine); USHBIN_ONLY( assert(routine->labtab_adr); assert(routine->lnrtab_adr); ); NON_USHBIN_ONLY( assert(routine->labtab_ptr >= 0); assert(routine->lnrtab_ptr >= 0); ); assert(routine->labtab_len >= 0); assert(routine->lnrtab_len >= 0); label_table = LABTAB_ADR(routine); last_label = label_table + routine->labtab_len; max_label = label_table++; while (label_table < last_label) { /* Find first label that goes past the input addr. The previous label is then the target line */ if (in_addr > LABEL_ADDR(routine, label_table)) { if (max_label->LABENT_LNR_OFFSET <= label_table->LABENT_LNR_OFFSET) max_label = label_table; } label_table++; } line_table = LABENT_LNR_ENTRY(routine, max_label); /* Used as offset !! */ in_addr_offset = (int4)(in_addr - CODE_BASE_ADDR(routine)); last_line = LNRTAB_ADR(routine); last_line += routine->lnrtab_len; for( ; ++line_table < last_line ;) { /* Find first line that is > input addr. The previous line is the target line */ if (in_addr_offset <= *line_table) { result = LINE_NUMBER_ADDR(routine, (line_table - 1)); break; } } if (line_table >= last_line) result = LINE_NUMBER_ADDR(routine, (line_table - 1)); return result; } fis-gtm-V6.0-003/sr_port/find_mvstent.c0000644000032200000250000001122012201176176016675 0ustar librarygtc/**************************************************************** * * * Copyright 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gt_timer.h" #include "io.h" #include "iotimer.h" #include "iotcpdef.h" #include "iosocketdef.h" #include #include "mv_stent.h" #include "find_mvstent.h" #include "stack_frame.h" GBLREF mv_stent *mv_chain; GBLREF stack_frame *frame_pointer; GBLREF unsigned char *stackbase, *stacktop, *msp, *stackwarn; /* Find and optionally clear the mv_stent keeping interrupted device information for us */ mv_stent *io_find_mvstent(io_desc *io_ptr, boolean_t clear_mvstent) { mv_stent *mvc, *mv_zintdev; assert(msp <= stackbase && msp > stacktop); assert(mv_chain <= (mv_stent *)stackbase && mv_chain > (mv_stent *)stacktop); assert(frame_pointer <= (stack_frame *)stackbase && frame_pointer > (stack_frame *)stacktop); mv_zintdev = NULL; for (mvc = mv_chain; mvc < (mv_stent *)frame_pointer ; mvc = (mv_stent *)(mvc->mv_st_next + (char *)mvc)) { if (MVST_ZINTDEV == mvc->mv_st_type && io_ptr == mvc->mv_st_cont.mvs_zintdev.io_ptr) { mv_zintdev = mvc; break; } if (!mvc->mv_st_next) GTMASSERT; } if (mv_zintdev && clear_mvstent) { if (mv_chain == mv_zintdev) POP_MV_STENT(); /* just pop if top of stack */ else { mv_zintdev->mv_st_cont.mvs_zintdev.io_ptr = NULL; mv_zintdev->mv_st_cont.mvs_zintdev.buffer_valid = FALSE; } } return mv_zintdev; } /* Find and optionally clear the mv_stent keeping information for interrupted * timed non IO commands. Unlike IO commands there is no associated structure * so the restart_pc is used to identify which instance of the command is of * interest */ mv_stent *find_mvstent_cmd(zintcmd_ops match_command, unsigned char *match_restart_pc, unsigned char *match_restart_ctxt, boolean_t clear_mvstent) { mv_stent *mvc, *mv_zintcmd; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(msp <= stackbase && msp > stacktop); assert(mv_chain <= (mv_stent *)stackbase && mv_chain > (mv_stent *)stacktop); assert(frame_pointer <= (stack_frame *)stackbase && frame_pointer > (stack_frame *)stacktop); assert((0 < match_command) && (ZINTCMD_LAST > match_command)); mv_zintcmd = NULL; if ((0 >= TAREF1(zintcmd_active, match_command).count) /* at least one mv_stent for this command */ || (match_restart_pc != TAREF1(zintcmd_active, match_command).restart_pc_last) || (match_restart_ctxt != TAREF1(zintcmd_active, match_command).restart_ctxt_last)) return mv_zintcmd; /* not ours so no need to search stack */ for (mvc = mv_chain; mvc < (mv_stent *)frame_pointer ; mvc = (mv_stent *)(mvc->mv_st_next + (char *)mvc)) { if (MVST_ZINTCMD == mvc->mv_st_type && match_command == mvc->mv_st_cont.mvs_zintcmd.command && match_restart_pc == mvc->mv_st_cont.mvs_zintcmd.restart_pc_check && match_restart_ctxt == mvc->mv_st_cont.mvs_zintcmd.restart_ctxt_check) { mv_zintcmd = mvc; break; } if (!mvc->mv_st_next) GTMASSERT; } if (mv_zintcmd && clear_mvstent) { /* restore previous zintcmd_active values before clearing MV_STENT entry */ TAREF1(zintcmd_active, match_command).restart_pc_last = mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_pc_prior; TAREF1(zintcmd_active, match_command).restart_ctxt_last = mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_ctxt_prior; TAREF1(zintcmd_active, match_command).count--; assert(0 <= TAREF1(zintcmd_active, match_command).count); if (mv_chain == mvc) POP_MV_STENT(); /* just pop if top of stack */ else { mv_zintcmd->mv_st_cont.mvs_zintcmd.command = ZINTCMD_NOOP; mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_pc_check = NULL; } } return mv_zintcmd; } fis-gtm-V6.0-003/sr_port/find_mvstent.h0000644000032200000250000000227312201176156016710 0ustar librarygtc/**************************************************************** * * * Copyright 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef FIND_MVSTENT_H #define FIND_MVSTENT_H mv_stent *find_mvstent_cmd(zintcmd_ops match_command, unsigned char *match_restart_pc, unsigned char *match_restart_ctxt, boolean_t clear_mvstent); /* Keep track of active interrupted commands in global to avoid unneeded searches of stack */ typedef struct { int count; /* number of active MVST_ZINTCMD entries for this command */ unsigned char *restart_pc_last; /* most recent on MVST stack */ unsigned char *restart_ctxt_last; } zintcmd_active_info; #endif fis-gtm-V6.0-003/sr_port/find_rtn_hdr.c0000644000032200000250000000275512201176176016652 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2004 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include #include "ident.h" #include "min_max.h" #define S_CUTOFF 7 GBLREF rtn_tabent *rtn_names, *rtn_names_end; rhdtyp *find_rtn_hdr(mstr *name) { rtn_tabent *bot, *top, *mid; int4 comp; mident rtn_name; mident_fixed rtn_name_buff; assert (name->len <= MAX_MIDENT_LEN); rtn_name.len = name->len; #ifdef VMS rtn_name.addr = &rtn_name_buff.c[0]; CONVERT_IDENT(rtn_name.addr, name->addr, name->len); #else rtn_name.addr = name->addr; #endif bot = rtn_names; top = rtn_names_end; for (;;) { if (top < bot) return 0; else if ((top - bot) < S_CUTOFF) { comp = -1; for (mid = bot; comp < 0 && mid <= top; mid++) { MIDENT_CMP(&mid->rt_name, &rtn_name, comp); if (0 == comp) return mid->rt_adr; } return 0; } else { mid = bot + (top - bot) / 2; MIDENT_CMP(&mid->rt_name, &rtn_name, comp); if (0 == comp) return mid->rt_adr; else if (comp < 0) { bot = mid + 1; continue; } else { top = mid - 1; continue; } } } } fis-gtm-V6.0-003/sr_port/five_2_ascii.c0000644000032200000250000000130112201176156016514 0ustar librarygtc/**************************************************************** * * * Copyright 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "five_2_ascii.h" unsigned char *five_2_ascii(unsigned short *inval, unsigned char *cp) { int4 val; val = *inval; *cp++ = (val >> 11) + '@'; *cp++ = ((val >> 6) & 0x1f) + '@'; *cp++ = ((val >> 1) & 0x1f) + '@'; return cp; } fis-gtm-V6.0-003/sr_port/five_2_ascii.h0000644000032200000250000000115412201176156016527 0ustar librarygtc/**************************************************************** * * * Copyright 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef FIVE_2_ASCII_H_INCLUDED #define FIVE_2_ASCII_H_INCLUDED unsigned char *five_2_ascii(unsigned short *inval, unsigned char *cp); #endif /* FIVE_2_ASCII_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/five_bit.c0000644000032200000250000000166712201176156016000 0ustar librarygtc/**************************************************************** * * * Copyright 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "five_bit.h" /* five_bit - convert 3-character string into 5-bit character representation */ unsigned short five_bit(unsigned char *src) /* src is pointer to 3-character string to be converted to 5-bit format */ { int index; unsigned short result; /* Or low-order 5 bits of each character together into high-order 15 bits of result. */ for (index = 0, result = 0; index < 3; index++, src++) result = (result << 5) | (*src & 0x1f); result <<= 1; return result; } fis-gtm-V6.0-003/sr_port/five_bit.h0000644000032200000250000000110612201176156015771 0ustar librarygtc/**************************************************************** * * * Copyright 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef FIVE_BIT_H_INCLUDED #define FIVE_BIT_H_INCLUDED unsigned short five_bit(unsigned char *src); #endif /* FIVE_BIT_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/fix_pages.h0000644000032200000250000000112012201176156016143 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef FIX_PAGES_INCLUDED #define FIX_PAGES_INCLUDED void fix_pages(unsigned char * bot, unsigned char * top); #endif /* FIX_PAGES_INCLUDED */ fis-gtm-V6.0-003/sr_port/fix_xfer_entry.h0000644000032200000250000000236712201176156017247 0ustar librarygtc/**************************************************************** * * * Copyright 2007, 2008 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef FIX_XFER_ENTRY_INCLUDED #define FIX_XFER_ENTRY_INCLUDED GBLREF xfer_entry_t xfer_table[]; #ifdef __ia64 GBLREF char xfer_table_desc[]; #endif /* __ia64 */ #if defined(__ia64) || defined(__x86_64__) #include "xfer_desc.i" #endif #ifndef __ia64 #define FIX_XFER_ENTRY(indx, func) \ { \ xfer_table[indx] = (xfer_entry_t)&func; \ } #else /* __ia64 */ #define FIX_XFER_ENTRY(indx, func) \ { \ xfer_table[indx] = (xfer_entry_t)CODE_ADDRESS(func); \ xfer_table_desc[indx] = func##_FUNCTYPE; \ } #endif /* __ia64 */ #endif /* FIX_XFER_ENTRY_INCLUDED */ fis-gtm-V6.0-003/sr_port/fl.mpt0000644000032200000250000000102512201176156015154 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1992,2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %FL ;GT.M %FL utility - first lines lister ;invoke ^%FL to get interaction ; d FL^%RO q fis-gtm-V6.0-003/sr_port/flt_mod.c0000644000032200000250000000602112201176156015622 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* flt_mod.(u, v) = u - (v*floor.(u/v)) where x-1 < floor.x <= x ^ int.x */ #include "mdef.h" #include "arit.h" #include "op.h" #include "eb_muldiv.h" #include "promodemo.h" #include "flt_mod.h" LITREF mval literal_zero; LITREF int4 ten_pwr[]; void flt_mod (mval *u, mval *v, mval *q) { int exp; int4 z, x; mval w; /* temporary mval for division result */ mval y; /* temporary mval for extended precision promotion to prevent modifying caller's data */ mval *u_orig; /* original (caller's) value of u */ error_def(ERR_DIVZERO); u_orig = u; MV_FORCE_NUM(u); MV_FORCE_NUM(v); if ((v->mvtype & MV_INT) != 0 && v->m[1] == 0) rts_error(VARLSTCNT(1) ERR_DIVZERO); if ((u->mvtype & MV_INT & v->mvtype) != 0) { /* Both are INT's; use shortcut. */ q->mvtype = MV_NM | MV_INT; eb_int_mod(u->m[1], v->m[1], q->m); return; } else if ((u->mvtype & MV_INT) != 0) { /* u is INT; promote to extended precision for compatibility with v. */ y = *u; promote(&y); /* y will be normalized, but not in canonical form */ u = &y; /* this is why we need u_orig */ } else if ((v->mvtype & MV_INT) != 0) { /* v is INT; promote to extended precision for compatibility with u. */ y = *v; promote(&y); v = &y; } /* At this point, both u and v are in extended precision format. */ /* Set w = floor(u/v). */ op_div (u, v, &w); if ((w.mvtype & MV_INT) != 0) promote(&w); exp = w.e; if (exp <= MV_XBIAS) { /* Magnitude of w, floor(u/v), is < 1. */ if (u->sgn != v->sgn && w.m[1] != 0 && exp >= EXPLO) { /* Signs differ (=> floor(u/v) < 0) and (w != 0) and (no underflow) => floor(u/v) == -1 */ w.sgn = 1; w.e = MV_XBIAS + 1; w.m[1] = MANT_LO; w.m[0] = 0; } else { /* Signs same (=> floor(u/v) >= 0) or (w == 0) or (underflow) => floor(u/v) == 0 */ *q = *u_orig; /* u - floor(u/v)*v == u - 0*v == u */ return; } } else if (exp < EXP_IDX_BIAL) { z = ten_pwr[EXP_IDX_BIAL - exp]; x = (w.m[1]/z)*z; if (u->sgn != v->sgn && (w.m[1] != x || w.m[0] != 0)) { w.m[0] = 0; w.m[1] = x + z; if (w.m[1] >= MANT_HI) { w.m[0] = w.m[0]/10 + (w.m[1]%10)*MANT_LO; w.m[1] /= 10; w.e++; } } else { w.m[0] = 0; w.m[1] = x; } } else if (exp < EXP_IDX_BIAQ) { z = ten_pwr[EXP_IDX_BIAQ - exp]; x = (w.m[0]/z)*z; if (u->sgn != v->sgn && w.m[0] != x) { w.m[0] = x + z; if (w.m[0] >= MANT_HI) { w.m[0] -= MANT_HI; w.m[1]++; } } else { w.m[0] = x; } } op_mul (&w, v, &w); /* w = w*v = floor(u/v)*v */ op_sub (u_orig, &w, q); /* q = u - w = u - floor(u/v)*v */ } fis-gtm-V6.0-003/sr_port/flt_mod.h0000644000032200000250000000103512201176156015627 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __FLT_MOD_H__ #define __FLT_MOD_H__ void flt_mod (mval *u, mval *v, mval *q); #endif fis-gtm-V6.0-003/sr_port/flush_jmp.c0000644000032200000250000002042412201176176016172 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #include #include "mv_stent.h" #include "objlabel.h" #include "cache.h" #include "stack_frame.h" #include "cache_cleanup.h" #include "op.h" #include "unwind_nocounts.h" #include "flush_jmp.h" #include "error.h" #include "tp_frame.h" #ifdef GTM_TRIGGER # include "gtm_trigger_trc.h" #endif GBLREF symval *curr_symval; GBLREF stack_frame *error_frame; GBLREF stack_frame *frame_pointer; GBLREF mv_stent *mv_chain; GBLREF unsigned char *stackbase,*stacktop,*msp,*stackwarn; GBLREF tp_frame *tp_pointer; LITREF boolean_t mvs_save[]; STATICFNDCL void fix_tphold_mvc(char *target, char *srcstart, char *srcend); error_def(ERR_STACKCRIT); error_def(ERR_STACKOFLOW); void flush_jmp (rhdtyp *rtn_base, unsigned char *context, unsigned char *transfer_addr) { mv_stent *mv_st_ent, *mv_st_prev; char *top; unsigned char *msp_save; int4 shift, size, mv_st_type; unwind_nocounts(); /* We are going to mutate the current frame from the program it was running to the program we want it to run. * If the current frame is marked for indr cache cleanup, do that cleanup now and unmark the frame. */ IF_INDR_FRAME_CLEANUP_CACHE_ENTRY_AND_UNMARK(frame_pointer); DBGEHND((stderr, "flush_jmp: Retargetting stack frame 0x"lvaddr" for transfer address 0x"lvaddr"\n", frame_pointer, transfer_addr)); /* Also unmark the SFF_ETRAP_ERR bit in case it is set. This way we ensure control gets transferred to * the mpc below instead of "error_return" (which is what getframe will do in case the bit is set). * It is ok to clear this bit because the global variable "error_frame" will still be set to point to * this frame so whenever we unwind out of this, we will rethrow the error at the parent frame. */ assert(!(frame_pointer->flags & SFF_ETRAP_ERR) || (NULL == error_frame) || (error_frame == frame_pointer)); assert(!(SFT_TRIGR & frame_pointer->type)); frame_pointer->flags &= SFF_ETRAP_ERR_OFF; /* clear SFF_ETRAP_ERR bit */ frame_pointer->flags &= SFF_IMPLTSTART_CALLD_OFF; /* clear SFF_IMPLTSTART_CALLD bit since this frame is being rewritten */ GTMTRIG_ONLY(DBGTRIGR((stderr, "flush_jmp: Turrning off SFF_IMPLTSTART_CALLD_OFF in frame 0x"lvaddr"\n", frame_pointer))); frame_pointer->rvector = rtn_base; frame_pointer->vartab_ptr = (char *)VARTAB_ADR(rtn_base); frame_pointer->vartab_len = frame_pointer->rvector->vartab_len; frame_pointer->mpc = transfer_addr; frame_pointer->ctxt = context; #ifdef HAS_LITERAL_SECT frame_pointer->literal_ptr = (int4 *)LITERAL_ADR(rtn_base); #endif frame_pointer->temp_mvals = frame_pointer->rvector->temp_mvals; size = rtn_base->temp_size; frame_pointer->temps_ptr = (unsigned char *)frame_pointer - size; size += rtn_base->vartab_len * SIZEOF(ht_ent_mname *); frame_pointer->l_symtab = (ht_ent_mname **)((char *)frame_pointer - size); assert(frame_pointer->type & SFT_COUNT); assert((unsigned char *)mv_chain > stacktop && (unsigned char *)mv_chain <= stackbase); while (((char *)mv_chain < (char *)frame_pointer) && !mvs_save[mv_chain->mv_st_type]) { assert(MVST_TRIGR != mv_chain->mv_st_type); /* Should never unwind a trigger frame here */ msp = (unsigned char *)mv_chain; op_oldvar(); } if ((char *)mv_chain > (char *)frame_pointer) { msp_save = msp; msp = (unsigned char *)frame_pointer->l_symtab; if (msp <= stackwarn) { if (msp <= stacktop) { msp = msp_save; rts_error(VARLSTCNT(1) ERR_STACKOFLOW); } else rts_error(VARLSTCNT(1) ERR_STACKCRIT); } memset(msp, 0, size); DBGEHND((stderr, "flush_jmp: Old msp: 0x"lvaddr" New msp: 0x"lvaddr"\n", msp_save, msp)); return; } /* We kept one or more mv_stents for this frame. We may need to shift the stack to get room to create an l_symtab * for this re-purposed frame. In the above loop, we stopped searching the mv_stent chain at the first mv_stent we * knew we had to keep. Since we are moving things around anyway, see if there are any mv_stents associated * with this frame which don't need to be kept and can reclaim. */ mv_st_ent = mv_chain; mv_st_prev = (mv_stent *)((char *)mv_st_ent + mv_st_ent->mv_st_next); top = (char *)mv_st_ent + mvs_size[mv_st_ent->mv_st_type]; while ((char *)mv_st_prev < (char *)frame_pointer) { mv_st_type = mv_st_prev->mv_st_type; assert(MVST_TRIGR != mv_st_type); /* Should never unwind a trigger frame here */ if (!mvs_save[mv_st_type]) { /* Don't need to keep this mv_stent. Remove it from the chain */ DBGEHND((stderr, "flush_jmp: Removing no-save mv_stent addr 0x"lvaddr" and type %d\n", mv_st_prev, mv_st_type)); unw_mv_ent(mv_st_prev); mv_st_ent->mv_st_next += mv_st_prev->mv_st_next; mv_st_prev = (mv_stent *)((char *)mv_st_prev + mv_st_prev->mv_st_next); continue; } /* We found a previous mv_stent we need to keep. If we had an interveening mv_stent we don't need to * keep, migrate the new keeper mv_stent adjacent to the previous keeper. */ if (mv_st_prev != (mv_stent *)top) { DBGEHND((stderr, "flush_jmp: Migrating keeper mv_stent from 0x"lvaddr" to 0x"lvaddr" type %d\n", mv_st_prev, top, mv_st_type)); if (MVST_TPHOLD == mv_st_type) { /* If we are moving an MVST_TPHOLD mv_stent, find it in the tpstack and fix its * address there too. Else we won't unwind to the correct place on a restart. */ fix_tphold_mvc(top, (char *)mv_st_prev, ((char *)mv_st_prev + mvs_size[MVST_TPHOLD])); } memmove(top, mv_st_prev, mvs_size[mv_st_type]); } DBGEHND((stderr, "flush_jmp: Updating offsets for mv_stent at addr 0x"lvaddr" type %d\n", mv_st_ent, mv_st_ent->mv_st_type)); mv_st_ent->mv_st_next = mvs_size[mv_st_ent->mv_st_type]; mv_st_ent = (mv_stent *)top; mv_st_ent->mv_st_next += (unsigned int)((char *)mv_st_prev - top); top += mvs_size[mv_st_ent->mv_st_type]; mv_st_prev = (mv_stent *)((char *)mv_st_ent + mv_st_ent->mv_st_next); } shift = (int4)((char *)frame_pointer - top - size); DBGEHND_ONLY(msp_save = msp); if (shift) { if ((unsigned char *)mv_chain + shift <= stackwarn) { if ((unsigned char *)mv_chain + shift <= stacktop) rts_error(VARLSTCNT(1) ERR_STACKOFLOW); else rts_error(VARLSTCNT(1) ERR_STACKCRIT); } DBGEHND((stderr, "flush_jmp: Shifting %d bytes of stack from 0x"lvaddr" to 0x"lvaddr" by %d bytes\n", INTCAST(top - (char *)mv_chain), mv_chain, (mv_chain + shift), shift)); /* Since we are moving one or more mv_stents, it is no more difficult to check the range against the * tp_frame chain than it is to loop through the mv_stents checking each one since the tp_frame stack * is usually no more than 1-3 deep. */ fix_tphold_mvc(((char *)mv_chain + shift), (char *)mv_chain, ((char *)mv_chain + (top - (char *)mv_chain))); memmove((char *)mv_chain + shift, mv_chain, top - (char *)mv_chain); mv_chain = (mv_stent *)((char *)mv_chain + shift); mv_st_ent = (mv_stent *)((char *)mv_st_ent + shift); mv_st_ent->mv_st_next -= shift; msp = (unsigned char *)mv_chain; } memset(frame_pointer->l_symtab, 0, size); DBGEHND((stderr, "flush_jmp: Old msp: 0x"lvaddr" New msp: 0x"lvaddr"\n", msp_save, msp)); return; } /* Routine to fix up the TPHOLD mv_stent address in the tp_stack when flush_jmp shifts the stack */ STATICFNDEF void fix_tphold_mvc(char *target, char *srcstart, char *srcend) { tp_frame *tf; DBGEHND((stderr, "fix_tphold_mvc: entered with target: 0x"lvaddr" srcstart: 0x"lvaddr" srcend: 0x"lvaddr"\n", target, srcstart, srcend)); for (tf = tp_pointer; ((NULL != tf) && ((char *)tf->fp > srcstart)); tf = tf->old_tp_frame) { if (((char *)tf->mvc >= srcstart) && ((char *)tf->mvc < srcend)) { DBGEHND((stderr, "fix_tphold_mvc: Modifying tp_frame mv_stent value from 0x"lvaddr" to 0x"lvaddr " level %d\n", tf->mvc, ((char *)tf->mvc + (target - srcstart)), tf->mvc->mv_st_cont.mvs_tp_holder.tphold_tlevel)); tf->mvc = (mv_stent *)((char *)tf->mvc + (target - srcstart)); } } } fis-gtm-V6.0-003/sr_port/flush_jmp.h0000644000032200000250000000112012201176156016165 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __FLUSH_JMP_H__ #define __FLUSH_JMP_H__ void flush_jmp (rhdtyp *rtn_base, unsigned char *context, unsigned char *transfer_addr); #endif fis-gtm-V6.0-003/sr_port/flush_pio.c0000644000032200000250000000206512201176156016172 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "io_params.h" GBLREF io_pair io_std_device; GBLREF bool prin_out_dev_failure; void flush_pio(void) { /* there is no eol character in the flush prototype */ /*unsigned char p;*/ if (io_std_device.out && !prin_out_dev_failure) /* Some utility pgms don't have devices to flush */ { /* do not flush if we've encountered an error with io_std_device already so that we give user $ZT, or EXCEPTION * a chance to execute */ /*p = (unsigned char)iop_eol; (io_std_device.out->disp_ptr->flush)(io_std_device.out, &p);*/ (io_std_device.out->disp_ptr->flush)(io_std_device.out); } } fis-gtm-V6.0-003/sr_port/fnname.h0000644000032200000250000000105312201176156015447 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #define FNLCL 0 #define FNGBL 1 #define FNEXTGBL1 2 #define FNEXTGBL2 4 #define FNVBAR 8 #define FNNAKGBL 32 fis-gtm-V6.0-003/sr_port/fnorder.h0000644000032200000250000000142012201176156015640 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef _FNORDER_H_INC_ #define _FNORDER_H_INC_ enum order_obj { GLOBAL = 0, LOCAL, LOCAL_NAME, INDIRECT, LAST_OBJECT }; enum order_dir { FORWARD = 0, BACKWARD, TBD, LAST_DIRECTION }; STATICFNDCL boolean_t set_opcode(triple *r, oprtype *result, oprtype *result_ptr, oprtype *second_opr, enum order_obj object); #endif fis-gtm-V6.0-003/sr_port/fnpc.h0000644000032200000250000000335612201176156015141 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef FNPC_INCLUDED #define FNPC_INCLUDED /* Note, FNPC_MAX should never exceed 254 since the value 255 is used to flag "invalid entry" */ #define FNPC_STRLEN_MIN 15 #define FNPC_MAX 50 #define FNPC_ELEM_MAX 80 /* The delimiter argument to op_fnp1, opfnzp1, op_setp1, and op_setzp1 is passed as an integer but contains 1-4 chars (zero filled). The unicode versions are interested in all of them but the non-unicode versions are only interested in the first char. */ typedef union { int unichar_val; unsigned char unibytes_val[4]; } delimfmt; typedef struct fnpc_struct { mstr last_str; /* The last string (addr/len) we used in cache */ unsigned int *pcoffmax; /* Address of last element in pstart array */ int delim; /* delimiter used in $[z]piece */ int npcs; /* Number of pieces for which values are filled in */ int indx; /* The index of this piece */ boolean_t byte_oriented; /* True if byte oriented; False if (unicode) char oriented */ unsigned int pstart[FNPC_ELEM_MAX + 1]; /* Where each piece starts (last elem holds end of last piece) */ } fnpc; typedef struct { fnpc *fnpcsteal; /* Last stolen cache element */ fnpc *fnpcmax; /* (use addrs to avoid array indexing) */ fnpc fnpcs[FNPC_MAX]; } fnpc_area; #ifdef DEBUG void fnpc_stats(void); #endif #endif fis-gtm-V6.0-003/sr_port/fnpc_stats.c0000644000032200000250000000616312201176156016351 0ustar librarygtc/**************************************************************** * * * Copyright 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "fnpc.h" #include "gtm_stdio.h" #ifdef DEBUG GBLREF uint4 process_id; GBLREF int c_miss; /* cache misses (debug) */ GBLREF int c_hit; /* cache hits (debug) */ GBLREF int c_small; /* scanned small string brute force */ GBLREF int c_small_pcs; /* chars scanned by small scan */ GBLREF int c_pskip; /* number of pieces "skipped" */ GBLREF int c_pscan; /* number of pieces "scanned" */ GBLREF int c_parscan; /* number of partial scans (partial cache hits) */ GBLREF int cs_miss; /* cache misses (debug) */ GBLREF int cs_hit; /* cache hits (debug) */ GBLREF int cs_small; /* scanned small string brute force */ GBLREF int cs_small_pcs; /* chars scanned by small scan */ GBLREF int cs_pskip; /* number of pieces "skipped" */ GBLREF int cs_pscan; /* number of pieces "scanned" */ GBLREF int cs_parscan; /* number of partial scans (partial cache hits) */ GBLREF int c_clear; /* cleared due to (possible) value change */ void fnpc_stats(void) { FPRINTF(stderr, "process id: %d\n", process_id); FPRINTF(stderr, "fnpc cache clears: %d\n", c_clear); FPRINTF(stderr, "Reference Piece:\n"); FPRINTF(stderr, " fnpc cache miss: %d\n", c_miss); FPRINTF(stderr, " fnpc cache hit: %d\n", c_hit); FPRINTF(stderr, " fnpc pieces skipped: %d\n", c_pskip); FPRINTF(stderr, " fnpc pieces scanned: %d\n", c_pscan); FPRINTF(stderr, " fnpc partial scans: %d\n", c_parscan); FPRINTF(stderr, " small string scans: %d\n", c_small); FPRINTF(stderr, " small str pcs scnd: %d\n", c_small_pcs); FPRINTF(stderr, "Set Piece:\n"); FPRINTF(stderr, " fnpc cache miss: %d\n", cs_miss); FPRINTF(stderr, " fnpc cache hit: %d\n", cs_hit); FPRINTF(stderr, " fnpc pieces skipped: %d\n", cs_pskip); FPRINTF(stderr, " fnpc pieces scanned: %d\n", cs_pscan); FPRINTF(stderr, " fnpc partial scans: %d\n", cs_parscan); FPRINTF(stderr, " small string scans: %d\n", cs_small); FPRINTF(stderr, " small str pcs scnd: %d\n", cs_small_pcs); } #endif fis-gtm-V6.0-003/sr_port/fntext_ch.c0000644000032200000250000000233212201176156016161 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "error.h" error_def(ERR_ASSERT); error_def(ERR_GTMASSERT); error_def(ERR_GTMASSERT2); error_def(ERR_GTMCHECK); error_def(ERR_MEMORY); error_def(ERR_OUTOFSPACE); error_def(ERR_STACKOFLOW); error_def(ERR_TPRETRY); error_def(ERR_VMSMEMORY); CONDITION_HANDLER(fntext_ch) { START_CH; GTMTRIG_ONLY(TREF(in_op_fntext) = FALSE); if (!DUMPABLE && (SIGNAL != ERR_TPRETRY)) { UNWIND(NULL, NULL); /* As per the standard, $TEXT returns null string if there are errors while */ /* loading/linking with the entryref. So, we ignore non-fatal errors. */ } else { NEXTCH; /* But, we don't want to ignore fatal errors as these may be indicative of serious */ /* issues that may need investigation. Also, TP restarts need to be handled properly. */ } } fis-gtm-V6.0-003/sr_port/follow.h0000644000032200000250000000101512201176156015503 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __FOLLOW_H__ #define __FOLLOW_H__ int follow(mval *, mval *); #endif fis-gtm-V6.0-003/sr_port/format2zwr.c0000644000032200000250000001214112201176156016313 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "mlkdef.h" #include "zshow.h" #include "patcode.h" #include "compiler.h" /* for CHARMAXARGS */ #ifdef UNICODE_SUPPORTED #include "gtm_icu_api.h" /* U_ISPRINT() needs this header */ #include "gtm_utf8.h" #endif GBLREF uint4 *pattern_typemask; GBLREF boolean_t gtm_utf8_mode; /* Routine to convert a string to ZWRITE format. Used by the utiltities. * NOTE: this routine does almost the same formatting as mval_write(). The reason * for not using mval_write() is because it is much more complex than we need * here. Moreover, this version is more efficient due to the availability of * pre-allocated destination buffer */ int format2zwr(sm_uc_ptr_t src, int src_len, unsigned char *des, int *des_len) { sm_uc_ptr_t cp; uint4 ch; int fastate = 0, ncommas, dstlen, chlen; boolean_t isctl, isill; uchar_ptr_t srctop, strnext, tmpptr; dstlen = *des_len = 0; if (src_len > 0) { srctop = src + src_len; fastate = 0; /* deals with the other characters */ for (cp = src; cp < srctop; cp += chlen) { if (!gtm_utf8_mode) { ch = *cp; isctl = ((pattern_typemask[ch] & PATM_C) != 0); isill = FALSE; chlen = 1; } #ifdef UNICODE_SUPPORTED else { strnext = UTF8_MBTOWC(cp, srctop, ch); isill = (WEOF == ch) ? (ch = *cp, TRUE) : FALSE; if (!isill) isctl = !U_ISPRINT(ch); chlen = (int)(strnext - cp); } #endif switch(fastate) { case 0: /* beginning of the string */ case 1: /* beginning of a new substring followed by a graphic character */ if (isill) { if (dstlen > 0) { des[dstlen++] = '"'; des[dstlen++] = '_'; } MEMCPY_LIT(des + dstlen, DOLLARZCH); dstlen += STR_LIT_LEN(DOLLARZCH); I2A(des, dstlen, ch); fastate = 3; ncommas = 0; } else if (isctl) { if (dstlen > 0) { /* close previous string with quote and prepare for concatenation */ des[dstlen++] = '"'; des[dstlen++] = '_'; } MEMCPY_LIT(des + dstlen, DOLLARCH); dstlen += STR_LIT_LEN(DOLLARCH); I2A(des, dstlen, ch); fastate = 2; ncommas = 0; } else { /* graphic characters */ if (0 == fastate) /* the initial quote in the beginning */ { des[dstlen++] = '"'; fastate = 1; } if ('"' == ch) des[dstlen++] = '"'; if (!gtm_utf8_mode) des[dstlen++] = ch; else { memcpy(&des[dstlen], cp, chlen); dstlen += chlen; } } break; case 2: /* subsequent characters following a non-graphic character in the form of $CHAR(x,) */ if (isill) { MEMCPY_LIT(des + dstlen, CLOSE_PAREN_DOLLARZCH); dstlen += STR_LIT_LEN(CLOSE_PAREN_DOLLARZCH); I2A(des, dstlen, ch); fastate = 3; } else if(isctl) { ncommas++; if (CHARMAXARGS == ncommas) { ncommas = 0; MEMCPY_LIT(des + dstlen, CLOSE_PAREN_DOLLARCH); dstlen += STR_LIT_LEN(CLOSE_PAREN_DOLLARCH); } else { MEMCPY_LIT(des + dstlen, COMMA); dstlen += STR_LIT_LEN(COMMA); } I2A(des, dstlen, ch); } else { MEMCPY_LIT(des + dstlen, CLOSE_PAREN_QUOTE); dstlen += STR_LIT_LEN(CLOSE_PAREN_QUOTE); if (!gtm_utf8_mode) des[dstlen++] = ch; else { memcpy(&des[dstlen], cp, chlen); dstlen += chlen; } if ('"' == ch) des[dstlen++] = '"'; fastate = 1; } break; case 3: /* subsequent characters following an illegal character in the form of $ZCHAR(x,) */ if(isill) { ncommas++; if (CHARMAXARGS == ncommas) { ncommas = 0; MEMCPY_LIT(des + dstlen, CLOSE_PAREN_DOLLARZCH); dstlen += STR_LIT_LEN(CLOSE_PAREN_DOLLARZCH); } else { MEMCPY_LIT(des + dstlen, COMMA); ++dstlen; } I2A(des, dstlen, ch); } else if (isctl) { MEMCPY_LIT(des + dstlen, CLOSE_PAREN_DOLLARCH); dstlen += STR_LIT_LEN(CLOSE_PAREN_DOLLARCH); I2A(des, dstlen, ch); fastate = 2; } else { MEMCPY_LIT(des + dstlen, CLOSE_PAREN_QUOTE); dstlen += STR_LIT_LEN(CLOSE_PAREN_QUOTE); if (!gtm_utf8_mode) des[dstlen++] = ch; else { memcpy(&des[dstlen], cp, chlen); dstlen += chlen; } if ('"' == ch) des[dstlen++] = '"'; fastate = 1; } break; default: assert(FALSE); break; } } /* close up */ switch(fastate) { case 1: des[dstlen++] = '"'; break; case 2: case 3: des[dstlen++] = ')'; break; default: assert(FALSE); break; } } else { des[0] = des[1] = '"'; dstlen = 2; } *des_len = dstlen; return 0; } fis-gtm-V6.0-003/sr_port/format_key_lv_val.c0000644000032200000250000000506512201176156017710 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* *-------------------------------------------------------------------------- * Descriptipn: * Given a non-null lv_val *, this will format the subscripted local variable key * starting from the base variable lv_val *. * Input: * lvpin: Pointer to the last subscript's lv_val * buff : Buffer where key will be formatted * size : Size of buff * Return Value: * End address upto which buffer was used to format the key * (Needed for length calculation in caller) *-------------------------------------------------------------------------- */ #include "mdef.h" #include "lv_val.h" #include "gtm_string.h" #include "mvalconv.h" #include "promodemo.h" /* for "demote" prototype used in LV_NODE_GET_KEY */ unsigned char *format_key_lv_val(lv_val *lvpin, unsigned char *buff, int size) { boolean_t is_base_var; int cnt, cntfmt; lv_val *lv, *base_lv; mval tempmv; lvTree *lvt; lvTreeNode *node, *nodep[MAX_LVSUBSCRIPTS]; unsigned char *endbuff; if (NULL == lvpin) return buff; lv = lvpin; is_base_var = LV_IS_BASE_VAR(lv); base_lv = !is_base_var ? LV_GET_BASE_VAR(lv) : lv; cntfmt = 0; while (lv != base_lv) { assert(!LV_IS_BASE_VAR(lv)); nodep[cntfmt++] = (lvTreeNode *)lv; lvt = LV_GET_PARENT_TREE(lv); assert(NULL != lvt); assert(lvt->base_lv == base_lv); lv = (lv_val *)LVT_PARENT(lvt); assert(NULL != lv); } endbuff = format_lvname(base_lv, buff, size); size -= (int)(endbuff - buff); buff = endbuff; if (cntfmt) { if (size < 1) return buff; *buff++ = '('; size--; } for (cnt = cntfmt - 1; cnt >= 0; cnt--) { node = nodep[cnt]; LV_NODE_GET_KEY(node, &tempmv); /* Get node key into "tempmv" depending on the structure type of "node" */ MV_FORCE_STRD(&tempmv); if (size < tempmv.str.len) { /* copy as much space as we have */ memcpy(buff, tempmv.str.addr, size); buff += size; return buff; } memcpy(buff, tempmv.str.addr, tempmv.str.len); size -= tempmv.str.len; buff += tempmv.str.len; if (cnt) { if (size < 1) return buff; *buff++ = ','; size--; } } if (cntfmt) { if (size < 1) return buff; *buff++ = ')'; size--; } return buff; } fis-gtm-V6.0-003/sr_port/format_key_mvals.c0000644000032200000250000000404012201176156017537 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* *-------------------------------------------------------------------------- * Descriptipn: * Given the lvname_info *, which contains all the mvals of all * subscripts and the name itself, of a local variable node, * this will format the entire local variable key * Input: * lvnp: Pointer to the structure of a local variable * buff: Buffer where key will be formatted * size: Size of buff * Return Value: * End address upto which buffer was used to format the key * (Needed for the length calculation in caller) *-------------------------------------------------------------------------- */ #include "mdef.h" #include "gtm_string.h" #include "lv_val.h" /* needed by "lv_nameinfo.h" */ unsigned char *format_key_mvals(unsigned char *buff, int size, lvname_info *lvnp) { int cnt; mval *keys; int n, subcnt; unsigned char *endbuff; cnt = (int)lvnp->total_lv_subs - 1; endbuff = format_lvname(lvnp->start_lvp, buff, size); size -= (int)(endbuff - buff); buff = endbuff; if (cnt > 0 && size > 0) { *buff++ = '('; size--; subcnt = 0; for (n = 0; ; ) { keys = lvnp->lv_subs[subcnt++]; MV_FORCE_STR(keys); if (size > (keys)->str.len) { memcpy(buff, (keys)->str.addr, (keys)->str.len); buff += (keys)->str.len; size -= (keys)->str.len; } else { /* copy as much space as we have */ memcpy(buff, (keys)->str.addr, size); buff += size; break; } if (++n < cnt && size > 0) { *buff++ = ','; size--; } else { if (size > 0) { *buff++ = ')'; size--; } break; } } } return buff; } fis-gtm-V6.0-003/sr_port/format_lvname.c0000644000032200000250000000351612201176176017040 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* *--------------------------------------------------------------------------------- * Description: * Given lv_val * of the local variable name, format the local variable name string * * Input Parameter: * start: Pointer to the local variable name * buff: Buffer where key will be formatted * size: Size of buff * * Return Value: * End address upto which buffer was used to format the key * (Needed for the length calculation in caller) *--------------------------------------------------------------------------------- */ #include "mdef.h" #include "gtm_string.h" #include #include "stack_frame.h" #include "lv_val.h" #include "min_max.h" GBLREF stack_frame *frame_pointer; unsigned char *format_lvname(lv_val *startlv, unsigned char *buff, int size) { int i, len; ht_ent_mname **j; mident *vent; if (!startlv) return buff; if ((startlv >= (lv_val *)frame_pointer->temps_ptr) && (startlv <= (lv_val *)(frame_pointer->temps_ptr + frame_pointer->rvector->temp_size))) return buff; for (i = 0, j = frame_pointer->l_symtab; i < frame_pointer->vartab_len; i++, j++) { if (*j && (lv_val *)((*j)->value) == startlv) break; } if (i >= frame_pointer->vartab_len) return buff; vent = &(((var_tabent *)frame_pointer->vartab_ptr)[i].var_name); assert(vent->len <= MAX_MIDENT_LEN); len = MIN(size, vent->len); memcpy(buff, vent->addr, len); return buff + len; } fis-gtm-V6.0-003/sr_port/format_targ_key.c0000644000032200000250000000647412201176156017367 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "format_targ_key.h" #include "gvsub2str.h" /* return a pointer that points after the last char added */ unsigned char *format_targ_key(unsigned char *out_char_ptr, int4 max_size, gv_key *key, boolean_t dollarc) { unsigned char *gvkey_char_ptr, *out_top, *work_char_ptr, work_buff[MAX_ZWR_KEY_SZ], *work_top; boolean_t is_string; DEBUG_ONLY(unsigned char *gvkey_top_ptr;) assert(12 < max_size); out_top = out_char_ptr + max_size - 2; /* - 2, as could add comma left-paren or TWO double quotes between checks */ gvkey_char_ptr = key->base; DEBUG_ONLY(gvkey_top_ptr = gvkey_char_ptr + key->end;) /* Ensure input key is well-formed (i.e. double null terminated) */ assert(KEY_DELIMITER == *(gvkey_top_ptr - 1)); assert(KEY_DELIMITER == *gvkey_top_ptr); /* The following assert (in the for loop) assumes that a global name will be able to fit in completely into any key. * But that is not true. For exmaple I can have a maxkeysize of 10 and try to set a global variable name of length 20. * That will have issues below. Until C9J10-003204 is fixed to handle long global names and small maxkeysizes, we * let the below code stay as it is (asserts only) to avoid overheads (of if checks for whether end is reached) in pro. * When that is fixed, it is possible, we see the key terminate before even the global name is finished. In that case, * we should return without '(' or ')' in the formatted buffer. The caller will know this is a case of too long global name. */ for (*out_char_ptr++ = '^'; (*out_char_ptr = *gvkey_char_ptr++); out_char_ptr++) assert(gvkey_char_ptr <= gvkey_top_ptr); assert(gvkey_char_ptr <= gvkey_top_ptr); if (0 == *gvkey_char_ptr) /* no subscipts */ return (out_char_ptr); *out_char_ptr++ = '('; for ( ; ; ) { assert(gvkey_char_ptr <= gvkey_top_ptr); if (0x01 == *gvkey_char_ptr) /* this must be a null string which was adjusted by op_gvorder */ { *out_char_ptr++ = '"'; *out_char_ptr++ = '"'; } else { is_string = FALSE; if ((STR_SUB_PREFIX == *gvkey_char_ptr) && !dollarc) { is_string = TRUE; *out_char_ptr++ = '"'; } work_top = gvsub2str(gvkey_char_ptr, work_buff, dollarc); for (work_char_ptr = work_buff; work_char_ptr < work_top;) { if (out_char_ptr >= out_top) { assert(FALSE); return (NULL); } *out_char_ptr++ = *work_char_ptr++; } if (is_string) *out_char_ptr++ = '"'; } if (out_char_ptr >= out_top) { assert(FALSE); return (NULL); } for ( ; *gvkey_char_ptr++; ) assert(gvkey_char_ptr <= gvkey_top_ptr); assert(gvkey_char_ptr <= gvkey_top_ptr); if (*gvkey_char_ptr) *out_char_ptr++ = ','; else break; } *out_char_ptr++ = ')'; assert(gvkey_char_ptr <= gvkey_top_ptr); return (out_char_ptr); } fis-gtm-V6.0-003/sr_port/format_targ_key.h0000644000032200000250000000123312201176156017360 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef FORMAT_TARG_KEY_INCLUDED #define FORMAT_TARG_KEY_INCLUDED unsigned char *format_targ_key(unsigned char *out_char_ptr, int4 max_size, gv_key *key, boolean_t dollarc); #endif /* FORMAT_TARG_KEY_INCLUDED */ fis-gtm-V6.0-003/sr_port/freecnt.mpt0000644000032200000250000000210312201176156016177 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1989,2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %FREECNT;GT.M %FREECNT utility - display database free blocks ; n rn,fn,fb,tb,%ZL i '$d(%zdebug) n $et s $et="zg "_$zl_":ERR^%FREECNT" u $p:(ctrap=$c(3):exc="zg "_$zl_":EXIT^%FREECNT") s rn=$view("GVFIRST") d head,show f s rn=$view("gvnext",rn) q:rn="" d show d EXIT q head ; w "Region",?16,"Free",?25,"Total",?40,"Database file",!,"------",?16,"----",?25,"-----",?40,"-------------",! q show ; s fn=$v("GVFILE",rn),fb=$v("FREEBLOCKS",rn),tb=$v("TOTALBLOCKS",rn) w rn,?12,$j(fb,8),?22,$j(tb,8)," (",$j(fb/tb*100.0,5,1),"%)",?40,fn,! q ERR w !,$p($zs,",",2,99),! s $ec="" ; Warning: Fall-through EXIT u $p:(ctrap="":exc="") q fis-gtm-V6.0-003/sr_port/fullbool.h0000644000032200000250000000123012201176156016016 0ustar librarygtc/**************************************************************** * * * Copyright 2010, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef FULLBOOL_H_INCLUDED #define FULLBOOL_H_INCLUDED enum gtm_bool_type { GTM_BOOL = 0, FULL_BOOL, FULL_BOOL_WARN }; enum gtm_se_type { OLD_SE = 0, STD_SE, SE_WARN }; #endif /* FULLBOOL_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/funsvn.h0000644000032200000250000000113112201176156015517 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ typedef struct { opctype opcode; bool can_set; char os_syst; } svn_data_type; typedef struct{ opctype opcode; char os_syst; } fun_data_type; fis-gtm-V6.0-003/sr_port/g.mpt0000644000032200000250000000446612201176156015015 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1987, 2009 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %G ;GT.M %G utility - global lister ; n %in,%ZL,%ZD i '$d(%zdebug) n $et s $et="zg "_$zl_":ERR^%G" u $p:(ctrap=$c(3):exc="zg "_$zl_":LOOP^%G") f d q:$l(%ZD) . r !,"Output device: : ",%ZD,! . i '$l(%ZD) s %ZD=$p q . i %ZD="^" q . i %ZD="?" d q . . w !!,"Select the device you want for output" . . w !,"If you wish to exit enter a carat (^)",! . . s %ZD="" . i $zparse(%ZD)="" w " no such device" s %ZD="" q . o %ZD:(newversion:block=2048:record=2044:exception="g noopen"):0 . i '$t w !,%ZD," is not available" s %ZD="" q . q noopen . w !,$p($ZS,",",2,999),! c %ZD s %ZD="" q:%ZD="^" d base q base f r !,"List ^",%in,! q:%in="" d . i $e(%in)="?",$l(%in)=1 d help q . i (%in="?D")!(%in="?d") d ^%GD u $p:(ctrap=$c(3):exc="zg "_($zl-2)_":LOOP^%G") q . s:%in="*" %in="?.E(*)" . s:$p(%in,"(")="*" $p(%in,"(")="?.E" . s:$e(%in)'="^" %in="^"_%in . n $et s $et="ZG "_$ZL_":badzwr" . u %ZD zwr @%in u $p . q badzwr . u $p w !,$p($zs,",",3,99),! . s $ec="" d EXIT q help w !,"VALID INPUT",!! w !,?3,"",?16,"to leave the %G utility ",! w !,?4,"?D",?16,"to display existing globals in your directory ",! w !,"[global name]",?16,"the MUMPS name for the global e.g. ABC, or" w !?16,"a MUMPS pattern to match selected globals e.g. ?1""A"".E, or" w !?16,"""*"" as a wildcard for all globals" w !?16,"the global name may be followed by: " w !?16,"subscript(s) in parentheses" w !?16,"a subscript is a MUMPS expression e.g. ""joe"",10,$e(a,1)," w !?16,"a ""*"" as a subscript causes all descendents to be included," w !?16,"or by a range of subscripts in parentheses" w !?16,"expressed as [expr]:[expr] e.g 1:10 ""a"":""d""",! q ERR u $p w !,$p($zs,",",2,99),! s $ecode="" ; Warning - Fall-through EXIT i $d(%ZD),%ZD'=$p c %ZD u $p:(ctrap="":exc="") q LOOP if 1'=$zeof d base q fis-gtm-V6.0-003/sr_port/gbldef.mpt0000644000032200000250000000405512201176156016004 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001, 2004 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %gbldef ; ; ;Global Collation Control ; kill(gname) n $et s $et="g error" i '$$edit(.gname) q 0 i "BGMM"'[$v("GVACCESS_METHOD",$v("REGION",gname)) zm 150376418:$v("REGION",gname); DBREMOTE i $d(@gname) zm 150373626 ;Error if there is data in the global s @gname="" k @gname ;make sure that the global is defined s gname=$e(gname,2,32) ;remove circumflex, take at most 31 chars v "YDIRTVAL":$e($v("YDIRTREE",gname),1,4),"YDIRTREE":gname q 1 ; set(gname,nct,act) n ver,$et s $et="g error" i '$$edit(.gname) q 0 i "BGMM"'[$v("GVACCESS_METHOD",$v("REGION",gname)) zm 150376418:$v("REGION",gname); DBREMOTE i $d(@gname) zm 150373626 ;Error if there is data in the global s act=+$g(act),nct=+$g(nct) s:nct nct=1 i (act>255)!(act<0) zm 150374290:act ; collation type specified is illegal i act s ver=$V("YCOLLATE",act) e s ver=0 i ver<0 zm 150376282:act ; doesn't find coll type, or can't get version s @gname="" k @gname ;make sure that the global is defined s gname=$e(gname,2,32) ;remove circumflex, take at most 31 chars v "YDIRTVAL":$e($v("YDIRTREE",gname),1,4)_$c(1,nct,act,ver),"YDIRTREE":gname q 1 ; get(gname) n t,tl,$et s $et="g error" i '$$edit(.gname) q 0 i "BGMM"'[$v("GVACCESS_METHOD",$v("REGION",gname)) zm 150376418:$v("REGION",gname); DBREMOTE s t=$e($v("YDIRTREE",$e(gname,2,32)),5,999),tl=$l(t) ;remove circumflex, take at most 31 chars i tl,tl>4!($a(t,1)'=1) zm 150374058 q $s(tl:$a(t,2)_","_$a(t,3)_","_$a(t,4),1:0) ; edit(gname) i $e(gname)'="^" s gname="^"_gname i $e(gname,2)'="%",$e(gname,2)'?1A zm 150373218 ; LKNAMEXPECTED i gname'?1"^"1E.AN zm 150373218 q 1 ; error s $ec="" q 0 fis-gtm-V6.0-003/sr_port/gbldefs.c0000644000032200000250000015771512201176176015627 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* General repository for global variable definitions. This keeps us from * pulling in modules and all their references when all we wanted was the * global data def. * * Note, all GBLDEF fields are automatically cleared to zeroes. No initialization to * zero (0) or NULL or any other value that translates to zeroes is necessary on these * fields and should be avoided as it creates extra linker and image startup processing * that can only slow things down even if only by a little. */ #include "mdef.h" #include "gtm_inet.h" #include "gtm_iconv.h" #include "gtm_socket.h" #include "gtm_unistd.h" #include "gtm_limits.h" #include #include #ifdef UNIX # include #endif #ifdef VMS # include /* Required for gtmsource.h */ # include # include # include "desblk.h" #endif #ifdef GTM_PTHREAD # include #endif #include "cache.h" #include "hashtab_addr.h" #include "hashtab_int4.h" #include "hashtab_int8.h" #include "hashtab_mname.h" #include "hashtab_str.h" #include "hashtab_objcode.h" /* The define of CHEXPAND below causes error.h to create GBLDEFs */ #define CHEXPAND #include "error.h" #include #include "gdsroot.h" #include "gdskill.h" #include "ccp.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gdscc.h" #include "comline.h" #include "compiler.h" #include "cmd_qlf.h" #include "io.h" #include "iosp.h" #include "jnl.h" #include "lv_val.h" #include "mdq.h" #include "mprof.h" #include "mv_stent.h" #include "stack_frame.h" #include "stp_parms.h" #include "stringpool.h" #include "buddy_list.h" /* needed for tp.h */ #include "tp.h" #include "tp_frame.h" #include "mlkdef.h" #include "zshow.h" #include "zwrite.h" #include "zbreak.h" #include "mmseg.h" #ifndef VMS # include "gtmsiginfo.h" #endif #include "gtmimagename.h" #include "iotcpdef.h" #include "gt_timer.h" #include "iosocketdef.h" /* needed for socket_pool and MAX_N_SOCKETS */ #include "ctrlc_handler_dummy.h" #include "unw_prof_frame_dummy.h" #include "op.h" #include "gtmsecshr.h" #include "error_trap.h" #include "patcode.h" /* for pat_everything and sizeof_pat_everything */ #include "source_file.h" /* for REV_TIME_BUFF_LEN */ #include "mupipbckup.h" #include "dpgbldir.h" #include "mmemory.h" #include "have_crit.h" #include "alias.h" /* FOR REPLICATION RELATED GLOBALS */ #include "repl_msg.h" #include "gtmsource.h" #include "gtmrecv.h" /* FOR MERGE RELATED GLOBALS */ #include "gvname_info.h" #include "op_merge.h" #ifdef UNIX #include "cli.h" #include "invocation_mode.h" #include "fgncal.h" #include "parse_file.h" /* for MAX_FBUFF */ #include "repl_sem.h" #include "gtm_zlib.h" #include "anticipatory_freeze.h" #endif #include "jnl_typedef.h" #include "repl_ctl.h" #ifdef VMS #include "gtm_logicals.h" /* for GTM_MEMORY_NOACCESS_COUNT */ #endif #include "gds_blk_upgrade.h" /* for UPGRADE_IF_NEEDED flag */ #include "cws_insert.h" /* for CWS_REORG_ARRAYSIZE */ #ifdef UNICODE_SUPPORTED #include "gtm_icu_api.h" #include "gtm_utf8.h" #include "gtm_conv.h" #endif # ifdef GTM_CRYPT # include "gtmcrypt.h" # include "gdsblk.h" # include "muextr.h" # endif #ifdef GTM_TRIGGER #include "gv_trigger.h" #include "gtm_trigger.h" #endif #define DEFAULT_ZERROR_STR "Unprocessed $ZERROR, see $ZSTATUS" #define DEFAULT_ZERROR_LEN (SIZEOF(DEFAULT_ZERROR_STR) - 1) GBLDEF gd_region *db_init_region; GBLDEF sgmnt_data_ptr_t cs_data; GBLDEF sgmnt_addrs *cs_addrs; GBLDEF sgmnt_addrs *cs_addrs_list; /* linked list of csa corresponding to all currently open databases */ GBLDEF unsigned short proc_act_type; GBLDEF volatile bool ctrlc_pending; GBLDEF bool undef_inhibit; GBLDEF volatile int4 ctrap_action_is; GBLDEF bool out_of_time; GBLDEF io_pair io_curr_device; /* current device */ GBLDEF io_pair io_std_device; /* standard device */ GBLDEF io_log_name *dollar_principal; /* pointer to log name GTM$PRINCIPAL if defined */ GBLDEF bool prin_in_dev_failure; GBLDEF bool prin_out_dev_failure; GBLDEF io_desc *active_device; GBLDEF bool error_mupip, file_backed_up, gv_replopen_error, gv_replication_error, incremental, jobpid, online, record, std_dev_outbnd, in_mupip_freeze, in_backup, view_debug1, view_debug2, view_debug3, view_debug4, mupip_error_occurred, dec_nofac; GBLDEF boolean_t is_updproc, is_updhelper, mupip_jnl_recover, suspend_lvgcol, run_time, unhandled_stale_timer_pop, gtcm_connection, is_replicator, /* TRUE => this process can write jnl records to the jnlpool for replicated db */ tp_in_use, /* TRUE => TP has been used by this process and is thus initialized */ dollar_truth = TRUE, gtm_stdxkill, /* TRUE => Use M Standard X-KILL - FALSE use historical GTM X-KILL (default) */ in_timed_tn, /* TRUE => Timed TP transaction in progress */ tp_timeout_deferred; /* TRUE => A TP timeout has occurred but is deferred */ GBLDEF volatile boolean_t tp_timeout_set_xfer; /* TRUE => A timeout succeeded in setting xfer table intercepts. This flag stays * a true global unless each thread gets its own xfer table. */ GBLDEF VSIG_ATOMIC_T forced_exit; /* Asynchronous signal/interrupt handler sets this variable to TRUE, * hence the VSIG_ATOMIC_T type in the definition. */ GBLDEF intrpt_state_t intrpt_ok_state = INTRPT_OK_TO_INTERRUPT; /* any other value implies it is not ok to interrupt */ GBLDEF unsigned char *msp, *mubbuf, *restart_ctxt, *stackbase, *stacktop, *stackwarn, *restart_pc; GBLDEF int4 backup_close_errno, backup_write_errno, mubmaxblk, forced_exit_err, exit_state, restore_read_errno; GBLDEF volatile int4 outofband, crit_count; GBLDEF int mumps_status = SS_NORMAL, stp_array_size; GBLDEF gvzwrite_datablk *gvzwrite_block; GBLDEF lvzwrite_datablk *lvzwrite_block; GBLDEF io_log_name *io_root_log_name; GBLDEF mliteral literal_chain; GBLDEF mstr *comline_base, *err_act, **stp_array, extnam_str, env_gtm_env_xlate; GBLDEF MSTR_CONST(default_sysid, "gtm_sysid"); GBLDEF mval dollar_zgbldir, dollar_zsource = DEFINE_MVAL_STRING(MV_STR, 0, 0, 0, NULL, 0, 0), dollar_zstatus, dollar_zstep = DEFINE_MVAL_STRING(MV_STR | MV_NM | MV_INT | MV_NUM_APPROX, 0, 0, 1, "B", 0, 0), dollar_ztrap, ztrap_pop2level = DEFINE_MVAL_STRING(MV_NM | MV_INT, 0, 0, 0, 0, 0, 0), zstep_action, dollar_system, dollar_estack_delta = DEFINE_MVAL_STRING(MV_STR, 0, 0, 0, NULL, 0, 0), dollar_etrap, dollar_zerror = DEFINE_MVAL_STRING(MV_STR, 0, 0, DEFAULT_ZERROR_LEN, DEFAULT_ZERROR_STR, 0, 0), dollar_zyerror, dollar_ztexit = DEFINE_MVAL_STRING(MV_STR, 0, 0, 0, NULL, 0, 0); GBLDEF uint4 dollar_zjob; GBLDEF mval dollar_zinterrupt; GBLDEF boolean_t dollar_zininterrupt; GBLDEF boolean_t dollar_ztexit_bool; /* Truth value of dollar_ztexit when coerced to boolean */ GBLDEF boolean_t dollar_zquit_anyway; GBLDEF mv_stent *mv_chain; GBLDEF sgm_info *first_sgm_info; /* List of participating regions in the TP transaction with NO ftok ordering */ GBLDEF sgm_info *first_tp_si_by_ftok; /* List of participating regions in the TP transaction sorted on ftok order */ GBLDEF spdesc indr_stringpool, rts_stringpool, stringpool; GBLDEF stack_frame *frame_pointer; GBLDEF stack_frame *zyerr_frame; GBLDEF symval *curr_symval; GBLDEF tp_frame *tp_pointer; GBLDEF tp_region *halt_ptr, *grlist; GBLDEF trans_num local_tn; /* transaction number for THIS PROCESS (starts at 0 each time) */ GBLDEF trans_num tstart_local_tn; /* copy of global variable "local_tn" at op_tstart time */ GBLDEF gv_namehead *gv_target; GBLDEF gv_namehead *gv_target_list; /* List of ALL gvts that were allocated (in targ_alloc) by this process */ GBLDEF gv_namehead *gvt_tp_list; /* List of gvts that were referenced in the current TP transaction */ GBLDEF gvt_container *gvt_pending_list; /* list of gvts that need to be re-examined/re-allocated when region is opened */ GBLDEF buddy_list *gvt_pending_buddy_list;/* buddy_list for maintaining memory for gv_targets to be re-examined/allocated */ GBLDEF int4 exi_condition; GBLDEF uint4 gtmDebugLevel; GBLDEF caddr_t smCallerId; /* Caller of top level malloc/free */ GBLDEF int process_exiting; GBLDEF int4 dollar_zsystem; GBLDEF int4 dollar_zeditor; GBLDEF rtn_tabent *rtn_fst_table, *rtn_names, *rtn_names_top, *rtn_names_end; GBLDEF int4 break_message_mask; GBLDEF bool rc_locked; GBLDEF boolean_t certify_all_blocks; /* If flag is set all blocks are checked after they are * written to the database. Upon error we stay critical * and report. This flag can be set via the MUMPS command * VIEW "GDSCERT":1. */ GBLDEF mval curr_gbl_root; GBLDEF gd_addr *original_header; GBLDEF hash_table_str *complits_hashtab; GBLDEF hash_table_str *compsyms_hashtab; GBLDEF mem_list *mem_list_head; GBLDEF boolean_t debug_mupip; GBLDEF unsigned char t_fail_hist[CDB_MAX_TRIES]; /* type has to be unsigned char and not enum cdb_sc to ensure single byte */ GBLDEF cache_rec_ptr_t cr_array[((MAX_BT_DEPTH * 2) - 1) * 2]; /* Maximum number of blocks that can be in transaction */ GBLDEF unsigned int cr_array_index; GBLDEF boolean_t need_core; /* Core file should be created */ GBLDEF boolean_t created_core; /* core file was created */ GBLDEF unsigned int core_in_progress; /* creating core NOW if > 0 */ GBLDEF boolean_t dont_want_core; /* Higher level flag overrides need_core set by lower level rtns */ GBLDEF boolean_t exit_handler_active; /* recursion prevention */ GBLDEF boolean_t block_saved; #if defined(KEEP_zOS_EBCDIC) || defined(VMS) GBLDEF iconv_t dse_over_cvtcd = (iconv_t)0; #endif GBLDEF gtm_chset_t dse_over_chset = CHSET_M; LITDEF MIDENT_DEF(zero_ident, 0, NULL); /* the null mident */ GBLDEF char *lexical_ptr; GBLDEF int4 aligned_source_buffer[MAX_SRCLINE / SIZEOF(int4) + 1]; GBLDEF unsigned char *source_buffer = (unsigned char *)aligned_source_buffer; GBLDEF src_line_struct src_head; GBLDEF short int source_column, source_line; GBLDEF bool devctlexp; GBLDEF char cg_phase; /* code generation phase */ /* Previous code generation phase: Only used by emit_code.c to initialize the push list at the * beginning of each phase (bug fix: C9D12-002478) */ GBLDEF char cg_phase_last; GBLDEF int cmd_cnt; GBLDEF command_qualifier glb_cmd_qlf = { CQ_DEFAULT }, cmd_qlf = { CQ_DEFAULT }; #ifdef __osf__ #pragma pointer_size (save) #pragma pointer_size (long) #endif GBLDEF char **cmd_arg; #ifdef __osf__ #pragma pointer_size (restore) #endif #ifdef UNIX GBLDEF volatile uint4 heartbeat_counter; GBLDEF boolean_t heartbeat_started; #endif /* DEFERRED EVENTS */ GBLDEF bool licensed = TRUE; #if defined(UNIX) GBLDEF volatile int4 num_deferred; #elif defined(VMS) GBLDEF volatile short num_deferred; GBLDEF int4 lkid, lid; GBLDEF desblk exi_blk; GBLDEF struct chf$signal_array *tp_restart_fail_sig; GBLDEF boolean_t tp_restart_fail_sig_used; #else # error "Unsupported Platform" #endif GBLDEF volatile int4 fast_lock_count; /* Used in wcs_stale */ /* REPLICATION RELATED GLOBALS */ GBLDEF gtmsource_options_t gtmsource_options; GBLDEF gtmrecv_options_t gtmrecv_options; GBLDEF boolean_t is_tracing_on; GBLDEF void (*tp_timeout_start_timer_ptr)(int4 tmout_sec) = tp_start_timer_dummy; GBLDEF void (*tp_timeout_clear_ptr)(void) = tp_clear_timeout_dummy; GBLDEF void (*tp_timeout_action_ptr)(void) = tp_timeout_action_dummy; GBLDEF void (*ctrlc_handler_ptr)() = ctrlc_handler_dummy; GBLDEF int (*op_open_ptr)(mval *v, mval *p, int t, mval *mspace) = op_open_dummy; GBLDEF void (*unw_prof_frame_ptr)(void) = unw_prof_frame_dummy; GBLDEF void (*heartbeat_timer_ptr)(void); /* Initialized only in gtm_startup() */ #ifdef UNICODE_SUPPORTED GBLDEF u_casemap_t gtm_strToTitle_ptr; /* Function pointer for gtm_strToTitle */ #endif GBLDEF boolean_t mu_reorg_process; /* set to TRUE by MUPIP REORG */ GBLDEF boolean_t mu_reorg_in_swap_blk; /* set to TRUE for the duration of the call to "mu_swap_blk" */ GBLDEF boolean_t mu_rndwn_process; GBLDEF gv_key *gv_currkey_next_reorg; GBLDEF gv_namehead *reorg_gv_target; #ifdef UNIX GBLDEF struct sockaddr_un gtmsecshr_sock_name; GBLDEF struct sockaddr_un gtmsecshr_cli_sock_name; GBLDEF key_t gtmsecshr_key; #endif GBLDEF int gtmsecshr_sockpath_len; GBLDEF int gtmsecshr_cli_sockpath_len; GBLDEF mstr gtmsecshr_pathname; GBLDEF int server_start_tries; GBLDEF int gtmsecshr_sockfd = FD_INVALID; GBLDEF boolean_t gtmsecshr_sock_init_done; GBLDEF char muext_code[MUEXT_MAX_TYPES][2] = { # define MUEXT_TABLE_ENTRY(muext_rectype, code0, code1) {code0, code1}, # include "muext_rec_table.h" # undef MUEXT_TABLE_ENTRY }; GBLDEF int patch_is_fdmp; GBLDEF int patch_fdmp_recs; GBLDEF boolean_t horiz_growth; GBLDEF int4 prev_first_off, prev_next_off; /* these two globals store the values of first_off and next_off in cse, * when there is a blk split at index level. This is to permit rollback * to intermediate states */ GBLDEF sm_uc_ptr_t min_mmseg; GBLDEF sm_uc_ptr_t max_mmseg; GBLDEF mmseg *mmseg_head; GBLDEF ua_list *first_ua, *curr_ua; GBLDEF char *update_array, *update_array_ptr; GBLDEF int gv_fillfactor = 100, rc_set_fragment; /* Contains offset within data at which data fragment starts */ GBLDEF uint4 update_array_size, cumul_update_array_size; /* the current total size of the update array */ GBLDEF kill_set *kill_set_tail; GBLDEF boolean_t pool_init; GBLDEF boolean_t is_src_server; GBLDEF boolean_t is_rcvr_server; GBLDEF jnl_format_buffer *non_tp_jfb_ptr; GBLDEF boolean_t dse_running; GBLDEF jnlpool_addrs jnlpool; GBLDEF jnlpool_ctl_ptr_t jnlpool_ctl; GBLDEF jnlpool_ctl_struct temp_jnlpool_ctl_struct; GBLDEF jnlpool_ctl_ptr_t temp_jnlpool_ctl = &temp_jnlpool_ctl_struct; GBLDEF sm_uc_ptr_t jnldata_base; GBLDEF int4 jnlpool_shmid = INVALID_SHMID; GBLDEF recvpool_addrs recvpool; GBLDEF int recvpool_shmid = INVALID_SHMID; GBLDEF int gtmsource_srv_count; GBLDEF int gtmrecv_srv_count; /* The following _in_prog counters are needed to prevent deadlocks while doing jnl-qio (timer & non-timer). */ GBLDEF volatile int4 db_fsync_in_prog; GBLDEF volatile int4 jnl_qio_in_prog; #ifdef UNIX GBLDEF void (*op_write_ptr)(mval *); GBLDEF void (*op_wteol_ptr)(int4 n); GBLDEF gtmsiginfo_t signal_info; #ifndef MUTEX_MSEM_WAKE GBLDEF int mutex_sock_fd = FD_INVALID; GBLDEF struct sockaddr_un mutex_sock_address; GBLDEF struct sockaddr_un mutex_wake_this_proc; GBLDEF int mutex_wake_this_proc_len; GBLDEF int mutex_wake_this_proc_prefix_len; GBLDEF fd_set mutex_wait_on_descs; #endif #endif GBLDEF void (*call_on_signal)(); GBLDEF enum gtmImageTypes image_type; /* initialized at startup i.e. in dse.c, lke.c, gtm.c, mupip.c, gtmsecshr.c etc. */ #ifdef UNIX GBLDEF parmblk_struct *param_list; /* call-in parameters block (defined in unix/fgncalsp.h)*/ GBLDEF unsigned int invocation_mode = MUMPS_COMPILE; /* how mumps has been invoked */ GBLDEF char cli_err_str[MAX_CLI_ERR_STR] = ""; /* Parse Error message buffer */ GBLDEF char *cli_err_str_ptr; GBLDEF boolean_t gtm_pipe_child; #endif GBLDEF io_desc *gtm_err_dev; /* this array is indexed by file descriptor */ GBLDEF boolean_t *lseekIoInProgress_flags; #if defined(UNIX) /* Latch variable for Unix implementations. Used in SUN and HP */ GBLDEF global_latch_t defer_latch; #endif GBLDEF int num_additional_processors; GBLDEF int gtm_errno = -1; /* holds the errno (unix) in case of an rts_error */ GBLDEF int4 error_condition; GBLDEF global_tlvl_info *global_tlvl_info_head; GBLDEF buddy_list *global_tlvl_info_list; GBLDEF boolean_t job_try_again; GBLDEF volatile int4 gtmMallocDepth; /* Recursion indicator */ GBLDEF d_socket_struct *socket_pool; GBLDEF boolean_t mu_star_specified; GBLDEF backup_reg_list *mu_repl_inst_reg_list; #ifndef VMS GBLDEF volatile int suspend_status = NO_SUSPEND; #endif GBLDEF gv_namehead *reset_gv_target = INVALID_GV_TARGET; GBLDEF VSIG_ATOMIC_T util_interrupt; GBLDEF sgmnt_addrs *kip_csa; GBLDEF boolean_t need_kip_incr; GBLDEF int merge_args; GBLDEF merge_glvn_ptr mglvnp; GBLDEF int ztrap_form; GBLDEF boolean_t ztrap_new; GBLDEF int4 wtfini_in_prog; /* items for $piece stats */ #ifdef DEBUG GBLDEF int c_miss; /* cache misses (debug) */ GBLDEF int c_hit; /* cache hits (debug) */ GBLDEF int c_small; /* scanned small string brute force */ GBLDEF int c_small_pcs; /* chars scanned by small scan */ GBLDEF int c_pskip; /* number of pieces "skipped" */ GBLDEF int c_pscan; /* number of pieces "scanned" */ GBLDEF int c_parscan; /* number of partial scans (partial cache hits) */ GBLDEF int cs_miss; /* cache misses (debug) */ GBLDEF int cs_hit; /* cache hits (debug) */ GBLDEF int cs_small; /* scanned small string brute force */ GBLDEF int cs_small_pcs; /* chars scanned by small scan */ GBLDEF int cs_pskip; /* number of pieces "skipped" */ GBLDEF int cs_pscan; /* number of pieces "scanned" */ GBLDEF int cs_parscan; /* number of partial scans (partial cache hits) */ GBLDEF int c_clear; /* cleared due to (possible) value change */ GBLDEF boolean_t setp_work; #endif GBLDEF z_records zbrk_recs; #ifdef UNIX GBLDEF ipcs_mesg db_ipcs; /* For requesting gtmsecshr to update ipc fields */ GBLDEF gd_region *ftok_sem_reg; /* Last region for which ftok semaphore is grabbed */ GBLDEF int gtm_non_blocked_write_retries; /* number of retries for non-blocked write to pipe */ #endif #ifdef VMS /* Following global variables store the state of an erroring sys$qio just before a GTMASSERT in the CHECK_CHANNEL_STATUS macro */ GBLDEF uint4 check_channel_status; /* stores the qio return status */ GBLDEF uint4 check_channel_id; /* stores the qio channel id */ #endif GBLDEF boolean_t write_after_image; /* true for after-image jnlrecord writing by recover/rollback */ GBLDEF int iott_write_error; GBLDEF int4 write_filter; GBLDEF boolean_t need_no_standalone; GBLDEF int4 zdir_form = ZDIR_FORM_FULLPATH; /* $ZDIR shows full path including DEVICE and DIRECTORY */ GBLDEF mval dollar_zdir = DEFINE_MVAL_STRING(MV_STR, 0, 0, 0, NULL, 0, 0); GBLDEF int * volatile var_on_cstack_ptr; /* volatile pointer to int; volatile so that nothing gets optimized out */ GBLDEF hash_table_int4 cw_stagnate; GBLDEF boolean_t cw_stagnate_reinitialized; GBLDEF uint4 pat_everything[] = { 0, 2, PATM_E, 1, 0, PAT_MAX_REPEAT, 0, PAT_MAX_REPEAT, 1 }; /* pattern = ".e" */ GBLDEF mstr_len_t sizeof_pat_everything = SIZEOF(pat_everything); GBLDEF uint4 *pattern_typemask; GBLDEF pattern *pattern_list; GBLDEF pattern *curr_pattern; /* Unicode related data */ GBLDEF boolean_t gtm_utf8_mode; /* Is GT.M running with Unicode Character Set; Set only after ICU initialization */ GBLDEF boolean_t is_gtm_chset_utf8; /* Is gtm_chset environment variable set to UTF8 */ GBLDEF boolean_t utf8_patnumeric; /* Should patcode N match non-ASCII numbers in pattern match ? */ GBLDEF boolean_t badchar_inhibit; /* Suppress malformed UTF-8 characters by default */ GBLDEF MSTR_DEF(dollar_zchset, 1, "M"); GBLDEF MSTR_DEF(dollar_zpatnumeric, 1, "M"); /* Standard MUMPS pattern-match table. * This table holds the current pattern-matching attributes of each ASCII character. * Bits 0..23 of each entry correspond with the pattern-match characters, A..X. */ GBLDEF pattern mumps_pattern = { (void *) 0, /* flink */ (void *) 0, /* typemask */ (void *) 0, /* pat YZ name array */ (void *) 0, /* pat YZ name-length array */ -1, /* number of YZ patcodes */ 1, /* namlen */ {'M', '\0'} /* name */ }; /* mapbit is used by pattab.c and patstr.c. Note that patstr.c uses only entries until PATM_X */ GBLDEF readonly uint4 mapbit[] = { PATM_A, PATM_B, PATM_C, PATM_D, PATM_E, PATM_F, PATM_G, PATM_H, PATM_I, PATM_J, PATM_K, PATM_L, PATM_M, PATM_N, PATM_O, PATM_P, PATM_Q, PATM_R, PATM_S, PATM_T, PATM_U, PATM_V, PATM_W, PATM_X, PATM_YZ1, PATM_YZ2, PATM_YZ3, PATM_YZ4 }; LITDEF uint4 typemask[PATENTS] = { PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, /* hex 00-07 : ASCII characters */ PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, /* hex 08-0F : ASCII characters */ PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, /* hex 10-17 : ASCII characters */ PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, /* hex 18-1F : ASCII characters */ PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, /* hex 20-27 : ASCII characters */ PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, /* hex 28-2F : ASCII characters */ PATM_N, PATM_N, PATM_N, PATM_N, PATM_N, PATM_N, PATM_N, PATM_N, /* hex 30-37 : ASCII characters */ PATM_N, PATM_N, PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, /* hex 38-3F : ASCII characters */ PATM_P, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, /* hex 40-47 : ASCII characters */ PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, /* hex 48-4F : ASCII characters */ PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, /* hex 50-57 : ASCII characters */ PATM_U, PATM_U, PATM_U, PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, /* hex 58-5F : ASCII characters */ PATM_P, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, /* hex 60-67 : ASCII characters */ PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, /* hex 68-6F : ASCII characters */ PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, /* hex 70-77 : ASCII characters */ PATM_L, PATM_L, PATM_L, PATM_P, PATM_P, PATM_P, PATM_P, PATM_C, /* hex 78-7F : ASCII characters */ PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, /* hex 80-87 : non-ASCII characters */ PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, /* hex 88-8F : non-ASCII characters */ PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, /* hex 90-97 : non-ASCII characters */ PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, /* hex 98-9F : non-ASCII characters */ PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, /* hex A0-A7 : non-ASCII characters */ PATM_P, PATM_P, PATM_L, PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, /* hex A8-AF : non-ASCII characters */ PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, /* hex B0-B7 : non-ASCII characters */ PATM_P, PATM_P, PATM_L, PATM_P, PATM_P, PATM_P, PATM_P, PATM_P, /* hex B8-BF : non-ASCII characters */ PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, /* hex C0-C7 : non-ASCII characters */ PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, /* hex C8-CF : non-ASCII characters */ PATM_P, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, /* hex D0-D7 : non-ASCII characters */ PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_U, PATM_P, PATM_L, /* hex D8-DF : non-ASCII characters */ PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, /* hex E0-E7 : non-ASCII characters */ PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, /* hex E8-EF : non-ASCII characters */ PATM_P, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, /* hex F0-F7 : non-ASCII characters */ PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_P, PATM_C /* hex F8-FF : non-ASCII characters */ }; GBLDEF uint4 pat_allmaskbits; /* universal set of valid pattern bit codes for currently active pattern table */ /* globals related to caching of pattern evaluation match result. * for a given tuple, we store the evaluation result. * in the above, * uniquely identifies a substring of the input string. * identifies the pattern atom that we are matching with * identifies the recursion depth of do_patalt() for this pattern atom ("repcnt" in code) * note that is a necessity in the above because the same alternation pattern atom can have different * match or not-match status for the same input string depending on the repetition count usage of the pattern atom * after a series of thoughts on an efficient structure for storing pattern evaluation, finally arrived at a simple * array of structures wherein for a given length (strlen) we have a fixed number of structures available. * we allocate an array of structures, say, 1024 structures. * this is a simple 1-1 mapping, wherein * for length 0, the available structures are the first 32 structures of the array, * for length 1, the available structures are the second 32 structures of the array. * ... * for length 47, the available structures are the 47th 32 structures of the array. * for length 48 and above, the available structures are all the remaining structures of the array. * whenever any new entry needs to be cached and there is no room among the available structures, we preempt the * most unfrequently used cache entry (to do this we do keep a count of every entry's frequency of usage) * the assumption is that substrings of length > 48 (an arbitrary reasonable small number) won't be used * so frequently so that they have lesser entries to fight for among themselves than lower values of length. * with the above caching in place, the program segment below took 15 seconds. * it was found that if the array size is increased to 16384 (as opposed to 1024 as above) and the available * structures for each length increased proportionally (i.e. 16 times = 16*32 structures instead of 32 as above) * the performance improved to the extent of taking 3 seconds. * but this raised an interesting question, that of "size" vs. "time" tradeoff. * with increasing array size, we get better "time" performance due to better caching. * but that has an overhead of increased "size" (memory) usage. * to arrive at a compromise, a dynamic algorithm emerged. the process will allocate a small array * beginning at 1024 entries and grow to a max of 16384 entries as and when it deems the hit ratio is not good. * the array only grows, i.e. there is no downsizing algorithm at play. * the dynamic algorithm addresses to an extent both the "size" and "time" issues and finishes the below in 1 second. * #defines for the dynamic algorithm growth can be found in patcode.h */ GBLDEF int4 curalt_depth = -1; /* depth of alternation nesting */ GBLDEF int4 do_patalt_calls[PTE_MAX_CURALT_DEPTH]; /* number of calls to do_patalt() */ GBLDEF int4 do_patalt_hits[PTE_MAX_CURALT_DEPTH]; /* number of pte_csh hits in do_patalt() */ GBLDEF int4 do_patalt_maxed_out[PTE_MAX_CURALT_DEPTH]; /* no. of pte_csh misses after maxing on allocation size */ GBLDEF pte_csh *pte_csh_array[PTE_MAX_CURALT_DEPTH]; /* pte_csh array (per curalt_depth) */ GBLDEF int4 pte_csh_cur_size[PTE_MAX_CURALT_DEPTH]; /* current pte_csh size (per curalt_depth) */ GBLDEF int4 pte_csh_alloc_size[PTE_MAX_CURALT_DEPTH]; /* current allocated pte_csh size (per curalt_depth) */ GBLDEF int4 pte_csh_entries_per_len[PTE_MAX_CURALT_DEPTH]; /* current number of entries per len */ GBLDEF int4 pte_csh_tail_count[PTE_MAX_CURALT_DEPTH]; /* count of non 1-1 corresponding pte_csh_array members */ GBLDEF pte_csh *cur_pte_csh_array; /* copy of pte_csh_array corresponding to curalt_depth */ GBLDEF int4 cur_pte_csh_size; /* copy of pte_csh_cur_size corresponding to curalt_depth */ GBLDEF int4 cur_pte_csh_entries_per_len; /* copy of pte_csh_entries_per_len corresponding to curalt_depth */ GBLDEF int4 cur_pte_csh_tail_count; /* copy of pte_csh_tail_count corresponding to curalt_depth */ GBLDEF readonly char *before_image_lit[] = {"NOBEFORE_IMAGES", "BEFORE_IMAGES"}; GBLDEF readonly char *jnl_state_lit[] = {"DISABLED", "OFF", "ON"}; GBLDEF readonly char *repl_state_lit[] = {"OFF", "ON", "WAS_ON"}; GBLDEF boolean_t crit_sleep_expired; /* mutex.mar: signals that a timer waiting for crit has expired */ GBLDEF uint4 crit_deadlock_check_cycle; /* compared to csa->crit_check_cycle to determine if a given region in a transaction legitimately has crit or not */ GBLDEF node_local_ptr_t locknl; /* if non-NULL, indicates node-local of interest to the LOCK_HIST macro */ GBLDEF boolean_t in_mutex_deadlock_check; /* if TRUE, mutex_deadlock_check() is part of our current C-stack trace */ /* $ECODE and $STACK related variables. * error_frame and skip_error_ret should ideally be part of dollar_ecode structure. since sr_avms/opp_ret.m64 uses these * global variables and it was felt risky changing it to access a member of a structure, they are kept as separate globals */ GBLDEF stack_frame *error_frame; /* ptr to frame where last error occurred or was rethrown */ GBLDEF boolean_t skip_error_ret; /* set to TRUE by golevel(), used and reset by op_unwind() */ GBLDEF dollar_ecode_type dollar_ecode; /* structure containing $ECODE related information */ GBLDEF dollar_stack_type dollar_stack; /* structure containing $STACK related information */ GBLDEF boolean_t ztrap_explicit_null; /* whether $ZTRAP was explicitly set to NULL in the current frame */ GBLDEF int4 gtm_object_size; /* Size of entire gtm object for compiler use */ GBLDEF int4 linkage_size; /* Size of linkage section during compile */ GBLDEF uint4 lnkrel_cnt; /* number of entries in linkage Psect to relocate */ GBLDEF int4 sym_table_size; /* size of the symbol table during compilation */ GBLDEF boolean_t stop_non_mandatory_expansion, non_mandatory_expansion; /* Used in stringpool managment */ GBLDEF jnl_fence_control jnl_fence_ctl; GBLDEF jnl_process_vector *prc_vec; /* for current process */ GBLDEF jnl_process_vector *originator_prc_vec; /* for client/originator */ LITDEF char *jrt_label[JRT_RECTYPES] = { #define JNL_TABLE_ENTRY(rectype, extract_rtn, label, update, fixed_size, is_replicated) label, #include "jnl_rec_table.h" /* BYPASSOK */ #undef JNL_TABLE_ENTRY }; LITDEF int jrt_update[JRT_RECTYPES] = { #define JNL_TABLE_ENTRY(rectype, extract_rtn, label, update, fixed_size, is_replicated) update, #include "jnl_rec_table.h" /* BYPASSOK */ #undef JNL_TABLE_ENTRY }; LITDEF boolean_t jrt_fixed_size[JRT_RECTYPES] = { #define JNL_TABLE_ENTRY(rectype, extract_rtn, label, update, fixed_size, is_replicated) fixed_size, #include "jnl_rec_table.h" /* BYPASSOK */ #undef JNL_TABLE_ENTRY }; LITDEF boolean_t jrt_is_replicated[JRT_RECTYPES] = { #define JNL_TABLE_ENTRY(rectype, extract_rtn, label, update, fixed_size, is_replicated) is_replicated, #include "jnl_rec_table.h" /* BYPASSOK */ #undef JNL_TABLE_ENTRY }; LITDEF char *jnl_file_state_lit[JNL_FILE_STATES] = { "JNL_FILE_UNREAD", "JNL_FILE_OPEN", "JNL_FILE_CLOSED", "JNL_FILE_EMPTY" }; /* Change the initialization if struct_jrec_tcom in jnl.h changes */ GBLDEF struct_jrec_tcom tcom_record = {{JRT_TCOM, TCOM_RECLEN, 0, 0, 0, 0}, 0, 0, 0, 0, "", {TCOM_RECLEN, JNL_REC_SUFFIX_CODE}}; GBLDEF jnl_gbls_t jgbl; GBLDEF short crash_count; GBLDEF trans_num start_tn; GBLDEF cw_set_element cw_set[CDB_CW_SET_SIZE]; GBLDEF unsigned char cw_set_depth, cw_map_depth; GBLDEF unsigned int t_tries; GBLDEF uint4 t_err; GBLDEF uint4 update_trans; /* Bitmask indicating among other things whether this region was updated; * See gdsfhead.h for UPDTRNS_* bitmasks * Bit-0 is 1 if cw_set_depth is non-zero or if it is a duplicate set * (cw_set_depth is zero in that case). * Bit-1 is unused for non-TP. * Bit-2 is 1 if transaction commit in this region is beyond point of rollback. */ GBLDEF boolean_t is_uchar_wcs_code[] = /* uppercase failure codes that imply database cache related problem */ { /* if any of the following failure codes are seen in the final retry, wc_blocked will be set to trigger cache recovery */ #define CDB_SC_NUM_ENTRY(code, value) #define CDB_SC_UCHAR_ENTRY(code, is_wcs_code, value) is_wcs_code, #define CDB_SC_LCHAR_ENTRY(code, is_wcs_code, value) #include "cdb_sc_table.h" /* BYPASSOK */ #undef CDB_SC_NUM_ENTRY #undef CDB_SC_UCHAR_ENTRY #undef CDB_SC_LCHAR_ENTRY }; GBLDEF boolean_t is_lchar_wcs_code[] = /* lowercase failure codes that imply database cache related problem */ { /* if any of the following failure codes are seen in the final retry, wc_blocked will be set to trigger cache recovery */ #define CDB_SC_NUM_ENTRY(code, value) #define CDB_SC_UCHAR_ENTRY(code, is_wcs_code, value) #define CDB_SC_LCHAR_ENTRY(code, is_wcs_code, value) is_wcs_code, #include "cdb_sc_table.h" /* BYPASSOK */ #undef CDB_SC_NUM_ENTRY #undef CDB_SC_UCHAR_ENTRY #undef CDB_SC_LCHAR_ENTRY }; GBLDEF boolean_t gvdupsetnoop = TRUE; /* if TRUE, duplicate SETs do not change GDS block (and therefore no PBLK journal * records will be written) although the database transaction number will be * incremented and logical SET journal records will be written. By default, this * behavior is turned ON. GT.M has a way of turning it off with a VIEW command. */ GBLDEF boolean_t gtm_fullblockwrites; /* Do full (not partial) database block writes T/F */ UNIX_ONLY(GBLDEF int4 gtm_shmflags;) /* Extra flags for shmat */ #ifdef VMS GBLDEF uint4 gtm_memory_noaccess_defined; /* count of the number of GTM_MEMORY_NOACCESS_ADDR logicals which are defined */ GBLDEF uint4 gtm_memory_noaccess[GTM_MEMORY_NOACCESS_COUNT]; /* see VMS gtm_env_init_sp.c */ #endif GBLDEF volatile boolean_t in_wcs_recover; /* TRUE if in "wcs_recover", used by "bt_put" and "generic_exit_handler" */ GBLDEF boolean_t in_gvcst_incr; /* set to TRUE by gvcst_incr, set to FALSE by gvcst_put * distinguishes to gvcst_put, if the current db operation is a SET or $INCR */ GBLDEF mval *post_incr_mval; /* mval pointing to the post-$INCR value */ GBLDEF mval increment_delta_mval; /* mval holding the INTEGER increment value, set by gvcst_incr, * used by gvcst_put/gvincr_recompute_upd_array which is invoked by t_end */ GBLDEF boolean_t is_dollar_incr; /* valid only if gvcst_put is in the call-stack (i.e. t_err == ERR_GVPUTFAIL); * is a copy of "in_gvcst_incr" just before it got reset to FALSE */ GBLDEF int indir_cache_mem_size; /* Amount of memory currently in use by indirect cache */ GBLDEF hash_table_objcode cache_table; GBLDEF int cache_hits, cache_fails; /* The alignment feature is disabled due to some issues in stringpool garbage collection. * TODO: When we sort out stringpool issues, change mstr_native_align to TRUE below */ GBLDEF boolean_t mstr_native_align; GBLDEF boolean_t save_mstr_native_align; GBLDEF mvar *mvartab; GBLDEF mvax *mvaxtab,*mvaxtab_end; GBLDEF mlabel *mlabtab; GBLDEF mline mline_root; GBLDEF mline *mline_tail; GBLDEF short int block_level; GBLDEF triple t_orig; GBLDEF int mvmax, mlmax, mlitmax; static char routine_name_buff[SIZEOF(mident_fixed)], module_name_buff[SIZEOF(mident_fixed)]; static char int_module_name_buff[SIZEOF(mident_fixed)]; GBLDEF MIDENT_DEF(routine_name, 0, &routine_name_buff[0]); GBLDEF MIDENT_DEF(module_name, 0, &module_name_buff[0]); GBLDEF MIDENT_DEF(int_module_name, 0, &int_module_name_buff[0]); GBLDEF char rev_time_buf[REV_TIME_BUFF_LEN]; GBLDEF unsigned short source_name_len; GBLDEF short object_name_len; UNIX_ONLY( GBLDEF unsigned char source_file_name[MAX_FBUFF + 1]; GBLDEF unsigned char object_file_name[MAX_FBUFF + 1]; GBLDEF int object_file_des; ) VMS_ONLY( GBLDEF char source_file_name[PATH_MAX]; GBLDEF char object_file_name[256]; GBLDEF struct FAB obj_fab; /* file access block for the object file */ ) GBLDEF int4 curr_addr, code_size; GBLDEF mident_fixed zlink_mname; GBLDEF sm_uc_ptr_t reformat_buffer; GBLDEF int reformat_buffer_len; GBLDEF volatile int reformat_buffer_in_use; /* used only in DEBUG mode */ GBLDEF boolean_t mu_reorg_upgrd_dwngrd_in_prog; /* TRUE if MUPIP REORG UPGRADE/DOWNGRADE is in progress */ GBLDEF boolean_t mu_reorg_nosafejnl; /* TRUE if NOSAFEJNL explicitly specified */ GBLDEF trans_num mu_reorg_upgrd_dwngrd_blktn; /* tn in blkhdr of current block processed by MUPIP REORG {UP,DOWN}GRADE */ GBLDEF inctn_opcode_t inctn_opcode = inctn_invalid_op; GBLDEF inctn_detail_t inctn_detail; /* holds detail to fill in to inctn jnl record */ GBLDEF uint4 region_open_count; /* Number of region "opens" we have executed */ GBLDEF uint4 gtm_blkupgrade_flag = UPGRADE_IF_NEEDED; /* by default upgrade only if necessary */ GBLDEF boolean_t disk_blk_read; GBLDEF boolean_t gtm_dbfilext_syslog_disable; /* by default, log every file extension message */ GBLDEF int4 cws_reorg_remove_index; /* see mu_swap_blk.c for comments on the need for these two */ GBLDEF block_id cws_reorg_remove_array[CWS_REORG_REMOVE_ARRAYSIZE]; GBLDEF uint4 log_interval; #ifdef UNIX GBLDEF uint4 gtm_principal_editing_defaults; /* ext_cap flags if tt */ GBLDEF boolean_t in_repl_inst_edit; /* used by an assert in repl_inst_read/repl_inst_write */ GBLDEF boolean_t in_repl_inst_create; /* used by repl_inst_read/repl_inst_write */ GBLDEF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS]; /* whether a particular replication semaphore is being held * by the current process or not. */ GBLDEF boolean_t detail_specified; /* Set to TRUE if -DETAIL is specified in MUPIP REPLIC -JNLPOOL or -EDITINST */ GBLDEF boolean_t in_mupip_ftok; /* Used by an assert in repl_inst_read */ GBLDEF uint4 section_offset; /* Used by PRINT_OFFSET_PREFIX macro in repl_inst_dump.c */ GBLDEF uint4 mutex_per_process_init_pid; /* pid that invoked "mutex_per_process_init" */ GBLDEF boolean_t gtm_quiet_halt; /* Suppress FORCEDHALT message */ #endif #ifdef UNICODE_SUPPORTED /* Unicode line terminators. In addition to the following * codepoints, the sequence CR LF is considered a single * line terminator. */ LITDEF UChar32 u32_line_term[] = { 0x000A, /* Line Feed */ 0x000D, /* Carraige Return */ 0x0085, /* Next Line - EBCDIC mostly */ 0x000C, /* Form Feed */ UTF_LINE_SEPARATOR, /* Line Separator */ UTF_PARA_SEPARATOR, /* Paragraph Separator */ 0x0000 }; /* Given the first byte in a UTF-8 representation, the following array returns the total number of bytes in the encoding * 00-7F : 1 byte * C2-DF : 2 bytes * E0-EF : 3 bytes * F0-F4 : 4 bytes * All others: 1 byte * For details on the UTF-8 encoding see gtm_utf8.h */ LITDEF unsigned int utf8_bytelen[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00-1F */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20-3F */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40-5F */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60-7F */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80-9F */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A0-BF */ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* C0-DF */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* E0-FF */ }; /* Given the first byte in a UTF-8 representation, the following array returns the number of bytes to follow * 00-7F : 0 byte * C2-DF : 1 byte * E0-EF : 2 bytes * F0-F4 : 3 bytes * All others: -1 bytes * For details on the UTF-8 encoding see gtm_utf8.h */ LITDEF signed int utf8_followlen[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00-1F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20-3F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40-5F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60-7F */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-9F */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-BF */ -1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* C0-DF */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-FF */ }; GBLDEF gtm_wcswidth_fnptr_t gtm_wcswidth_fnptr; /* see comment in gtm_utf8.h about this typedef */ #endif GBLDEF uint4 gtm_max_sockets; /* Maximum sockets per socket device supported by this process */ GBLDEF d_socket_struct *newdsocket; /* Commonly used temp socket area */ GBLDEF boolean_t dse_all_dump; /* TRUE if DSE ALL -DUMP is specified */ GBLDEF int socketus_interruptus; /* How many times socket reads have been interrutped */ GBLDEF int4 pending_errtriplecode; /* if non-zero contains the error code to invoke ins_errtriple with */ GBLDEF uint4 process_id; GBLDEF uint4 image_count; /* not used in UNIX but defined to preserve VMS compatibility */ GBLDEF size_t totalRmalloc; /* Total storage currently (real) malloc'd (includes extent blocks) */ GBLDEF size_t totalAlloc; /* Total allocated (includes allocation overhead but not free space */ GBLDEF size_t totalUsed; /* Sum of user allocated portions (totalAlloc - overhead) */ GBLDEF size_t totalRallocGta; /* Total storage currently (real) mmap alloc'd */ GBLDEF size_t totalAllocGta; /* Total mmap allocated (includes allocation overhead but not free space */ GBLDEF size_t totalUsedGta; /* Sum of "in-use" portions (totalAllocGta - overhead) */ GBLDEF volatile char *outOfMemoryMitigation; /* Cache that we will freed to help cleanup if run out of memory */ GBLDEF uint4 outOfMemoryMitigateSize;/* Size of above cache (in Kbytes) */ GBLDEF int mcavail; GBLDEF mcalloc_hdr *mcavailptr, *mcavailbase; GBLDEF uint4 max_cache_memsize; /* Maximum bytes used for indirect cache object code */ GBLDEF uint4 max_cache_entries; /* Maximum number of cached indirect compilations */ GBLDEF void (*cache_table_relobjs)(void); /* Function pointer to call cache_table_rebuild() */ UNIX_ONLY(GBLDEF ch_ret_type (*ht_rhash_ch)()); /* Function pointer to hashtab_rehash_ch */ UNIX_ONLY(GBLDEF ch_ret_type (*jbxm_dump_ch)()); /* Function pointer to jobexam_dump_ch */ UNIX_ONLY(GBLDEF ch_ret_type (*stpgc_ch)()); /* Function pointer to stp_gcol_ch */ #ifdef VMS GBLDEF boolean_t tp_has_kill_t_cse; /* cse->mode of kill_t_write or kill_t_create got created in this transaction */ #endif GBLDEF cache_rec_ptr_t pin_fail_cr; /* Pointer to the cache-record that we failed while pinning */ GBLDEF cache_rec pin_fail_cr_contents; /* Contents of the cache-record that we failed while pinning */ GBLDEF cache_rec_ptr_t pin_fail_twin_cr; /* Pointer to twin of the cache-record that we failed to pin */ GBLDEF cache_rec pin_fail_twin_cr_contents; /* Contents of twin of the cache-record that we failed to pin */ GBLDEF bt_rec_ptr_t pin_fail_bt; /* Pointer to bt of the cache-record that we failed to pin */ GBLDEF bt_rec pin_fail_bt_contents; /* Contents of bt of the cache-record that we failed to pin */ GBLDEF int4 pin_fail_in_crit; /* Holder of crit at the time we failed to pin */ GBLDEF int4 pin_fail_wc_in_free; /* Number of write cache records in free queue when we failed to pin */ GBLDEF int4 pin_fail_wcs_active_lvl; /* Number of entries in active queue when we failed to pin */ GBLDEF int4 pin_fail_ref_cnt; /* Reference count when we failed to pin */ GBLDEF int4 pin_fail_in_wtstart; /* Count of processes in wcs_wtstart when we failed to pin */ GBLDEF int4 pin_fail_phase2_commit_pidcnt; /* Number of processes in phase2 commit when we failed to pin */ GBLDEF zwr_hash_table *zwrhtab; /* How we track aliases during zwrites */ GBLDEF uint4 zwrtacindx; /* When creating $ZWRTACxxx vars for ZWRite, this holds xxx */ GBLDEF uint4 tstartcycle; /* lv_val cycle for tstart operations */ GBLDEF uint4 lvtaskcycle; /* lv_val cycle for misc lv_val related tasks */ GBLDEF int4 SPGC_since_LVGC; /* stringpool GCs since the last lv_val GC */ GBLDEF int4 LVGC_interval = MIN_SPGC_PER_LVGC; /* dead data GC is done every LVGC_interval stringpool GCs */ GBLDEF lv_xnew_var *xnewvar_anchor; /* Anchor for unused lv_xnew_var blocks */ GBLDEF lv_xnew_ref *xnewref_anchor; /* Anchor for unused lv_xnew_ref blocks */ GBLDEF mval *alias_retarg; /* Points to an alias return arg created by a "QUIT *" recorded here so * symtab-unwind logic can find it and modify it if necessary if a * symtab popped during the return and the retarg points to an lv_val * that is going to be destroyed. */ #ifdef DEBUG_ALIAS GBLDEF boolean_t lvmon_enabled; /* Enable lv_val monitoring */ #endif GBLDEF block_id gtm_tp_allocation_clue; /* block# hint to start allocation for created blocks in TP */ #ifdef UNIX GBLDEF int4 gtm_zlib_cmp_level; /* zlib compression level specified at process startup */ GBLDEF int4 repl_zlib_cmp_level; /* zlib compression level currently in use in replication pipe. * This is a source-server specific variable and is non-zero only * if compression is enabled and works in the receiver server as well. */ GBLDEF zlib_cmp_func_t zlib_compress_fnptr; GBLDEF zlib_uncmp_func_t zlib_uncompress_fnptr; #endif GBLDEF mlk_stats_t mlk_stats; /* Process-private M-lock statistics */ #ifdef UNIX /* Initialized blockalrm, block_ttinout and block_sigsent can be used by all threads */ GBLDEF boolean_t blocksig_initialized; /* set to TRUE when blockalrm and block_sigsent are initialized */ GBLDEF sigset_t blockalrm; UNIX_ONLY(GBLDEF sigset_t block_ttinout;) GBLDEF sigset_t block_sigsent; /* block all signals that can be sent externally (SIGINT, SIGQUIT, SIGTERM, SIGTSTP, SIGCONT) */ GBLDEF char *gtm_core_file; GBLDEF char *gtm_core_putenv; #endif #ifdef __MVS__ GBLDEF char *gtm_utf8_locale_object; GBLDEF boolean_t gtm_tag_utf8_as_ascii = TRUE; #endif #ifdef GTM_CRYPT LITDEF char gtmcrypt_repeat_msg[] = "Please look at prior messages related to encryption for more details"; GBLDEF boolean_t gtmcrypt_initialized; /* Set to TRUE if gtmcrypt_init() completes successfully */ GBLDEF char dl_err[MAX_ERRSTR_LEN]; GBLDEF gtmcrypt_init_t gtmcrypt_init_fnptr; GBLDEF gtmcrypt_close_t gtmcrypt_close_fnptr; GBLDEF gtmcrypt_hash_gen_t gtmcrypt_hash_gen_fnptr; GBLDEF gtmcrypt_encrypt_t gtmcrypt_encrypt_fnptr; GBLDEF gtmcrypt_decrypt_t gtmcrypt_decrypt_fnptr; GBLDEF gtmcrypt_getkey_by_hash_t gtmcrypt_getkey_by_hash_fnptr; GBLDEF gtmcrypt_getkey_by_name_t gtmcrypt_getkey_by_name_fnptr; GBLDEF gtmcrypt_strerror_t gtmcrypt_strerror_fnptr; #endif /* GTM_CRYPT */ #ifdef DEBUG /* Following definitions are related to white_box testing */ GBLDEF boolean_t gtm_white_box_test_case_enabled; GBLDEF int gtm_white_box_test_case_number; GBLDEF int gtm_white_box_test_case_count; GBLDEF int gtm_wbox_input_test_case_count; /* VMS allows maximum 31 characters for external identifer */ GBLDEF boolean_t stringpool_unusable; /* Set to TRUE by any function that does not expect any of its function * callgraph to use/expand the stringpool. */ GBLDEF boolean_t stringpool_unexpandable; /* Set to TRUE by any function for a small period when it has ensured * enough space in the stringpool so it does not expect any more garbage * collections or expansions. */ GBLDEF boolean_t donot_INVOKE_MUMTSTART; /* Set to TRUE whenever an implicit TSTART is done in gvcst_put/kill as * part of an explicit + trigger update. In this situation, we dont expect * MUM_TSTART macro to be invoked at all (see skip_INVOKE_RESTART below * for description on why this is needed). So we keep this debug-only * flag turned on throughout the gvcst_put/kill. An assert in * mdb_condition_handler (invoked by INVOKE_RESTART macro when it does * an rts_error) checks it never gets invoked while this is set. */ #endif GBLDEF boolean_t block_is_free; /* Set to TRUE if the caller wants to let t_qread know that the block it is * attempting to read is actually a FREE block */ GBLDEF int4 gv_keysize; GBLDEF gd_addr *gd_header; GBLDEF gd_binding *gd_map; GBLDEF gd_binding *gd_map_top; #ifdef GTM_TRIGGER GBLDEF int4 gtm_trigger_depth; /* 0 if no trigger, 1 if inside trigger; 2 if inside nested trigger etc. */ GBLDEF int4 tstart_trigger_depth; /* gtm_trigger_depth at the time of the outermost "op_tstart" * (i.e. explicit update). This should be used only if dollar_tlevel * is non-zero as it is not otherwise maintained. */ GBLDEF uint4 trigger_name_cntr; /* Counter from which trigger names are constructed */ GBLDEF boolean_t *ztvalue_changed_ptr; /* -> boolean in current gtm_trigger_parms signaling if ztvalue has been updated */ GBLDEF boolean_t ztwormhole_used; /* TRUE if $ztwormhole was used by trigger code */ GBLDEF mstr *dollar_ztname; GBLDEF mval *dollar_ztdata, *dollar_ztoldval, *dollar_ztriggerop, *dollar_ztupdate, *dollar_ztvalue, dollar_ztwormhole = DEFINE_MVAL_STRING(MV_STR, 0, 0, 0, NULL, 0, 0), dollar_ztslate = DEFINE_MVAL_STRING(MV_STR, 0, 0, 0, NULL, 0, 0), gtm_trigger_etrap; /* Holds $ETRAP value for inside trigger */ GBLDEF int tprestart_state; /* When triggers restart, multiple states possible. See tp_restart.h */ GBLDEF boolean_t skip_INVOKE_RESTART; /* set to TRUE if caller of op_tcommit/t_retry does not want it to * use the INVOKE_RESTART macro (which uses an rts_error to trigger * the restart) instead return code. The reason we dont want to do * rts_error is that this is an implicit tstart situation where we * did not do opp_tstart.s so we dont want control to be transferred * using the MUM_TSTART macro by mdb_condition_handler (which assumes * opp_tstart.s invocation). */ GBLDEF boolean_t goframes_unwound_trigger; /* goframes() unwound a trigger base frame during its unwinds */ GBLDEF symval *trigr_symval_list; /* List of availalable symvals for use in (nested) triggers */ GBLDEF boolean_t dollar_ztrigger_invoked; /* $ZTRIGGER() was invoked on at least one region in this transaction */ # ifdef DEBUG GBLDEF gv_trigger_t *gtm_trigdsc_last; /* For debugging purposes - parms gtm_trigger called with */ GBLDEF gtm_trigger_parms *gtm_trigprm_last; GBLDEF ch_ret_type (*ch_at_trigger_init)(); /* Condition handler in effect when gtm_trigger called */ # endif GBLDEF boolean_t explicit_update_repl_state; /* Initialized just before an explicit update invokes any triggers. * Set to 1 if triggering update is to a replicated database. * Set to 0 if triggering update is to a non-replicated database. * Value stays untouched across nested trigger invocations. */ #endif GBLDEF boolean_t skip_dbtriggers; /* Set to FALSE by default (i.e. triggers are invoked). Set to TRUE * unconditionally by MUPIP LOAD as it always skips triggers. Also set * to TRUE by journal recovery/update-process only when they encounter * updates done by MUPIP LOAD so they too skip trigger processing. In the * case of update process, this keeps primary/secondary in sync. In the * case of journal recovery, this keeps the db and jnl in sync. */ GBLDEF boolean_t expansion_failed; /* used by string pool when trying to expand */ GBLDEF boolean_t retry_if_expansion_fails; /* used by string pool when trying to expand */ GBLDEF boolean_t mupip_exit_status_displayed; /* TRUE if mupip_exit has already displayed a message for non-zero status. * Used by mur_close_files to ensure some message gets printed in case * of abnormal exit status (in some cases mupip_exit might not have been * invoked but we will still go through mur_close_files e.g. if exit is * done directly without invoking mupip_exit). */ GBLDEF boolean_t implicit_trollback; /* Set to TRUE by OP_TROLLBACK macro before calling op_trollback. Set * to FALSE by op_trollback. Used to indicate op_trollback as to * whether it is being called from generated code (opp_trollback.s) * or from C runtime code. */ #ifdef DEBUG GBLDEF boolean_t ok_to_UNWIND_in_exit_handling; /* see gtm_exit_handler.c for comments */ GBLDEF boolean_t skip_block_chain_tail_check; GBLDEF boolean_t in_mu_rndwn_file; /* TRUE if we are in mu_rndwn_file (holding standalone access) */ #endif GBLDEF char gvcst_search_clue; #ifdef UNIX /* The following are replication related global variables. Ideally if we had a repl_gbls_t structure (like jnl_gbls_t) * this would be a member in that. But since we dont have one and since we need to initialize this specificially to a * non-zero value (whereas usually everything else accepts a 0 default value), this is better kept as a separate global * variable instead of inside a global variable structure. */ GBLDEF int4 strm_index = INVALID_SUPPL_STRM; /* # of the supplementary stream if one exists. * If this process is an update process running on a supplementary * replication instance and the journal pool allows updates (that * is the instance was started as a root primary), the value of * this variable will be anywhere from 1 to 15 once the receiver * establishes connection with a non-supplementary source server. * If this process is a mumps process running on a supplementary * replication instance and the journal pool allows updates (that * is the instance was started as a root primary), the value of * this variable will be 0 to indicate this is the local stream. * Otherwise, this variable is set to -1 (INVALID_SUPPL_STRM) * This variable is used by t_end/tp_tend to determine if strm_seqno * field in the journal record needs to be filled in or not. * It is filled in only if this variable is 0 to 15. */ GBLDEF repl_conn_info_t *this_side, *remote_side; /* Replication related global variables END */ GBLDEF seq_num gtmsource_save_read_jnl_seqno; GBLDEF gtmsource_state_t gtmsource_state = GTMSOURCE_DUMMY_STATE; #endif GBLDEF boolean_t gv_play_duplicate_kills; /* A TRUE value implies KILLs of non-existent nodes will continue to * write jnl records and increment the db curr_tn even though they dont * touch any GDS blocks in the db (i.e. treat it as a duplicate kill). * Set to TRUE for the update process & journal recovery currently. * Set to FALSE otherwise. */ GBLDEF boolean_t donot_fflush_NULL; /* Set to TRUE whenever we dont want gtm_putmsg to fflush(NULL). BYPASSOK * As of Jan 2012, mu_rndwn_all is the only user of this functionality. */ #ifdef UNIX GBLDEF boolean_t jnlpool_init_needed; /* TRUE if jnlpool_init should be done at database init time (eg., for * anticipatory freeze supported configurations). The variable is set * explicitly by interested commands (eg., MUPIP REORG). */ GBLDEF boolean_t span_nodes_disallowed; /* Indicates whether spanning nodes are not allowed. For example, * they are not allowed for GT.CM OMI and GNP. */ GBLDEF boolean_t argumentless_rundown; GBLDEF is_anticipatory_freeze_needed_t is_anticipatory_freeze_needed_fnptr; GBLDEF set_anticipatory_freeze_t set_anticipatory_freeze_fnptr; GBLDEF boolean_t is_jnlpool_creator; GBLDEF char gtm_dist[GTM_PATH_MAX]; /* Value of $gtm_dist env variable */ #endif GBLDEF boolean_t in_jnl_file_autoswitch; /* Set to TRUE for a short window inside jnl_file_extend when we are about to * autoswitch; used by jnl_write. */ #ifdef GTM_PTHREAD GBLDEF pthread_t gtm_main_thread_id; /* ID of the main GT.M thread. */ GBLDEF boolean_t gtm_main_thread_id_set; /* Indicates whether the thread ID is set. */ GBLDEF boolean_t gtm_jvm_process; /* Indicates whether we are running with JVM or stand-alone. */ #endif GBLDEF size_t gtm_max_storalloc; /* Maximum that GTM allows to be allocated - used for testing */ #ifdef VMS GBLDEF sgmnt_addrs *vms_mutex_check_csa; /* On VMS, mutex_deadlock_check() is directly called from mutex.mar. In * order to avoid passing csa parameter from the VMS assembly, we set this * global from mutex_lock* callers. */ #endif GBLDEF boolean_t ipv4_only; /* If TRUE, only use AF_INET. * Reflects the value of the gtm_ipv4_only environment variable, so is process wide. */ fis-gtm-V6.0-003/sr_port/gbldefs_usr_share.c0000644000032200000250000000254412201176156017665 0ustar librarygtc/**************************************************************** * * * Copyright 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* General repository for global variable definitions used both in DDPGVUSR and GTMSHR. gvusr_init should setup these globals */ /* for use in DDPGVUSR.*/ /***************** DO NOT MOVE THESE GLOBALS INTO GBLDEFS.C; IT WILL CAUSE DDPGVUSR.EXE BLOAT *****************/ #include "mdef.h" #include "gdsroot.h" #include "gdskill.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" GBLDEF gd_region *gv_cur_region; GBLDEF gv_key *gv_altkey, *gv_currkey; GBLDEF bool caller_id_flag = TRUE; #ifdef INT8_SUPPORTED GBLDEF const seq_num seq_num_zero = 0; GBLDEF const seq_num seq_num_one = 1; GBLDEF const seq_num seq_num_minus_one = (seq_num)-1; #else GBLDEF const seq_num seq_num_zero = {0, 0}; GBLDEF const seq_num seq_num_minus_one = {(uint4)-1, (uint4)-1}; # ifdef BIGENDIAN GBLDEF const seq_num seq_num_one = {0, 1}; # else GBLDEF const seq_num seq_num_one = {1, 0}; # endif #endif fis-gtm-V6.0-003/sr_port/gc.mpt0000644000032200000250000000336612201176156015156 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1989, 2006 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %GC ;GT.M %GC utility - global copy ; n %GI,%GO,%SC,$et s %ZL=$zl,$et="zg "_$ZL_":ERR^%GC" u 0:(ctrap=$c(3):exc="zg "_$ZL_":RESTART^%GC") w !,"Global copy",! RESTART r !,"Show copied nodes ? ",%SC s %SC=($tr(%SC,"yes","YES")=$e("YES",1,$l(%SC))) f r !,"From global ^",%GI q:%GI="" d COPY u 0:(ctrap="":exc="") q COPY n c,ix i $e(%GI)="?" s ix=%GI d help q i $e(%GI)'="^" s %GI="^"_%GI i '$d(@%GI) w !,"Global "_%GI_" does not exist." q f r !,"To global ^",%GO q:$e(%GO)'="?" s ix=%GO d help i %GO="" q i $e(%GO)'="^" s %GO="^"_%GO i $d(@%GO) w !,"Global "_%GO_" already exists." q s c=0 i '$d(%SC) n %SC s %SC=0 i $d(@%GI)'[0 s @%GO=@%GI s c=c+1 i %SC w !,%GO,"=",@%GI f s %GI=$q(@%GI) q:%GI="" s c=c+1,ix="("_$p(%GI,"(",2,999),@(%GO_ix)=@%GI i %SC w !,%GO_ix,"=",@%GI w !,"Total ",c," nodes copied.",! q help i $l(ix)=2,"Dd"[$e(ix,2) d ^%GD u 0:flush q W !!,"This routine copies a node and all its descendents" w !,"from one global variable to another" w !,"""From global"" requests the source for the copy," w !,"""To global"" requests the destination" w !,"Use standard MUMPS gvn syntax to specify the node names" w !,"?D invokes %GD to get a global directory" w !," drops you back to the prior prompt or out of %GC" w ! q ERR w !,$p($zs,",",2,99),! u 0:(ctrap="":exc="") s $ec="" q fis-gtm-V6.0-003/sr_port/gce.mpt0000644000032200000250000000461712201176156015323 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1989, 2003 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %GCE ;GT.M %GCE utility - global change every occurrence ; n c,g,gn,m,n,ns,os,s,sc,sn,%ZD,%ZG,x i '$d(%zdebug) n $et s $et="zg "_$zl_":ERR^%GCE" u $p:(ctrap=$c(3):exc="zg "_$zl_":LOOP^%GCE") w !,"Global Change Every occurrence",! d base q base f d main q:'%ZG i $d(%ZD),%ZD'=$p c %ZD u $p:(ctrap="":exc="") q main k %ZG d CALL^%GSEL i '%ZG q s gn="" r !,"Old string: ",os i os="" w !,"No string to find - no search done.",! s %ZG=0 q i os?.E1C.E w !,"The Old string contains control characters" r !,"New string: ",ns i ns?.E1C.E w !,"The New string contains control characters" f r !,"Show changed nodes ? ",x,! q:$e(x)'="?" d help i $l(x) s sc=$e("NO",1,$l(x))'=$e($tr(x,"no","NO"),1,2) e s sc=1 i sc f d q:$l(%ZD) . r !,"Output device: : ",%ZD,! . i '$l(%ZD) s %ZD=$p q . i %ZD="^" q . i %ZD="?" d q . . w !!,"Select the device you want for output" . . w !,"If you wish to exit enter a carat (^)",! . . s %ZD="" . i $zparse(%ZD)="" w " no such device" s %ZD="" q . o %ZD:(newversion:block=2048:record=2044:exception="g noopen"):0 . i '$t w !,%ZD," is not available" s %ZD="" q . q noopen . w !,$p($ZS,",",2,999),! c %ZD s %ZD="" i sc q:%ZD="^" e s %ZD=$p i %ZD'=$p d . u %ZD w $zd($h,"DD-MON-YEAR 24:60:SS"),!,"Global Change Every occurrence of:",!,">",os,"<",!,"To:",!,">",ns,"<",! u $p f s gn=$o(%ZG(gn)) q:gn="" d search q search w:$x>70 ! w gn,?$x\10+1*10 s g=gn,(m,n)=0 u %ZD i ($d(@g)#10=1) s n=1 d:@g[os change f s g=$q(@g) q:g="" s n=n+1 d:@g[os change i m w !!,m," changes made in total ",n," nodes.",! e w !!,"No changes made in total ",n," nodes.",! u $p q change w:sc !,g,!,"Was : ",@g s s=@g,sn="",c=$l(s,os) f i=1:1:c-1 s sn=sn_$p(s,os,i)_ns s @g=sn_$p(s,os,c),m=m+i w:sc !,"Now : ",@g,! q help w !,"Answer No to this prompt if you do not wish a trail of the changes" q q ERR i $d(%ZD),%ZD'=$p c %ZD u $p w !,$p($zs,",",2,99),! u $p:(ctrap="":exc="") s $ec="" q LOOP i $d(%ZD),%ZD'=$p c %ZD d base q fis-gtm-V6.0-003/sr_port/gd.mpt0000644000032200000250000000140412201176156015146 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1987,2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %GD ;GT.M %GD utility - global directory ; n %ZG,%ZL i '$d(%zdebug) n $et s $et="zg "_$zl_":ERR^%GD" u $p:(ctrap=$c(3):exc="k %ZG zg "_$zl_":LOOP^%GD") w !,"Global Directory",! d GD^%GSEL,EXIT q ERR u $p w !,$p($zs,",",2,99),! s $ec="" ; Warning: Fall-through! EXIT u $p:(ctrap="":exc="") q LOOP d GD^%GSEL,EXIT q fis-gtm-V6.0-003/sr_port/gde.hlp0000644000032200000250000022256712201176156015315 0ustar librarygtc1 Overview Overview The GT.M Global Directory Editor (GDE) is a utility that enables you to create, examine, and modify a global directory. GDE is a program written in M and you can invoke it from the shell with $gtm_dist/mumps -run ^GDE, with the gtm alias gtm -run GDE, or from inside the direct mode with Do ^GDE. **Note** The input to GDE can be a text file. In a production environment, FIS recommends using text files to define database configurations, and putting these text files under version control. A global directory stores database attributes and mapping rules. The mapping rules are like a sieve for globals that determines which database files hold which global names. The database attributes serve as a blueprint that MUPIP CREATE uses to create new database file(s). Once a database file is created, GT.M continues to use the global directory as a sieve. However, once MUPIP CREATE applies the database attributes (blueprint) to create a database file, GT.M does not use the blueprint until the next MUPIP CREATE. Therefore, if you use MUPIP SET (or DSE) to change the attributes of a database file, always perform an equivalent change to any global directory used for a subsequent MUPIP CREATE. 2 Identifying_the_Current_Global_Directory Identifying the Current Global Directory GT.M identifies the current Global Directory by referring to the environment variable gtmgbldir. GDE, MUPIP, LKE, DSE, and the GT.M run-time system use this environment variable. The run-time system normally uses this environment variable, but may also access a Global Directory by setting $ZGBLDIR or by using the extended global reference || or {} syntax. If you maintain multiple Global Directories, define gtmgbldir to point to the currently active Global Directory. You may want to define gtmgbldir in your login file. Note that this definition is a pathname. If it does not start with a "/", then it is a relative pathname and GT.M searches for it starting in the current working directory. To change the current Global Directory assignment, specify a new definition for gtmgbldir. Example: $ gtmgbldir=prod.gld $ export gtmgbldir 2 Creating_a_Default_Global_Directory Creating a Default Global Directory When you invoke GDE and no Global Directory exists for gtmgbldir, GDE produces a default Global Directory that contains a minimal set of required components and values for database characteristics. It can be used for purposes such as development and testing work. A default Global Directory also serves as a starting point or template for building custom global directories. To retain this default Global Directory, exit GDE without making any changes. Example: $ gtmgbldir=./mumps.gld $ export gtmgbldir $ gtm GTM>d ^GDE %GDE-I-GDUSEDEFS, Using defaults for Global Directory /usr/accntg/jones/mumps.gld GDE> EXIT %GDE-I-VERIFY, Verification OK %GDE-I-GDCREATE, Creating Global Directory file /usr/accntg/jones/mumps.gld 2 Mapping_Global_Variables_in_a_Global_Directory Mapping Global Variables in a Global Directory Mapping is the process of connecting a global variable name to a database file. A complete mapping has the following four components: o NAME o REGION o SEGMENT o FILE These components may be defined in any order, but the final result must be a complete logical path from name to file: NAME(s) ---> REGION ---> SEGMENT ---> FILE The default Global Directory contains one complete mapping that comprises these entries for name, region, segment, and file. * ---> DEFAULT ---> DEFAULT ---> mumps.dat (NAME) (REGION) (SEGMENT) (FILE) The * wildcard identifies all possible global names. Subsequent edits create entries for individual global names or name prefixes. Regions and segments store information used to control the creation of the file. The characteristics stored with the region and segment are passed to MUPIP only when creating the database file using the CREATE command, so subsequent changes to these characteristics in the Global Directory have no effect on an existing database. When you create a new mapping, GDE ensures that it has all these components by refusing to complete the EXIT command until all components of the mapping exist. Informational messages inform you of any missing or extra components. 2 Examining_the_Default_Global_Directory Examining the Default Global Directory The default Global Directory looks like this: *** TEMPLATES *** Std Inst Def Rec Key Null Null Freeze Qdb Region Coll Size Size Subs Coll Jnl on Error Rndwn ---------------------------------------------------------------------------------------------------- 0 4080 255 NEVER Y Y DISABLED DISABLED Jnl File (def ext: .mjl) Before Buff Alloc Exten AutoSwitch -------------------------------------------------------------------------------------- Y 2308 2048 2048 8386560 Segment Active Acc Typ Block Alloc Exten Options ------------------------------------------------------------------------------ * BG DYN 4096 5000 10000 GLOB =1000 LOCK = 40 RES = 0 ENCR = OFF MM DYN 4096 5000 10000 DEFER LOCK = 40 *** NAMES *** Global Region ------------------------------------------------------------------------------ * DEFAULT *** REGIONS *** Std Inst Dynamic Def Rec Key Null Null Freeze Qdb Region Segment Coll Size Size Subs Coll Jnl on Error Rndwn ----------------------------------------------------------------------------------------------------------------- DEFAULT DEFAULT 0 4080 255 NEVER Y Y DISABLED DISABLED *** JOURNALING INFORMATION *** Region Jnl File (def ext: .mjl) Before Buff Alloc Exten AutoSwitch -------------------------------------------------------------------------------------------------------- DEFAULT $gtmdir/$gtmver/g/gtm.mjl Y 2308 2048 2048 8386560 *** SEGMENTS *** Segment File (def ext: .dat)Acc Typ Block Alloc Exten Options ------------------------------------------------------------------------------------------- DEFAULT $gtmdir/$gtmver/g/gtm.dat BG DYN 4096 5000 10000 GLOB=1000 LOCK= 40 RES = 0 ENCR=OFF *** MAP *** - - - - - - - - - - Names - - - - - - - - - - From Up to Region / Segment / File(def ext: .dat) -------------------------------------------------------------------------------------------------------- % ... REG = DEFAULT SEG = DEFAULT FILE = $gtmdir/$gtmver/g/gtm.dat LOCAL LOCKS REG = DEFAULT SEG = DEFAULT FILE = $gtmdir/$gtmver/g/gtm.dat GDE> There are five primary sections in a Global Directory: o TEMPLATES o NAMES o REGIONS o SEGMENTS o MAP The function of each section in the Global Directory is described as follows: TEMPLATES This section of the Global Directory provides a default value for every database or file parameter passed to GT.M as part of a region or segment definition. GDE uses templates to complete a region or segment definition where one of these necessary values is not explicitly defined. GDE provides initial default values when creating a new Global Directory. You can then change any of the values using the appropriate -REGION or -SEGMENT qualifiers with the TEMPLATE command. NAMES An M program sees a monolithic global variable name space. The NAMES section of the Global Directory partitions the name space so that different globals reside in different files. While each M global can reside in only one file, each file can store many M globals. REGIONS The REGIONS section lists all of the regions in the Global Directory. Each region defines common properties for all the M global variables; therefore, multiple sets of names from the NAMES section map onto a single region. You assign these values by specifying the appropriate qualifier when you create or modify individual regions. If you do not specify a value for a particular parameter, GDE assigns the default value from the TEMPLATES section. SEGMENTS This section of the Global Directory lists currently defined segments. While regions specify properties of global variables, segments specify the properties of files. There is a one-to-one mapping between regions and segments. You assign these values by specifying the appropriate qualifier when you create or modify individual segments. If you do not specify a value for a particular parameter, GDE assigns the default value from the TEMPLATES section. MAP This section of the Global Directory lists the current mapping of names to region to segment to file. In the default Global Directory, there are two lines in this section: one specifies the destination for all globals, the other one is for local locks. If you add any new mapping component definitions (that is, any new names, regions, or segments), this section displays the current status of that mapping. Any components of the mapping not currently defined display "NONE". Because GDE requires all elements of a mapping to be defined, you will not be able to EXIT (and save) your Global Directory until you complete all mappings. 2 Global_Directory_Abbreviations Global Directory Abbreviations GDE uses the following abbreviations to display the output of a global directory. The following list show global directory abbreviations with the associated qualifiers. For a description of the function of individual qualifiers, see "GDE Command Summary". Abbreviation Full Form Acc ACCESS_METHOD Alloc ALLOCATION AutoSwitch AUTOSWITCHLIMIT Block BLOCK_SIZE Buff BUFFER_SIZE Def Coll COLLATION_DEFAULT Exten EXTENSION_COUNT File FILE_NAME GLOB GLOBAL_BUFFER_COUNT Inst Freeze On Error INST_FREEZE_ON_ERROR JNL JOURNAL KeySize KEY_SIZE LOCK LOCK_SPACE Null Subs NULL_SUBSCRIPTS Qdb Rndwn QDBRUNDOWN Std Null Coll STDNULLCOLL Rec Size RECORD_SIZE RES RESERVED_BYTES Region REGION Typ DYNAMIC_SEGMENT 2 Customizing_a_Global_Directory Customizing a Global Directory Once you have installed GT.M and verified its operation, create a Global Directory based on your needs. To create this customized Global Directory, use the appropriate GDE commands and qualifiers to build the desired Global Directory. The GDE commands are described later in this chapter. You can also create a text file of GDE commands with a standard text editor and process this file with GDE. In a production environment, this gives better configuration control than interactive usage with GDE. 3 Adding_a_Journaling_Information_Section Adding a Journaling Information Section If you select the -JOURNAL option when you ADD or CHANGE a region in a Global Directory, the following section is added to your Global Directory and displays when you invoke SHOW. The columns provided display the values you selected with the journal options, or defaults provided by FIS for any options not explicitly defined. *** JOURNALING INFORMATION *** Region Jnl File (def ext: .mjl) Before Buff Alloc Exten AutoSwitch ------------------------------------------------------------------------------------------ DEFAULT $gtmdir/$gtmver/g/gtm.mjl Y 2308 2048 2048 8386560 1 Using_GDE Using GDE The default installation procedure places the GDE utility into a directory assigned to the environment variable gtm_dist. To invoke GDE: from within GTM, use the command: GTM>do ^GDE from the shell, enter: $ mumps -r GDE GDE displays informational messages like the following, and then the GDE> prompt: %GDE-I-LOADGD, loading Global Directory file /prod/mumps.gld %GDE-I-VERIFY, Verification OK GDE> If this does not work, contact your system manager to investigate setup and file access issues. To leave GDE: 1. Use the GDE EXIT command to save all changes and return to the shell. GDE> EXIT 2. Use the GDE QUIT command to discard all changes and return to the shell. This will not save any changes. GDE> QUIT 2 Guidelines_for_Mapping Guidelines for Mapping This section lists the parameters that apply to defining each component of a mapping. NAME The name is the portion of the global variable name without subscripts. More than one name can map to a single region, but a single name can only map to one region. A name: o Maps to only one region in the Global Directory. o Is case sensitive. o Must begin with an alphabetic character or a percent sign (%). o Can be one to 31 alphanumeric characters. o Can be a discrete "global" name, for example, aaa corresponds to the global variable ^aaa. o Can be a partial name ending with a wild card ("*"), for example, abc* represents all globals beginning with the letters ^abc. REGION A region is a logical structure that holds information about a portion of a database, such as key-size and record-size. A key is the internal representation of a global variable name. In this chapter the terms global variable name and key are used interchangeably. A record refers to a key and its data. A Global Directory must have at least one region. A region only maps to a single segment. More than one name may map to a region. A region name: o Can include alphanumerics, dollar signs ($), and underscores ( _ ). o Can have from 1 to 16 characters. GDE automatically converts region names to uppercase, and uses DEFAULT for the default region name. SEGMENT A segment defines file-related database storage characteristics. A segment must map to a single file. A segment can be mapped by only one region. GT.M uses a segment to define a physical file and access method for the database stored in that file. A segment-name: o Can include alphanumerics, dollar signs ($), and underscores ( _ ) o Can have from one to 16 characters GDE automatically converts segment names to uppercase. GDE uses DEFAULT for the default segment name. FILE Files are the structures provided by UNIX for the storage and retrieval of information. Files used by GT.M must be random-access files resident on disk. By default, GDE uses the file-name mumps.dat for the DEFAULT segment. GDE adds the .dat to the file name when you do not specify an extension. Generally, avoid non-graphic and punctuation with potential semantic significance to the file system in file names as they tend to produce operational difficulties. 3 Example_of_a_Basic_Mapping Example of a Basic Mapping To complete this procedure, you must have already opened a Global Directory. o ADD a new global variable name. GDE> add -name cus -region=cusreg This maps the global name cus to the region cusreg. o ADD region cusreg, if it does not exist. GDE> add -region cusreg -d=cusseg This creates the region cusreg and connects it to the segment cusseg. -d[ynamic] is a required qualifier that takes the associated segment-name as a value. o ADD segment cusreg, if it does not exist, and link it to a file. GDE> add -segment cusseg -file=cus This creates the segment cusseg and connects it to the file cus.dat. To review the information you have added to the Global Directory, enter the command SHOW. To perform a base consistency check in the configuration, enter the command VERIFY. To exit the Global Directory and save your changes, enter the command EXIT. At this point, GDE performs an automatic verification. If successfully confirmed, the mappings and database specifications become part of the Global Directory, available for access by processes, utilities, and the run-time system. Only MUPIP CREATE uses the database specifications; run-time processes and other utility functions use only the map and ignore the other information in a global directory. 1 Commands Commands This section describes the GDE commands. GDE allows abbreviations of commands. The section describing each command provides the minimum abbreviation for that command and a description of any qualifiers that are not object-related. The section discussing the object-type describes all the associated object-related qualifiers. Command Syntax: The general format for GDE commands is: command [-object-type] [object-name] [-qualifier] where: -object-type Indicates whether the command operates on a -N[AME] space, -R[EGION], or -S[EGMENT]. object-name Specifies the name of the N[AME] space, R[EGION], or S[EGMENT]. Objects of different types may have the same name. Name spaces may include the wildcard operator (*) as a suffix. -qualifier Indicates an object qualifier. The format description for each individual command specifies required qualifiers for that command. The @, EXIT, HELP, LOG, QUIT, SETGD, and SPAWN commands do not use this general format. For the applicable format, refer to the section explaining each of these commands. Comments on the command line may be delimited by an exclamation mark (!). **Caution** An exclamation mark not enclosed in quotation marks ("") causes GDE to ignore the rest of that input line. 2 at-sign at-sign The @ command executes a GDE command file. Use the @ command to execute GDE commands stored in a text file. The format of the @ command is: @file-name The file-name specifies the command file to execute. Use the file-name alone for a file in the current working directory, or specify the relative path, or the full path. GDE executes each line of the command file as if it were entered at the terminal. Example: GDE> @standard This command executes the GDE commands in the file to standard in the current working directory. standard should contain GDE commands; comments should start with an exclamation mark (!). 2 Add Add The ADD command inserts a new name, region, or segment into the Global Directory. The format of the ADD command is one of the f ollowing: A[DD]-N[AME] name-space -R[EGION]=region-name A[DD]-R[EGION] region-name -D[YNAMIC]=segment-name [-REGION-qualifier...] A[DD]-S[EGMENT] segment-name [-SEGMENT-qualifier...] -F[ILE_NAME]=file-name The ADD command requires specification of an object-type and object-name. GDE supplies default values from the templates for qualifiers not explicitly supplied in the command. Name spaces and file-names are case-sensitive; other objects are not case-sensitive. Example: GDE> add -segment temp -file_name=scratch This command creates a segment-name TEMP and maps it to the file scratch.dat in the current working directory. However, if you specify scratch is as the file-name, in other words specify it in the form of an environment variable, GT.M finds the file using the translation of that environment variable. 2 Change Change The CHANGE command alters the name-to-region or region-to-segment mapping and /or the environment for a region or segment. The format of the CHANGE command is: C[HANGE]-N[AME] name-space -R[EGION]=new-region C[HANGE]-R[EGION] region-name [-REGION-qualifier...] C[HANGE]-S[EGMENT] segment-name [-SEGMENT-qualifier...] The CHANGE command requires specification of an object-type and object-name. Once you exit GDE, mapping changes take effect for any subsequent image activation (for example, the next RUN or the mumps -direct command). Changes to database parameters only take effect for new database files created with subsequent MUPIP CREATE commands that use the modified Global Directory. Use the MUPIP SET command (or in some cases DSE) to change characteristics of existing database files. Example: GDE> change -region master -dynamic=temp -key=100 This command changes the region master to use the segment temp and establishes a maximum KEY_SIZE of 100 characters for the next creation of a file for this region. The segment change takes effect the first time the system uses the Global Directory after the GDE session EXITs, while the KEY_SIZE change takes effect after the next MUPIP CREATE that creates a new database file for segment temp. 2 Delete Delete The DELETE command removes a name, region, or segment from the Global Directory. The DELETE command does not delete any actual data. However, GT.M does not access database files that do not have mapped global variables except through extended references using an alternative global directory that does not map to them. Note that GT.M replication does not support global updates made with extended references, unless they actually map to the same file as they would with the master global directory of the instance. The format of the DELETE command is: D[ELETE]-N[AME] name-space D[ELETE]-R[EGION] region-name D[ELETE]-S[EGMENT] segment-name The DELETE command requires specification of an object-type and object-name. Deleting a name removes the name-to-region mapping. Deleting a region unmaps all names mapped to the region. Deleting a segment unmaps the region mapped to the segment. You may map the deleted names to another region or the deleted region to another segment using the CHANGE command. The default name-space (*) cannot be deleted. Example: GDE> del -name T* This command deletes the explicit mapping of all global names starting with the letter "T." This command does not delete any global variables. However, it may make preexisting globals starting with the letter "T" invisible, at least while using this global directory, because the T* global names map to the default namespace going forward. 2 Exit Exit The EXIT command writes all changes made in the current GDE editing session to the Global Directory and terminates the current editing session. The format of the EXIT command is: E[XIT] GDE performs a full verification test (VERIFY) on the data. If the verification succeeds, GDE writes the new Global Directory to file system and issues a verification message. If the verification fails, GDE displays a listing of all unverifiable mappings and waits for corrections. Make appropriate corrections, or leave the Global Directory in its original, unedited state by using the QUIT command. If you have not made any changes to the Global Directory, GDE does not save a new Global Directory unless the original global directory had an older format which GDE has automatically upgraded. Note that while GDE upgrades older global directories to the current version, there is no facility to downgrade global directories to prior versions, so you should always save copies of any global directories that might be needed to retrieve archival data. 2 Help Help The HELP command displays online information about GDE commands and qualifiers. The format of the HELP command is: H[ELP] [topic...] where topic specifies the GDE command for which you want information. If you omit the topic, GDE prompts you for it. 2 LOCks LOCks The LOCKS command specifies the region into which GT.M maps locks on resource names not starting with a caret symbol (^). GDE maps locks on resource names, starting with a caret symbol (^), to the database region mapped for the global variable name matching the resource name. The format of the LOCKS command is: LOC[KS] -R[EGION]=region-name The LOCKS -REGION= qualifier allows specification of a region for local locks. By default, GDE maps local locks to the default region DEFAULT. Example: GDE> lock -region=main This command maps all locks on resource names that don't start with the caret symbol, "^" to the region main. 2 LOG LOG The LOG command creates a log file of all GDE commands and displays for the current editing session. Because the system places an exclamation point (!) (i.e., the comment symbol) before all display lines that are not entered by the user. In the log, the log can be used with the @ symbol as a command procedure. The format of the LOG command is: LOG LOG -ON[=file-name] LOG -OF[F] The LOG command, without a qualifier, reports the current status of GDE logging. The LOG command displays a message showing whether logging is in effect and the specification of the current log file for the GDE session. The log facility can be turned on and off using the -ON or -OFF qualifiers any time during a GDE session. However, GDE closes the log files only when the GDE session ends. The -ON qualifier has an optional argument of a file, which must identify a legal UNIX file. If LOG -ON has no file-argument, GDE uses the previous log file for the editing session. If no log file has previously been specified during this editing session, GDE uses the default log file GDELOG.LOG. Example: GDE> log -on="standard.log" This command turns on logging of the session and directs the output to standard.log. 2 Quit Quit The QUIT command ends the current editing session without saving any changes to the Global Directory. GDE does not update the Global Directory file. The format of the QUIT command is: Q[UIT] If the session made changes to the Global Directory, GDE issues a message warning that the Global Directory has not been updated. 2 Rename Rename The RENAME command allows you to change a name-space, the name of a region, or the name of a segment. The format of the RENAME command is: R[ENAME]-N[AME] old-name new-name R[ENAME]-R[EGION] old-region-name new-region-name R[ENAME]-S[EGMENT] old-segment-name new-segment-name The RENAME command requires specification of an object-type and two object-names. When renaming a region, GDE transfers all name mappings to the new region. When renaming a segment, GDE transfers the region mapping to the new segment. Example: GDE> rename -segment stable table This command renames segment stable to table and shifts any region mapped to stable so it is mapped to table. 2 SEtgd SEtgd The SETGD command closes out edits on one Global Directory and opens edits on another. The format of the SETGD command is: SE[TGD] -F[ILE]=file-name [-Q[UIT]] The -FILE=file-name specifies a different Global Directory file. When you provide a file-name without a full or relative pathname GDE uses the current working directory; if the file is missing an extension, then GDE defaults the type to .gld. The -QUIT qualifier specifies that any changes made to the current Global Directory are not written and are lost when you change Global Directories. SETGD changes the Global Directory that GDE is editing. If the current Global Directory has not been modified, or the -QUIT qualifier appears in the command, the change simply occurs. However, if the current Global Directory has been modified, GDE verifies the Global Directory, and if the verification is successful, writes that Global Directory. If the verification is not successful, the SETGD fails. Example: GDE> SETGD -f="temp" This changes the Global Directory being edited to temp. The quotation marks around the file name identifies the name of the file unequivocally to UNIX. If the -f is the final qualifier on the line, then the quotation marks are unnecessary. 2 SHow SHow The SHOW command displays information contained in the Global Directory about names, regions, and segments. The format of the SHOW command is: SH[OW] -C[OMMAND] -F[ILE]=[gde-command-file] SH[OW] -N[AME] [name-space] SH[OW] -R[EGION] [region-name] SH[OW] -S[EGMENT] [segment-name] SH[OW] -M[AP] [-R[EGION]=region-name] SH[OW] -T[EMPLATE] SH[OW] -A[LL] -COMMAND: Displays GDE commands that recreate the current Global Directory state. -F[ILE]=gde-command-file: Optionally specifies a file to hold the GDE commands produced by -COMMAND. -FILE must must always appear after -COMMAND. -NAME, -REGION, -SEGMENT, -MAP, -TEMPLATE, and -ALL are qualifiers that cause GDE to display selected portions of the Global Directory as follows: -MAP: Displays the current mapping of all names, regions, segments, and files. This qualifier corresponds to the section of the SHOW report titled ***MAP***. The output of a SHOW -MAP may be restricted to a particular region by specifying a -REGION qualifier with a region name argument. -TEMPLATE: Displays the current region and segment templates. This qualifier corresponds to the section of the SHOW report titled: ***TEMPLATES*** -ALL: Displays the entire Global Directory. This qualifier corresponds to displaying "all" sections of the SHOW report: ***TEMPLATES***, ***NAMES***, ***REGIONS***, ***SEGMENTS***, ***MAP***. By default, SHOW displays -ALL. If you want to print the Global Directory, create a log file by executing LOG -ON= before executing the SHOW command. The -LOG command captures all the commands entered and output. You can print the log file if you want a hard copy record. If you want to export the current Global Directory state, create a GDE command file with the SHOW -COMMAND -FILE=gde-command-file and run it in the target environment. Example: GDE>show -template *** TEMPLATES *** Std Inst Def Rec Key Null Null Freeze Qdb Region Coll Size Size Subs Coll Jnl on Error Rndwn ---------------------------------------------------------------------------------------------- 0 4080 255 NEVER Y Y DISABLED DISABLED Jnl File (def ext: .mjl) Before Buff Alloc Exten AutoSwitch ------------------------------------------------------------------------------------------ Y 2308 2048 2048 8386560 Segment Active Acc Typ Block Alloc Exten Options ------------------------------------------------------------------------------ * BG DYN 4096 5000 10000 GLOB =1000 LOCK = 40 RES = 0 ENCR = OFF MM DYN 4096 5000 10000 DEFER LOCK = 40 This displays only the TEMPLATES section of the Global Directory. GDE>SHOW -command TEMPLATE -SEGMENT -ACCESS_METHOD=MM -BLOCK_SIZE=4096 -ALLOCATION=5000 -EXTENSION_COUNT=10000 -LOCK_SPACE=40 -RESERVED_BYTES=0 -DEFER TEMPLATE -SEGMENT -ACCESS_METHOD=BG -BLOCK_SIZE=4096 -ALLOCATION=5000 -EXTENSION_COUNT=10000 -LOCK_SPACE=40 -RESERVED_BYTES=0 -GLOBAL_BUFFER_COUNT=1000 TEMPLATE -REGION -RECORD_SIZE=4080 -KEY_SIZE=255 -NULL_SUBSCRIPTS=NEVER -STDNULLCOLL -NOINST_FREEZE_ON_ERROR -NOQDBRUNDOWN TEMPLATE -REGION -JOURNAL=(BEFORE_IMAGE,BUFFER_SIZE=2308,ALLOCATION=2048,EXTENSION=2048,AUTOSWITCHLIMIT=8386560) ! LOCKS -REGION=DEFAULT CHANGE -REGION DEFAULT -DYNAMIC=DEFAULT -COLLATION_DEFAULT=0 -RECORD_SIZE=4080 -KEY_SIZE=255 -NULL_SUBSCRIPTS=NEVER -STDNULLCOLL -JOURNAL=(BEFORE_IMAGE,BUFFER_SIZE=2308,ALLOCATION=2048,EXTENSION=2048,AUTOSWITCHLIMIT=8386560, FILE="$gtmdir/$gtmver/g/gtm.mjl") -NOINST_FREEZE_ON_ERROR -NOQDBRUNDOWN ! CHANGE -SEGMENT DEFAULT -ACCESS_METHOD=BG -BLOCK_SIZE=4096 -ALLOCATION=5000 -EXTENSION_COUNT=10000 -LOCK_SPACE=40 -RESERVED_BYTES=0 -GLOBAL_BUFFER_COUNT=1000 -FILE=$gtmdir/$gtmver/g/gtm.dat ! This command displays the GDE commands to recreate the current global directory state. 2 Template Template The TEMPLATE command maintains a set of -REGION and -SEGMENT qualifier values for use as templates when ADDing regions and segments. When an ADD command omits qualifiers, GDE uses the template values as defaults. GDE maintains a separate set of -SEGMENT qualifier values for each ACCESS_METHOD. When GDE modifies the ACCESS_METHOD, it activates the appropriate set of TEMPLATEs and sets all unspecified qualifiers to the template defaults for the new ACCESS_METHOD. Use the GDE SHOW command to display qualifier values for all ACCESS_METHODs. The format of the TEMPLATE command is: T[EMPLATE] -R[EGION] [-REGION-qualifier...] T[EMPLATE] -S[EGMENT] [-SEGMENT-qualifier...] The TEMPLATE command requires specification of an object-type. Example: GDE> template -segment -allocation=200000 This command modifies the segment template so that any segments ADDed after this time produce database files with an ALLOCATION of 200,000 GDS blocks. 2 Verify Verify The VERIFY command validates information entered into the current Global Directory. It checks the name-to-region mappings to ensure all names map to a region. The VERIFY command checks region-to-segment mappings to ensure each region maps to a segment, each segment maps to only one region, and the segment maps to a UNIX file. The EXIT command implicitly performs a VERIFY -ALL. The format of the VERIFY command is: V[ERIFY] V[ERIFY] -N[AME] [name-space] V[ERIFY] -R[EGION] [region-name] V[ERIFY] -S[EGMENT] [segment-name] V[ERIFY] -M[AP] V[ERIFY] -T[EMPLATE] V[ERIFY] -A[LL] The object-type is optional. -MAP, -TEMPLATE, and -ALL are special qualifiers used as follows: -MAP Checks that all names map to a region, all regions map to a segment, and all segments map to a file. -TEMPLATE Checks that all templates currently are consistent and useable. -ALL Checks all map and template data. VERIFY with no qualifier, VERIFY -MAP, and VERIFY -ALL each check all current information. Example: GDE> verify -region regis This command verifies the region regis. 1 Qualifiers Qualifiers The -NAME, -REGION, and -SEGMENT qualifiers each have additional qualifiers used to further define or specify characteristics of a name, region, or segment. For more information, refer to the additional topics. 2 Name_Qualifiers Name Qualifiers The following -NAME qualifier can be used with the ADD or CHANGE commands. -REGION=region-name Specifies the name of a region. Region names are not case-sensitive, but are represented as uppercase by GDE. The minimum length is one alphabetic character. The maximum length is 16 alphanumeric characters. Example: GDE> add -name a* -region=areg This command creates the name-space a*, if it does not exist, and maps it to the region areg. Summary +------------------------------------------------------------------+ | GDE NAME Qualifiers | |------------------------------------------------------------------| | QUALIFIER | DEFAULT | MINIMUM | MAXIMUM | |------------------------------------+---------+---------+---------| | -R[EGION]=region-name (characters) | (none) | 1A | 16A/N | +------------------------------------------------------------------+ 2 Region_Qualifiers Region Qualifiers The following -REGION qualifiers can be used with the ADD, CHANGE, or TEMPLATE commands. -C[OLLATION_SEQUENCE]=id number Specifies the number of the collation sequence definition to be used as the default for this database file. The number can be any integer from 0 to 255. The number you assign as a value must match the number of a defined collation sequence that resides in the shared library pointed to by the environment variable gtm_collate_n. For information on defining this environment variable and creating an alternate collation sequence, refer to the "Internationalization" chapter in the GT.M Programmer's Guide. The minimum COLLATION_SEQUENCE ID number is zero, which is the standard M collation sequence. The maximum COLLATION_SEQUENCE ID number is 255. By default, GDE uses zero (0) as the COLLATION_SEQUENCE ID. -D[YNAMIC_SEGMENT]=segment-name Specifies the name of the segment to which the region is mapped. Segment-names are not case-sensitive, but are displayed as uppercase by GDE. The minimum length is one alphabetic character. The maximum length is 16 alphanumeric characters. -K[EY_SIZE]=size in bytes Specifies the maximum size of keys, in bytes, which can be stored in the region. The KEY_SIZE must be less than the RECORD_SIZE. GDE rejects the command if the KEY_SIZE is inappropriate for the RECORD_SIZE. The minimum KEY_SIZE is three bytes. The maximum KEY_SIZE is 1019 bytes. When determining the maximum key size, applications should consider the following: o A key must fit within one database block and the maximum KEY_SIZE is limited to 40 bytes less than the block size. For example, a 1024 byte block can support a maximum KEY_SIZE of 984 bytes and a 1536 byte block size is the smallest that supports a maximum KEY_SIZE of 1019 bytes. o GT.M uses packed decimal representation for numeric subscripts which may be larger or smaller than the original representation. o GT.M substitutes an element terminator for the caret (^), any comma (,), and any right parenthesis ()). o GT.M adds an extra byte for every string element, including the global name. For example, the key ^ACN ("Name", "Type") internally occupies 17 bytes. By default, GDE uses a KEY_SIZE of 64 bytes. -R[ECORD_SIZE]=size in bytes Specifies the maximum size (in bytes) of a global variable node's value that can be stored in a region. The KEY_SIZE must be less than the RECORD_SIZE. GDE rejects the command if the KEY_SIZE is inappropriate for the RECORD_SIZE. If the size of a global exceeds one database block, GT.M implicitly spans that global across multiple database blocks. In the event a global variable node spans multiple blocks, and the process is not already within a TP transaction, the GT.M run-time system automatically and transparently performs the entire operation within an implicit TP transaction (just as is the case with triggers). The minimum RECORD_SIZE is seven or eight, depending on your platform. The maximum RECORD_SIZE is 1,048,576 bytes (1MiB). By default, GDE uses a RECORD_SIZE of 256 bytes. -[NO]N[ULL_SUBSCRIPTS]=[ALWAYS|NEVER|EXISTING] Indicates whether GT.M allows null subscripts for global variables stored in the region (that is, whether GT.M permits references such as ^aaa("",1)). ALWAYS indicates that the null subscripts for global variables are allowed. NEVER indicates that null subscripts for global variables are not allowed. EXISTING indicates that null subscripts for global variable can be accessed and updated, but not created anew. By default, regions have -NULL_SUBSCRIPTS=NEVER. -[NO]STDNULLCOLL[=TRUE|FALSE] Determines whether GT.M null subscripts collate in conformance to the M standard. If -STDNULLCOLL is set to TRUE or -STDNULLCOLL is specified, subscripts of globals in the database follow the M standard where the null subscript collates before all other subscripts. If -STDNULLCOLL is set to FALSE or -NOSTDNULLCOLL is specified, null subscripts collate between numeric and string subscripts. -[NO]INST[_FREEZE_ON_ERROR] Controls whether custom errors in a region should automatically cause an Instance Freeze. This qualifier modifies the value of "Inst Freeze on Error" file header element. -[NO]Q[DBRUNDOWN] Quickens normal process shutdown where a large number of processes accessing a database file are required to shutdown almost simultaneously, for example, in benchmarking scenarios. When a terminating GT.M process observes that a large number of processes are attached to a database file and QDBRUNDOWN is enabled, it bypasses checking whether it is the last process accessing the database. Such a check occurs in a critical section and bypassing it also bypasses the usual RUNDOWN actions which accelerates process shutdown removing a possible impediment to process startup. By default, QDBRUNDOWN is disabled. Note that with QDBRUNDOWN there is a possibility of race condition that might leave the database fileheader and IPC resources in need of cleanup. Although QDBRUNDOWN minimizes the probability of such a race condition, it cannot eliminate it. When using QDBRUNDOWN, FIS recommends an explicit MUPIP RUNDOWN of the database file after the last process exits, to ensure the cleanup of database fileheader and IPC resources. -[NO]J[OURNAL][=journal-option-list] Specifies whether the database file allows journaling. If it does, this qualifier establishes characteristics for the journal file. -NOJOURNAL specifies that updates to the database file are not journaled. -NOJOURNAL does not accept an argument assignment. -JOURNAL specifies that journaling is allowed. -JOURNAL takes one or more arguments in a journal-option-list. The journal-option-list contains keywords separated with commas (,) enclosed in parentheses ( ). If the list contains only one keyword, the parentheses are optional. Although you do not have to establish the criteria for your journaling process at this point, it is efficient to do so, even if you are not entirely sure you will use journaling. The options available for -JOURNAL set up the environment, so it is ready for you to enable with MUPIP SET -JOURNAL. You can also change or add any of the established options at that time. The journal-option-list includes: o [NO]BE[FORE_IMAGE] o F[ILE_NAME]=file-specification-name o AUTOSWITCHLIMIT=blocks o A[LLOCATION]=blocks o E[XTENSION]=blocks o BU[FFER_SIZE]=pages The following section describes some -JOURNAL options. Specifies the limit on the size of a journal file. When the journal file size reaches the limit, GT.M automatically performs an implicit online switch to a new journal file. -[NO]BE[FORE_IMAGE] [NO]BEFORE_IMAGE controls whether the journal should capture before images of information that an update is about to modify. The BEFORE_IMAGE option is required if you plan to consider "roll-back" (Backward) recovery of the associated database file or if you plan to use certain database replication options. -F[ILE_NAME]="file-name" Specifies the name of the journal file. The name should always be enclosed in quotation marks in this context. Journal file-specifications-names are limited to 255 characters. By default, GDE derives the file-specification-name from the database "file-name". By default, GDE uses a journal file extension of .mjl. JOL Summary With GDE, you can create the journal files and define the journal parameters; however, you must use MUPIP SET to actually enable journaling. Summary The following table summarizes GDE region qualifiers. It provides their abbreviations, defaults (as provided by FIS), and allowable minimum and maximum values. +-----------------------------------------------------------------------------+ | GDE REGION Qualifiers | |-----------------------------------------------------------------------------| | QUALIFIER | DEFAULT | MINIMUM | MAXIMUM | |--------------------------------------------+----------+---------+-----------| |-C[OLLATION_SEQUENCE]=id-number (integer) |0 |0 |255 | |--------------------------------------------+----------+---------+-----------| |-D[YNAMIC_SEGMENT] =segment-name (char) |- |1 |16 | |--------------------------------------------+----------+---------+-----------| |-K[EY_SIZE]=size in bytes (integer) |64 |3 |1019 | |--------------------------------------------+----------+---------+-----------| |-R[ECORD_SIZE]=size in bytes (integer) |256 |7 |1,048,576 | | | | |(1 MiB) | |--------------------------------------------+----------+---------+-----------| |-N[ULL_SUBSCRIPTS]=[ALWAYS|NEVER|EXISTING] |NEVER |- |- | |--------------------------------------------+----------+---------+-----------| |-[NO]STDNULLCOLL |N |- |- | |--------------------------------------------+----------+---------+-----------| |-[NO]INST[_FREEZE_ON_ERROR] |DISABLED |- |- | |--------------------------------------------+----------+---------+-----------| |-[NO]Q[DBRUNDOWN] |DISABLED |- |- | |--------------------------------------------+----------+---------+-----------| |-[NO]J[OURNAL] [=journal-option-list] |-NOJ |- |- | +-----------------------------------------------------------------------------+ 2 Segment_Qualifiers Segment Qualifiers The following -SEGMENT qualifiers can be used with the ADD, CHANGE, or TEMPLATE commands. -AC[CESS_METHOD]=code Specifies the access method or the GT.M buffering strategy for storing and retrieving data from the global database file. o code can have 2 values - Buffered Global (BG) or Memory Mapped (MM). The default value is BG. o With BG, the global buffer pool manages the buffers (the OS/file system may also provide additional buffering). You get the choice of using BEFORE_IMAGE or NOBEFORE_IMAGE journaling for your database. o BG supports both forward and backward recovery and rollback to recover a database without a restore. o BG is a likely choice when you need faster recovery times from system failures. o With MM, GT.M bypasses the global buffer pool and relies entirely on the OS/file system to manage the data traffic between memory and disk. GT.M has no control over the timing of disk updates, therefore there is a greater reliance on the OS/file system for database performance. o MM supports NOBEFORE_IMAGE journaling only. GT.M triggers an error if you use MM with BEFORE_IMAGE Journaling. MM also supports MUPIP FORWARD -RECOVER and MUPIP JOURNAL -ROLLBACK with the -RESYNC or -FETCHRESYNC qualifiers to generate lost and broken transaction files. For more information, see the Journaling chapter. o MM does not support backward recovery/rollback. o MM is a possible choice when you need performance advantage in situations where the above restrictions are acceptable. o GDE maintains a separate set of segment qualifier values for each ACCESS_METHOD. o When GDE modifies the ACCESS_METHOD, it activates the appropriate set of TEMPLATEs and sets all unspecified qualifiers to the default values of the new ACCESS_METHOD. Example: GDE> change -segment DEFAULT -access_method=MM This command sets MM as the access method or the GT.M buffering strategy for storing and retrieving database for segment DEFAULT. -AL[LOCATION]=blocks Specifies the number of blocks GT.M allocates to a disk file when MUPIP creates the file. For GDS files, the number of bytes allocated is the size of the database file header plus the ALLOCATION size times the BLOCK_SIZE. o The minimum ALLOCATION is 10 blocks. o The maximum ALLOCATION is 1,040,187,392 blocks. o By default, GDE uses an ALLOCATION of 100 blocks. o The maximum size of a database file is 1,040,187,392(992Mi) blocks. o Out of the requested allocation, GT.M always reserves 32 global buffers for BG access method for read-only use to ensure that non-dirty global buffers are always available. o The default ALLOCATION was chosen for initial development and experimentation with GT.M. Because file fragmentation impairs performance, make the initial allocation for production files and large projects large enough to hold the anticipated contents of the file for a length of time consistent with your UNIX file reorganization schedule. -BL[OCK_SIZE]=size Specifies the size, in bytes, of each database block in the file system. The BLOCK_SIZE must be a multiple of 512. If the BLOCK_SIZE is not a multiple of 512, GDE rounds off the BLOCK_SIZE to the next highest multiple of 512 and issues a warning message. If the specified BLOCK_SIZE is less than the minimum, GDE uses the minimum BLOCK_SIZE. If the specified BLOCK_SIZE is greater than the maximum, GDE issues an error message. A BLOCK_SIZE that is equal to the page size used by your UNIX implementation serves well for most applications, and is a good starting point. You should determine the block sizes for your application through performance timing and benchmarking. In general, larger block sizes are more efficient from the perspective of the input/output subsystem. However, larger block sizes use more system resources (CPU and shared memory) and may increase collision and retry rates for transaction processing. **Note** Global nodes that span blocks incur some overhead and optimum application performance is likely to be obtained from a BLOCK_SIZE that accommodates the majority of nodes within a single block. If you adjust the BLOCK_SIZE, you should also adjust GLOBAL_BUFFER_COUNT. GDE does not allow you to change the block size to an arbitrary number. It always rounds the block size to the next higher multiple of 512, because the database block size must always be a multiple of 512. The minimum BLOCK_SIZE is 512 bytes. The maximum BLOCK_SIZE is 65,024 bytes. **Note** FIS recommends against using databases with block sizes larger than 16KB. If a specific global variable has records that have large record sizes, FIS recommends placing that global variable in a file by itself with large block sizes and using more appropriate block sizes for other global variables. 4KB and 8KB are popular database block sizes. By default, GDE uses a BLOCK_SIZE of 1024 bytes. -[NO]ENcryption Specifies whether or not the database file for a segment is flagged for encryption. Note that MUPIP CREATE acquires an encryption key for this file and puts a cryptographic hash of the key in the database file header. -EX[TENSION_COUNT]=blocks Specifies the number of extra GDS blocks of disk space by which the file should extend. The extend amount is interpreted as the number of usable GDS blocks to create with the extension. To calculate the number of host operating system blocks added with each extension, multiply the number of GDS blocks added by (GDS BLOCK_SIZE/host BLOCK_SIZE); add one local bitmap block for each 512 blocks added in each extension to the amount from step 1. If the extension is not a multiple of 512, remember to roundup when figuring the number of bitmap blocks. When a MUPIP EXTEND command does not include a -BLOCKS= qualifier, EXTEND uses the extension size in the database header. The extension amount may be changed with the MUPIP SET command. The minimum EXTENSION is zero blocks. The maximum EXTENSION is 65,535 blocks. By default, GDE uses an EXTENSION of 100 blocks. Like allocation, the default extension amount was chosen for initial development and experimentation with GT.M projects. Use larger extensions for larger files. Because multiple file extensions adversely affect performance, set up extensions appropriate to the file allocation. -F[ILE_NAME]=file-name Specifies the file for a segment. The maximum file name length is 255 characters. By default, GDE uses a file-name of mumps followed by the default extension, which is .dat. -G[LOBAL_BUFFER_COUNT]=size Specifies the number of global buffers for a file. Global buffers reside in shared memory and are part of the database caching mechanisms. Global buffers do not apply to MM databases. Choose the settings for this qualifier carefully. Small numbers of global buffers tend to throttle database performance. However, if your system has limited memory and the database file traffic is not heavy enough to hold the cache in memory, increasing GLOBAL_BUFFER_COUNT may trigger paging. If database global buffers are paged out, it may result in poor performance. Therefore, do not increase this factor to a large value without careful observation. The proper number of GLOBAL_BUFFERs depends on the application and the amount of primary memory available on the system. Most production databases exhibit a direct relationship between the number of GLOBAL_BUFFERs and performance. However, the relationship is not linear, but asymptotic, so that increases past some point have progressively less benefit. This point of diminishing returns depends on the application. For most applications, FIS expects the optimum number of GLOBAL_BUFFERs to be between 1K and 64K. Because transaction processing can be involved in an update and a transaction is limited to half the GLOBAL_BUFFER_COUNT, the value for GLOBAL_BUFFER_COUNT should therefore be at least twenty-six plus twice the number of the blocks required by the largest global variable node in your application. Generally, you should increase the number of GLOBAL_BUFFERs for production GDS databases. This is because GT.M uses the shared memory database cache associated with each GDS file for the majority of caching. The minimum GLOBAL_BUFFER_COUNT for BG is 64 blocks. The maximum for GLOBAL_BUFFER_COUNT for BG is 2147483647 blocks, but may vary depending on your platform. By default, GDE uses a GLOBAL_BUFFER_COUNT that is appropriate for the typical size of the platform. **Note** If global buffers are "paged out," improvements in system performance resulting from more global buffers will be more than offset by the dramatic slowdown that results from globals buffers that are "paged out." -L[OCK_SPACE]=integer Specifies the number of pages of space to use for the lock database stored with this segment. The size of a page is always 512 bytes. As GT.M runs out of space to store LOCK control information, LOCKs become progressively less efficient. If a single process consumes all the LOCK space, it cannot continue, and any other processes cannot proceed using LOCKs. The minimum LOCK_SPACE is 10 pages. The maximum LOCK_SPACE is 65,536 pages. By default, GDE uses a LOCK_SPACE of 40 pages. LOCK_SPACE usage depends on the number of locks and the number of processes waiting for locks. To estimate lock space needs, here is a rule of thumb: o 1.5KB overhead for the lock space, plus o 640 bytes for each lock base name, plus o 128 bytes for each subscript, plus o 128 bytes for each waiting process. Generally, you would limit LOCK_SPACE when memory is scarce or you want to be made aware of unexpected levels of LOCK usage. For most other cases, there is no reason to limit the LOCK_SPACE. If you are introducing new code, FIS recommends using TSTART and TCOMMIT as a more efficient alternate for most LOCKs because it pushes the responsibility for Isolation onto GT.M, which internally manages them with optimistic algorithms. -R[ESERVED_BYTES]=size Specifies the size to be reserved in each database block. RESERVED_BYTES is generally used to reserve room for compatibility with other implementations of M or to observe communications protocol restrictions. RESERVED_BYTES may also be used as a user-managed fill factor. The minimum RESERVED_BYTES is zero bytes. The maximum Reserved_Bytes is the block size minus the size of the block header (which is 7 or 8 depending on your platform) minus the maximum record size. By default, GDE uses a RESERVED_BYTES size of zero bytes. Summary The following table summarizes GDE segment qualifiers. It provides abbreviations, defaults (as provided by FIS), and allowable minimum and maximum values. +------------------------------------------------------------------------+ | GDE SEGMENT Qualifiers | |------------------------------------------------------------------------| | QUALIFIER | DEFAULT | MIN | MAX | |------------------------------------------------------------------------| | ** BLOCK_SIZE minus the size of the block header | |------------------------------------------------------------------------| | * May vary by platform | |------------------------------------------------------------------------| | -AC[CESS_METHOD]=BG|MM | BG | - | - | |-------------------------------+-----------+-----+----------------------| | -AL[LOCATION]=size (blocks) | 100 | 10 | 1,040,187,392(992Mi) | |-------------------------------+-----------+-----+----------------------| | -BL[OCK_SIZE]=size (bytes) | 1024 | 512 | 65024 | |-------------------------------+-----------+-----+----------------------| | -[NO]EN[CRYPTION] | 0 | | | |-------------------------------+-----------+-----+----------------------| | -EX[TENSION_COUNT]=size | 100 | 0 | 65,535 | | (blocks) | | | | |-------------------------------+-----------+-----+----------------------| | -F[ILE_NAME]=file-name | mumps.dat | - | 255 | | (chars) | | | | |-------------------------------+-----------+-----+----------------------| | -G[LOBAL_BUFFER_COUNT]=size | 1024* | 64 | 2147483647 | | (blocks) | | | | |-------------------------------+-----------+-----+----------------------| | -L[OCK_SPACE]=size (pages) | 40 | 10 | 65536 | |-------------------------------+-----------+-----+----------------------| | -R[ESERVED_BYTES]=size | 0 | 0 | block size-7 | | (bytes) | | | | +------------------------------------------------------------------------+ 1 Summary Summary The following table summarizes GDE commands, abbreviations, object types, required object names, and optional qualifiers. +------------------------------------------------------------------------+ | GDE Command Summary | |------------------------------------------------------------------------| | Command | Specified Object | Required Object Name/[Optional] | | | Type | Qualifier | |------------------------------------------------------------------------| | * -ALL is the default for the SHOW and VERIFY commands. | |------------------------------------------------------------------------| | @ | N/A | file-name | |------------+------------------+----------------------------------------| | | | name-space | | A[DD] | -N[AME] | | | | | -R[EGION]=region-name | |------------+------------------+----------------------------------------| | | | region-name | | - | -R[EGION] | | | | | -D[YNAMIC]=segment-name | | | | [-REGION-qualifier...] | |------------+------------------+----------------------------------------| | | | segment-name | | - | -S[EGMENT] | | | | | -F[ILE_NAME]=file-name | | | | [-SEGMENT-qualifier...] | |------------+------------------+----------------------------------------| | | | name-space | | C[HANGE] | -N[AME] | | | | | -R[EGION]=new-region | |------------+------------------+----------------------------------------| | | | region-name | | - | -R[EGION] | | | | | [-REGION-qualifier...] | |------------+------------------+----------------------------------------| | | | segment-name | | - | -S[EGMENT] | | | | | [-SEGMENT-qualifier] | |------------+------------------+----------------------------------------| | D[ELETE] | -N[AME] | name-space | |------------+------------------+----------------------------------------| | - | -R[EGION] | region-name | |------------+------------------+----------------------------------------| | - | -S[EGMENT] | segment-name | |------------+------------------+----------------------------------------| | E[XIT] | N/A | N/A | |------------+------------------+----------------------------------------| | HE[LP] | N/A | Keyword | |------------+------------------+----------------------------------------| | LOC[KS] | N/A | -R[EGION]=region-name | |------------+------------------+----------------------------------------| | | | [-ON][=file-name] | | LOG | N/A | | | | | [-OF[F]] | |------------+------------------+----------------------------------------| | Q[UIT] | N/A | N/A | |------------+------------------+----------------------------------------| | R[ENAME] | -N[AME] | old-name new-name | |------------+------------------+----------------------------------------| | - | -R[EGION] | old-reg-name new-reg-name | |------------+------------------+----------------------------------------| | - | -S[EGMENT] | old-seg-name new-seg-name | |------------+------------------+----------------------------------------| | SE[TGD] | N/A | -F[ILE]=file-name [-Q[UIT]] | |------------+------------------+----------------------------------------| | SH[OW] | -N[AME] | [name-space] | |------------+------------------+----------------------------------------| | - | -R[EGION] | [region-name] | |------------+------------------+----------------------------------------| | - | -S[EGMENT] | [segment-name] | |------------+------------------+----------------------------------------| | - | -M[AP] | [R[EGION]=region-name] | |------------+------------------+----------------------------------------| | - | T[EMPLATE] | N/A | |------------+------------------+----------------------------------------| | - | -A[LL]* | N/A | |------------+------------------+----------------------------------------| | T[EMPLATE] | -R[EGION] | [-REGION-qualifier...] | |------------+------------------+----------------------------------------| | - | -S[EGMENT] | [ -SEGMENT-qualifier...] | |------------+------------------+----------------------------------------| | V[ERIFY] | -N[AME] | [name-space] | |------------+------------------+----------------------------------------| | - | -R[EGION] | [region-name] | |------------+------------------+----------------------------------------| | - | -S[EGMENT] | [segment-name] | |------------+------------------+----------------------------------------| | - | -M[AP] | N/A | |------------+------------------+----------------------------------------| | - | -T[EMPLATE] | N/A | |------------+------------------+----------------------------------------| | - | -A[LL]* | N/A | +------------------------------------------------------------------------+ 2 Qualifier_Summary Qualifier Summary The following table summarizes all qualifiers for the ADD, CHANGE, and TEMPLATE commands. The defaults are those supplied by FIS. +------------------------------------------------------------------------------------------------+ | GDE Command Qualifiers | |------------------------------------------------------------------------------------------------| | QUALIFIER | DEF | MIN | MAX | NAM | REG | SEG | |------------------------------------------------------------------------------------------------| | * DEFAULT is the default region- and segment-name | | ** MUMPS is the default file-name | | *** May vary by platform | | **** -NONULL_SUBSCRIPTS | |------------------------------------------------------------------------------------------------| |-AC[CESS_METHOD]=code |BG |- |- |- |- |X | |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| |-AL[LOCATION]=size(blocks) |100 |10 |1040187392(992Mi) |- |- |X | |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| |-BL[OCK_SIZE]=size(bytes) |1024 |512 |65024 |- |- |X | |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| |-C[OLLATION_SEQUENCE]=id-number (integer) |0 |0 |255 |- |X |- | |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| |-D[YNAMIC_SEGMENT]=segment-name (chars) |* |1A |16A/N |- |X |- | |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| |-EX[TENSION_COUNT]=size (blks) |100 |0 |65535 |- |- |X | |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| |-F[ILE_NAME]=file-name (chars) |** |1A |255A/N |- |- |X | |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| |-G[LOBAL_BUFFER_COUNT]=size (blocks) |1024 |64 |2147483647 *** |- |- |X | | |*** | | | | | | |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| |-K[EY_SIZE]=size (bytes) |64 |3 |1019 |- |X |- | |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| |-L[OCK_SPACE]=size (pages) |40 |10 |65536 |- |- |X | |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| |-[NO]INST[_FREEZE_ON_ERROR] |FALSE |- |- |- |X |- | |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| |-[NO]Q[DBRUNDOWN] |FALSE |- |- |- |X |- | |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| |-[NO]J[OURNAL]=option-list |-NOJ |- |- |- |X |- | |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| |-N[ULL_SUBSCRIPTS]=[ALWAYS|NEVER|EXISTING] |NEVER |- |- |- |X |- | | |or ****| | | | | | |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| |-[NO]STDNULLCOLL[=TRUE|FALSE] |FALSE |- |- |- |X |- | |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| |-R[ECORD_SIZE]=size (bytes) |256 |7 |1048576 |- |X |- | |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| |-R[EGION] region-name (chars) |* |1A |16A/N |X |- |- | |--------------------------------------------+-------+-----+-------------------+-----+-----+-----| |-R[ESERVED_BYTES]=size (bytes) |0 |0 |blocksize |- |- |X | +------------------------------------------------------------------------------------------------+ fis-gtm-V6.0-003/sr_port/gde.m0000644000032200000250000000665512201176156014764 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001, 2011 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; gde: ;base module - d DEBUG^GDE to debug i $$set^%LCLCOL(0) s (debug,runtime)=0 DBG: ;transfer point for DEBUG and "runtime" %gde s $et=$s(debug:"b:$zs'[""%GDE""!allerrs ",1:"")_"g:(""%GDE%NONAME""[$p($p($zs,"","",3),""-"")) SHOERR^GDE d ABORT^GDE" s io=$io,useio="io",comlevel=0,combase=$zl,resume(0)=$zl_":INTERACT" i $$set^%PATCODE("M") d GDEINIT^GDEINIT,GDEMSGIN^GDEMSGIN,GDFIND^GDESETGD,CREATE^GDEGET:create,LOAD^GDEGET:'create i debug s prompt="DEBUGDE>",uself="logfile" e s prompt="GDE>",uself="logfile:(ctrap=$c(3,25,26):exception=""d CTRL^GDE"")" e s useio="io:(ctrap=$c(3,25,26):exception=""d CTRL^GDE"")" u @useio i $l(comline) d comline,EXIT^GDEEXIT i runtime s prompt="GD_SHOW>",verb="SHOW",x="" f s x=$o(syntab(x)) q:'$l(x) i x'="SHOW" k syntab(x) INTERACT f u io:ctrap=$c(25,26) w !,prompt," " r comline u @useio d comline:$l(comline) q comline: s cp=1,ntoken="",ntoktype="TKEOL" s:runtime comline="/"_comline d GETTOK^GDESCAN i log u @uself w comline,! u @useio i runtime n NAME,REGION,SEGMENT,gqual,lquals zg:"/QUIT"[$tr(comline,lower,upper) combase-1 d SHOW^GDEPARSE q i ntoktype="TKAMPER" s resume(comlevel+1)=$zl d comfile q d GDEPARSE^GDEPARSE q CTRL i $p($zs,",",3,999)["%GTM-E-CTRAP, Character trap $C(3) encountered" do zg @resume(comlevel) . i comlevel>0 d comeof; if we take a ctrl-c in a command file then get out of that command file i $p($zs,",",3,999)["%GTM-E-CTRAP, Character trap $C(25) encountered" h i $p($zs,",",3,999)["%GTM-E-CTRAP, Character trap $C(26) encountered" d EXIT^GDEEXIT i $p($zs,",",3,999)="%GTM-E-IOEOF, Attempt to read past an end-of-file" d comexit i $zeof d EXIT^GDEEXIT d ABORT ; comexit: i 'update d QUIT^GDEQUIT i $$ALL^GDEVERIF,$$GDEPUT^GDEPUT h DBGCOMX u $i:exception="" s $et="" zm (gdeerr("VERIFY")\2*2):"FAILED" h comfile: d GETTOK^GDESCAN,TFSPEC^GDEPARSE s (comfile,comfile(comlevel+1))=$zparse(value,"","",".COM") i '$l($zsearch(comfile)),'$l($zsearch(comfile)) zm gdeerr("FILENOTFND"):comfile e o comfile:(read:exc="zg "_$zl_":comeof") zm gdeerr("EXECOM"):comfile d SCRIPT comeof c comfile s comlevel=$select(comlevel>1:comlevel-1,1:0) i comlevel>0 s comfile=comfile(comlevel) zm gdeerr("EXECOM"):comfile e u @useio i $p($zs,",",3)'["%GTM-E-IOEOF",$p($zs,",",3)'["FILENOTFND" w !,$p($zs,",",3,9999),! q SCRIPT: s comlevel=comlevel+1 f u comfile r comline i $e(comline,1)'="!" u @useio d comline:$l(comline) ;this loop is terminated by the comfile exception at eof SHOERR w !,$p($zs,",",3,999),! s comlevel=$s(comlevel>1:comlevel-1,1:0) s $ecode="" zg @resume(comlevel) q ABORT s abortzs=$zs,abort="GDEDUMP.DMP",$et="" o abort:(newversion:noreadonly) u abort zsh "*" c abort u @useio ; make GDECHECK error fatal except native UNIX i $d(gdeerr) zm gdeerr("GDECHECK") Write $ZMessage($Select($ZVersion'["VMS"&(256>abortzs):+abortzs,1:+abortzs\8*8+4)),! e w $zs h DEBUG ;entry point to debug gde i $$set^%LCLCOL(0) s allerrs=0,debug=1,runtime=0 u 0:(ctrap="":exception="") zb DBGCOMX,ABORT g DBG fis-gtm-V6.0-003/sr_port/gdeadd.m0000644000032200000250000000402212201176156015417 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; add: ;implement the verb: ADD NAME i $d(nams(NAME)) zm gdeerr("OBJDUP"):"Name":NAME i '$d(lquals("REGION")) zm gdeerr("QUALREQD"):"Region" s update=1,nams=nams+1 s nams(NAME)=lquals("REGION") q REGION i $d(regs(REGION)) zm gdeerr("OBJDUP"):"Region":REGION i '$d(lquals("DYNAMIC_SEGMENT")) zm gdeerr("QUALREQD"):"Dynamic_segment" i $d(lquals("JOURNAL")),lquals("JOURNAL"),'$d(lquals("BEFORE_IMAGE")) zm gdeerr("QUALREQD"):"Before_image" i $d(lquals("NULL_SUBSCRIPTS")) d NQUALS^GDEVERIF(.lquals) i '$$RQUALS^GDEVERIF(.lquals) zm gdeerr("OBJNOTADD"):"Region":REGION s update=1,s="",regs=regs+1 f s s=$o(tmpreg(s)) q:'$l(s) s regs(REGION,s)=tmpreg(s) f s s=$o(lquals(s)) q:'$l(s) s regs(REGION,s)=lquals(s) i $d(segs),$d(regs(REGION,"DYNAMIC_SEGMENT")),$d(segs(regs(REGION,"DYNAMIC_SEGMENT"),"ACCESS_METHOD")) d . i "MM"=segs(regs(REGION,"DYNAMIC_SEGMENT"),"ACCESS_METHOD"),'$d(lquals("BEFORE_IMAGE")) s regs(REGION,"BEFORE_IMAGE")=0 q SEGMENT i $d(segs(SEGMENT)) zm gdeerr("OBJDUP"):"Segment":SEGMENT i '$d(lquals("FILE_NAME")) zm gdeerr("QUALREQD"):"File" s am=$s($d(lquals("ACCESS_METHOD")):lquals("ACCESS_METHOD"),1:tmpacc) i '$$SQUALS^GDEVERIF(am,.lquals) zm gdeerr("OBJNOTADD"):"Segment":SEGMENT s update=1,s="",segs=segs+1 s segs(SEGMENT,"ACCESS_METHOD")=am i "MM"=am s s="" f s s=$o(regs(s)) q:'$l(s) d . i regs(s,"DYNAMIC_SEGMENT")=SEGMENT,'$d(lquals("BEFORE_IMAGE")) s regs(s,"BEFORE_IMAGE")=0 d seg f s s=$o(lquals(s)) q:'$l(s) s segs(SEGMENT,s)=lquals(s) q seg: s segs(SEGMENT,"FILE_NAME")=lquals("FILE_NAME") f s s=$o(tmpseg(am,s)) q:'$l(s) s segs(SEGMENT,s)=tmpseg(am,s) q fis-gtm-V6.0-003/sr_port/gdechang.m0000644000032200000250000000325112201176156015752 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; change: ;implement the verb: CHANGE NAME i '$d(nams(NAME)) zm gdeerr("OBJNOTFND"):"Name":NAME i '$d(lquals("REGION")) zm gdeerr("QUALREQD"):"Region" s update=1 s nams(NAME)=lquals("REGION") q REGION i '$d(regs(REGION)) zm gdeerr("OBJNOTFND"):"Region":REGION i $d(lquals("JOURNAL")),lquals("JOURNAL"),'regs(REGION,"JOURNAL"),'$d(lquals("BEFORE_IMAGE")) d . zm gdeerr("QUALREQD"):"Before_image" i $d(lquals("NULL_SUBSCRIPTS")) d NQUALS^GDEVERIF(.lquals) i '$$RQUALS^GDEVERIF(.lquals) zm gdeerr("OBJNOTCHG"):"region":REGION s update=1,s="" f s s=$o(lquals(s)) q:'$l(s) s regs(REGION,s)=lquals(s) q SEGMENT i '$d(segs(SEGMENT)) zm gdeerr("OBJNOTFND"):"Segment":SEGMENT s am=$s($d(lquals("ACCESS_METHOD")):lquals("ACCESS_METHOD"),1:segs(SEGMENT,"ACCESS_METHOD")) i '$$SQUALS^GDEVERIF(am,.lquals) zm gdeerr("OBJNOTCHG"):"segment":SEGMENT s update=1,s="" s segs(SEGMENT,"ACCESS_METHOD")=am f s s=$o(lquals(s)) q:'$l(s) s segs(SEGMENT,s)=lquals(s) f s s=$o(tmpseg(am,s)) q:'$l(s) d . i '$l(tmpseg(am,s)) s segs(SEGMENT,s)="" q . i '$l(segs(SEGMENT,s)) s segs(SEGMENT,s)=tmpseg(am,s) i "MM"=am,"MM"'=tmpacc s s="" f s s=$o(regs(s)) q:'$l(s) d . i regs(s,"DYNAMIC_SEGMENT")=SEGMENT,'$d(lquals("BEFORE_IMAGE")) s regs(s,"BEFORE_IMAGE")=0 q fis-gtm-V6.0-003/sr_port/gdedelet.m0000644000032200000250000000150412201176156015766 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; delete: ;implement the verb: DELETE NAME i '$d(nams(NAME)) zm gdeerr("OBJNOTFND"):"Name":NAME i NAME="*" zm gdeerr("LVSTARALON") s update=1 k nams(NAME) s nams=nams-1 q REGION i '$d(regs(REGION)) zm gdeerr("OBJNOTFND"):"Region":REGION s update=1 k regs(REGION) s regs=regs-1 q SEGMENT i '$d(segs(SEGMENT)) zm gdeerr("OBJNOTFND"):"Segment":SEGMENT s update=1 k segs(SEGMENT) s segs=segs-1 q fis-gtm-V6.0-003/sr_port/gdeerrors.msg0000644000032200000250000000773212201176156016550 0ustar librarygtc!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! ! Copyright 2001, 2012 Fidelity Information Services, Inc ! ! ! ! This source code contains the intellectual property ! ! of its copyright holder(s), and is made available ! ! under a license. If you do not know the terms of ! ! the license, please stop and do not read further. ! ! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .FACILITY GDE, 248 /PREFIX = GDE_ .TITLE GDEERRORS Error Messages for GDE BLKSIZ512 /info/fao=4 EXECOM /info/fao=2 FILENOTFND /error/fao=2 GDCREATE /info/fao=2 GDECHECK /info/fao=0 GDUNKNFMT /info/fao=2 GDUPDATE /info/fao=2 GDUSEDEFS /info/fao=2 ILLCHAR /error/fao=2 INPINTEG /fatal/fao=0 KEYTOOBIG /info/fao=4 KEYSIZIS /info/fao=2 KEYWRDAMB /error/fao=4 KEYWRDBAD /error/fao=4 LOADGD /info/fao=2 LOGOFF /info/fao=2 LOGON /info/fao=2 LVSTARALON /error/fao=0 MAPBAD /info/fao=8 MAPDUP /info/fao=10 NAMSTARTBAD /error/fao=2 NOACTION /info/fao=2 RPAREN /error/fao=0 NOEXIT /info/fao=0 NOLOG /info/fao=2 NOVALUE /error/fao=2 NONEGATE /error/fao=2 OBJDUP /error/fao=4 OBJNOTADD /error/fao=4 OBJNOTCHG /error/fao=4 OBJNOTFND /error/fao=4 OBJREQD /error/fao=2 PREFIXBAD /error/fao=4 QUALBAD /error/fao=2 QUALDUP /error/fao=2 QUALREQD /error/fao=2 RECTOOBIG /info/fao=6 RECSIZIS /info/fao=2 REGIS /info/fao=2 SEGIS /info/fao=4 VALTOOBIG /info/fao=6 VALTOOLONG /error/fao=6 VALTOOSMALL /info/fao=6 VALUEBAD /error/fao=4 VALUEREQD /error/fao=2 VERIFY /info/fao=2 BUFSIZIS /info/fao=2 BUFTOOSMALL /info/fao=4 MMNOBEFORIMG /info/fao=0 NOJNL /info/fao=2 GDREADERR /info/fao=2 GDNOTSET /info/fao=0 INVGBLDIR /info/fao=4 WRITEERROR /info/fao=2 NONASCII /error/fao=4 CRYPTNOMM /error/fao=2 JNLALLOCGROW /info/fao=8 KEYFORBLK /info/fao=4 .end fis-gtm-V6.0-003/sr_port/gdeexit.m0000644000032200000250000000112312201176156015637 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; exit: ;implement the verb: EXIT EXIT i 'update d QUIT^GDEQUIT i '$$ALL^GDEVERIF zm gdeerr("NOEXIT") q i '$$GDEPUT^GDEPUT q ; zm is issued in GDEPUT.m h fis-gtm-V6.0-003/sr_port/gdehelp.m0000644000032200000250000000110712201176156015620 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; help: ;implement the verb: HELP HELP n helpline s helpline=$e(comline,cp-$l(ntoken),999) u io:ctrap=$c(3,25) zh helpline:helpfile u @useio q fis-gtm-V6.0-003/sr_port/gdeinit.m0000644000032200000250000004602012201176156015636 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; gdeinit: ;set up local variables and arrays GDEINIT i $ZVER'["VMS" view "BADCHAR" s renpref="" s log=0,logfile="GDELOG.LOG",BOL="" s ZERO=$c(0),ONE=$c(1),TRUE=ONE,FALSE=ZERO,TAB=$c(9) s endian("VAX","VMS")=FALSE,glo("VMS")=1024 s endian("AXP","VMS")=FALSE,endian("AXP","OSF1")=FALSE,glo("VMS")=1024,glo("OSF1")=1024 s endian("x86","SCO")=FALSE,endian("x86","UWIN")=FALSE,endian("x86","Linux")=FALSE,endian("x86","CYGWIN")=FALSE s endian("x86_64","Linux")=FALSE s glo("SCO")=384,glo("UWIN")=1024,glo("Linux")=1024,glo("CYGWIN")=1024 s endian("SEQUOIA_SERIES_400","VAX")=TRUE,glo("VAX")=1024 s endian("HP-PA","HP-UX")=TRUE,glo("HP-UX")=1024 s endian("IA64","HP-UX")=TRUE,glo("HP-UX")=1024 s endian("IA64","Linux")=FALSE,glo("Linux")=1024 s endian("SPARC","SUN/OS_V4.x")=TRUE,endian("SPARC","Solaris")=TRUE,glo("SUN/OS_V4.x")=800,glo("Solaris")=1024 s endian("MIPS","A25")=TRUE,glo("A25")=1024 s endian("B30","NONSTOP-UX")=TRUE,glo("NONSTOP-UX")=1024 s endian("B32","NONSTOP-UX")=TRUE,glo("NONSTOP-UX")=1024 s endian("MC-680x0","SYS_V/68_R3V6")=TRUE,endian("MC-680x0","TOPIX")=TRUE,glo("SYS_V/68_R3V6")=1024,glo("TOPIX")=1024 s endian("RS6000","AIX")=TRUE,glo("AIX")=1024 s endian("S390","OS390")=TRUE,endian("S390X","Linux")=TRUE,glo("OS390")=1024 ; The following line is for support of AIX V3.2.5 only and can (and should) ; be removed (along with this comment) as soon as we drop support for ; AIX V3.2.5. This change is needed to correspond to the change in ; release_name.h. C9801-000344 s glo("AIX325")=glo("AIX") s HEX(0)=1 s gtm64=$p($zver," ",4) i "/IA64/RS6000/SPARC/x86_64/x86/S390/S390X"[("/"_gtm64) s encsupportedplat=TRUE,gtm64=$s("x86"=gtm64:FALSE,1:TRUE) e s (encsupportedplat,gtm64)=FALSE i (gtm64=TRUE) f x=1:1:16 s HEX(x)=HEX(x-1)*16 i x#2=0 s TWO(x*4)=HEX(x) e f x=1:1:8 s HEX(x)=HEX(x-1)*16 i x#2=0 s TWO(x*4)=HEX(x) f i=25:1:30 s TWO(i)=TWO(i-1)*2 s TWO(31)=TWO(32)*.5 s lower="abcdefghijklmnopqrstuvwxyz",upper="ABCDEFGHIJKLMNOPQRSTUVWXYZ" s endian=endian($p($zver," ",4),$p($zver," ",3)) s ver=$p($zver," ",3) s defglo=glo(ver) s comline=$zcmdline s nullsubs="\NEVER\FALSE\ALWAYS\TRUE\EXISTING" s nommbi=1 ; this is used in gdeverif and should be removed along with the code when support is added d UNIX:ver'="VMS" d VMS:ver="VMS" d syntabi ; i (gtm64=FALSE) d . s SIZEOF("am_offset")=324 . s SIZEOF("file_spec")=256 . s SIZEOF("gd_header")=16 . s SIZEOF("gd_contents")=44 . s SIZEOF("gd_map")=36 . if ver'="VMS" d . . s SIZEOF("gd_region")=356 . . s SIZEOF("gd_region_padding")=0 ; not used on VMS . . s SIZEOF("gd_segment")=340 . e d . . s SIZEOF("gd_region")=332 . . s SIZEOF("gd_segment")=336 e d . s SIZEOF("am_offset")=332 . s SIZEOF("file_spec")=256 . s SIZEOF("gd_header")=16 . s SIZEOF("gd_contents")=80 . s SIZEOF("gd_map")=40 . s SIZEOF("gd_region")=368 . s SIZEOF("gd_region_padding")=4 . s SIZEOF("gd_segment")=360 s SIZEOF("mident")=32 s SIZEOF("blk_hdr")=16 i ver'="VMS" d . s SIZEOF("rec_hdr")=4 ;GTM-6941 e d . s SIZEOF("rec_hdr")=3 s SIZEOF("dsk_blk")=512 i ver'="VMS" d . s SIZEOF("max_str")=1048576 e d . s SIZEOF("max_str")=32767 s SIZEOF("reg_jnl_deq")=4 ; not used on VMS s MAXNAMLN=SIZEOF("mident")-1,MAXREGLN=32,MAXSEGLN=32 ; maximum name length allowed is 31 characters s PARNAMLN=31,PARREGLN=31,PARSEGLN=31 ; ; tokens are used for error reporting only s tokens("TKIDENT")="identifier" s tokens("TKNUMLIT")="number" s tokens("TKEOL")="end-of-line" s tokens("""")="TKSTRLIT",tokens("TKSTRLIT")="string literal" s tokens("@")="TKAMPER",tokens("TKAMPER")="ampersand" s tokens("*")="TKASTER",tokens("TKASTER")="asterisk" s tokens(":")="TKCOLON",tokens("TKCOLON")="colon" s tokens(",")="TKCOMMA",tokens("TKCOMMA")="comma" s tokens("$")="TKDOLLAR",tokens("TKDOLLAR")="dollar sign" s tokens("=")="TKEQUAL",tokens("TKEQUAL")="equal sign" s tokens("<")="TKLANGLE",tokens("TKLANGLE")="left angle bracket" s tokens("[")="TKLBRACK",tokens("TKLBRACK")="left bracket" s tokens("(")="TKLPAREN",tokens("TKLPAREN")="left parenthesis" s tokens("-")="TKDASH",tokens("TKDASH")="dash" s tokens("%")="TKPCT",tokens("TKPCT")="percent sign" s tokens(".")="TKPERIOD",tokens("TKPERIOD")="period" s tokens(")")="TKRPAREN",tokens("TKRPAREN")="right parenthesis" s tokens("]")="TKRBRACK",tokens("TKRBRACK")="right bracket" s tokens(">")="TKRANGLE",tokens("TKRANGLE")="right angle bracket" s tokens(";")="TKSCOLON",tokens("TKSCOLON")="semicolon" s tokens("/")="TKSLASH",tokens("TKSLASH")="slash" s tokens("_")="TKUSCORE",tokens("TKUSCORE")="underscore" s tokens("!")="TKEXCLAM",tokens("TKEXCLAM")="exclamation point" s tokens("TKOTHER")="other" ; maximums and mimimums ; region s minreg("ALLOCATION")=$s(ver'="VMS":200,1:10) s minreg("BEFORE_IMAGE")=0,minreg("COLLATION_DEFAULT")=0,minreg("STDNULLCOLL")=0 s minreg("EXTENSION")=0 i ver'="VMS" d . s minreg("AUTOSWITCHLIMIT")=16384 . s minreg("ALIGNSIZE")=4096 ; geq RECORD_SIZE . s minreg("EPOCH_INTERVAL")=1 . s minreg("SYNC_IO")=0 . s minreg("YIELD_LIMIT")=0 . s minreg("INST_FREEZE_ON_ERROR")=0 . s minreg("BUFFER_SIZE")=2307 . s minreg("QDBRUNDOWN")=0 . s minreg("RECORD_SIZE")=0 e d . s minreg("RECORD_SIZE")=SIZEOF("rec_hdr")+4 s minreg("JOURNAL")=0,minreg("KEY_SIZE")=3,minreg("NULL_SUBSCRIPTS")=0 s maxreg("ALLOCATION")=TWO(24),maxreg("BEFORE_IMAGE")=1 s maxreg("COLLATION_DEFAULT")=255,maxreg("STDNULLCOLL")=1 i ver="VMS" do . s maxreg("EXTENSION")=HEX(4)-1 . s maxreg("BUFFER_SIZE")=2000 e d . s maxreg("EXTENSION")=1073741823 . s maxreg("AUTOSWITCHLIMIT")=8388607 . s maxreg("ALIGNSIZE")=4194304 . s maxreg("EPOCH_INTERVAL")=32767 . s maxreg("SYNC_IO")=1 . s maxreg("YIELD_LIMIT")=2048 . s maxreg("INST_FREEZE_ON_ERROR")=1 . s maxreg("BUFFER_SIZE")=32768 . s maxreg("QDBRUNDOWN")=1 s maxreg("JOURNAL")=1,maxreg("KEY_SIZE")=1019,maxreg("NULL_SUBSCRIPTS")=2 s maxreg("RECORD_SIZE")=SIZEOF("max_str") ; segments ; bg s minseg("BG","ALLOCATION")=10,minseg("BG","BLOCK_SIZE")=SIZEOF("dsk_blk"),minseg("BG","EXTENSION_COUNT")=0 s minseg("BG","GLOBAL_BUFFER_COUNT")=64,minseg("BG","LOCK_SPACE")=10,minseg("BG","RESERVED_BYTES")=0 s maxseg("BG","ALLOCATION")=TWO(27),(maxseg("BG","BLOCK_SIZE"),maxseg("BG","RESERVED_BYTES"))=HEX(4)-SIZEOF("dsk_blk") i ver'="VMS" s maxseg("BG","ALLOCATION")=TWO(30)-TWO(25) ; supports 992M blocks for UNIX only s maxseg("BG","EXTENSION_COUNT")=HEX(4)-1,maxseg("BG","LOCK_SPACE")=65536 i (gtm64=TRUE) s maxseg("BG","GLOBAL_BUFFER_COUNT")=2147483647 ; 2G-1 e s maxseg("BG","GLOBAL_BUFFER_COUNT")=65536 ; mm s minseg("MM","ALLOCATION")=10,minseg("MM","BLOCK_SIZE")=SIZEOF("dsk_blk"),minseg("MM","DEFER")=0 s minseg("MM","LOCK_SPACE")=10,minseg("MM","EXTENSION_COUNT")=0,minseg("MM","RESERVED_BYTES")=0 s maxseg("MM","ALLOCATION")=TWO(27),(maxseg("MM","BLOCK_SIZE"),maxseg("BG","RESERVED_BYTES"))=HEX(4)-SIZEOF("dsk_blk") i ver'="VMS" s maxseg("MM","ALLOCATION")=TWO(30)-TWO(25) ; supports 992M blocks for UNIX only s maxseg("MM","DEFER")=86400,maxseg("MM","LOCK_SPACE")=1000,maxseg("MM","EXTENSION_COUNT")=HEX(4)-1 q ;----------------------------------------------------------------------------------------------------------------------------------- ; gde command language syntax table syntabi: s syntab("ADD","NAME")="" s syntab("ADD","NAME","REGION")="REQUIRED" s syntab("ADD","NAME","REGION","TYPE")="TREGION" s syntab("ADD","REGION")="" s syntab("ADD","REGION","COLLATION_DEFAULT")="REQUIRED" s syntab("ADD","REGION","COLLATION_DEFAULT","TYPE")="TNUMBER" s syntab("ADD","REGION","STDNULLCOLL")="NEGATABLE" s syntab("ADD","REGION","DYNAMIC_SEGMENT")="REQUIRED" s syntab("ADD","REGION","DYNAMIC_SEGMENT","TYPE")="TSEGMENT" i ver'="VMS" s syntab("ADD","REGION","INST_FREEZE_ON_ERROR")="NEGATABLE" s syntab("ADD","REGION","JOURNAL")="NEGATABLE,REQUIRED,LIST" s syntab("ADD","REGION","JOURNAL","ALLOCATION")="REQUIRED" s syntab("ADD","REGION","JOURNAL","ALLOCATION","TYPE")="TNUMBER" s syntab("ADD","REGION","JOURNAL","AUTOSWITCHLIMIT")="REQUIRED" s syntab("ADD","REGION","JOURNAL","AUTOSWITCHLIMIT","TYPE")="TNUMBER" s syntab("ADD","REGION","JOURNAL","BUFFER_SIZE")="REQUIRED" s syntab("ADD","REGION","JOURNAL","BUFFER_SIZE","TYPE")="TNUMBER" s syntab("ADD","REGION","JOURNAL","BEFORE_IMAGE")="NEGATABLE" s syntab("ADD","REGION","JOURNAL","EXTENSION")="REQUIRED" s syntab("ADD","REGION","JOURNAL","EXTENSION","TYPE")="TNUMBER" s syntab("ADD","REGION","JOURNAL","FILE_NAME")="REQUIRED" s syntab("ADD","REGION","JOURNAL","FILE_NAME","TYPE")="TFSPEC" ;s syntab("ADD","REGION","JOURNAL","STOP_ENABLED")="NEGATABLE" s syntab("ADD","REGION","KEY_SIZE")="REQUIRED" s syntab("ADD","REGION","KEY_SIZE","TYPE")="TNUMBER" s syntab("ADD","REGION","NULL_SUBSCRIPTS")="NEGATABLE,REQUIRED" s syntab("ADD","REGION","NULL_SUBSCRIPTS","TYPE")="TNULLSUB" s syntab("ADD","REGION","NULL_SUBSCRIPTS","TYPE","VALUES")=nullsubs i ver'="VMS" s syntab("ADD","REGION","QDBRUNDOWN")="NEGATABLE" s syntab("ADD","REGION","RECORD_SIZE")="REQUIRED" s syntab("ADD","REGION","RECORD_SIZE","TYPE")="TNUMBER" s syntab("ADD","SEGMENT")="" s syntab("ADD","SEGMENT","ACCESS_METHOD")="REQUIRED" s syntab("ADD","SEGMENT","ACCESS_METHOD","TYPE")="TACCMETH" s syntab("ADD","SEGMENT","ACCESS_METHOD","TYPE","VALUES")=accmeth s syntab("ADD","SEGMENT","ALLOCATION")="REQUIRED" s syntab("ADD","SEGMENT","ALLOCATION","TYPE")="TNUMBER" s syntab("ADD","SEGMENT","BLOCK_SIZE")="REQUIRED" s syntab("ADD","SEGMENT","BLOCK_SIZE","TYPE")="TNUMBER" s syntab("ADD","SEGMENT","BUCKET_SIZE")="REQUIRED" s syntab("ADD","SEGMENT","BUCKET_SIZE","TYPE")="TNUMBER" s syntab("ADD","SEGMENT","DEFER")="NEGATABLE" i ver'="VMS" s syntab("ADD","SEGMENT","ENCRYPTION_FLAG")="NEGATABLE" s syntab("ADD","SEGMENT","EXTENSION_COUNT")="REQUIRED" s syntab("ADD","SEGMENT","EXTENSION_COUNT","TYPE")="TNUMBER" s syntab("ADD","SEGMENT","FILE_NAME")="REQUIRED" s syntab("ADD","SEGMENT","FILE_NAME","TYPE")="TFSPEC" s syntab("ADD","SEGMENT","GLOBAL_BUFFER_COUNT")="REQUIRED" s syntab("ADD","SEGMENT","GLOBAL_BUFFER_COUNT","TYPE")="TNUMBER" s syntab("ADD","SEGMENT","LOCK_SPACE")="REQUIRED" s syntab("ADD","SEGMENT","LOCK_SPACE","TYPE")="TNUMBER" s syntab("ADD","SEGMENT","RESERVED_BYTES")="REQUIRED" s syntab("ADD","SEGMENT","RESERVED_BYTES","TYPE")="TNUMBER" s syntab("ADD","SEGMENT","WINDOW_SIZE")="REQUIRED" s syntab("ADD","SEGMENT","WINDOW_SIZE","TYPE")="TNUMBER" s syntab("CHANGE","NAME")="" s syntab("CHANGE","NAME","REGION")="REQUIRED" s syntab("CHANGE","NAME","REGION","TYPE")="TREGION" s syntab("CHANGE","REGION")="" s syntab("CHANGE","REGION","COLLATION_DEFAULT")="REQUIRED" s syntab("CHANGE","REGION","COLLATION_DEFAULT","TYPE")="TNUMBER" s syntab("CHANGE","REGION","STDNULLCOLL")="NEGATABLE" s syntab("CHANGE","REGION","DYNAMIC_SEGMENT")="REQUIRED" s syntab("CHANGE","REGION","DYNAMIC_SEGMENT","TYPE")="TSEGMENT" i ver'="VMS" s syntab("CHANGE","REGION","INST_FREEZE_ON_ERROR")="NEGATABLE" s syntab("CHANGE","REGION","JOURNAL")="NEGATABLE,REQUIRED,LIST" s syntab("CHANGE","REGION","JOURNAL","ALLOCATION")="REQUIRED" s syntab("CHANGE","REGION","JOURNAL","ALLOCATION","TYPE")="TNUMBER" s syntab("CHANGE","REGION","JOURNAL","AUTOSWITCHLIMIT")="REQUIRED" s syntab("CHANGE","REGION","JOURNAL","AUTOSWITCHLIMIT","TYPE")="TNUMBER" s syntab("CHANGE","REGION","JOURNAL","BUFFER_SIZE")="REQUIRED" s syntab("CHANGE","REGION","JOURNAL","BUFFER_SIZE","TYPE")="TNUMBER" s syntab("CHANGE","REGION","JOURNAL","BEFORE_IMAGE")="NEGATABLE" s syntab("CHANGE","REGION","JOURNAL","EXTENSION")="REQUIRED" s syntab("CHANGE","REGION","JOURNAL","EXTENSION","TYPE")="TNUMBER" s syntab("CHANGE","REGION","JOURNAL","FILE_NAME")="REQUIRED" s syntab("CHANGE","REGION","JOURNAL","FILE_NAME","TYPE")="TFSPEC" ;s syntab("CHANGE","REGION","JOURNAL","STOP_ENABLED")="NEGATABLE" s syntab("CHANGE","REGION","KEY_SIZE")="REQUIRED" s syntab("CHANGE","REGION","KEY_SIZE","TYPE")="TNUMBER" s syntab("CHANGE","REGION","NULL_SUBSCRIPTS")="NEGATABLE,REQUIRED" s syntab("CHANGE","REGION","NULL_SUBSCRIPTS","TYPE")="TNULLSUB" s syntab("CHANGE","REGION","NULL_SUBSCRIPTS","TYPE","VALUES")=nullsubs i ver'="VMS" s syntab("CHANGE","REGION","QDBRUNDOWN")="NEGATABLE" s syntab("CHANGE","REGION","RECORD_SIZE")="REQUIRED" s syntab("CHANGE","REGION","RECORD_SIZE","TYPE")="TNUMBER" s syntab("CHANGE","SEGMENT")="" s syntab("CHANGE","SEGMENT","ACCESS_METHOD")="REQUIRED" s syntab("CHANGE","SEGMENT","ACCESS_METHOD","TYPE")="TACCMETH" s syntab("CHANGE","SEGMENT","ACCESS_METHOD","TYPE","VALUES")=accmeth s syntab("CHANGE","SEGMENT","ALLOCATION")="REQUIRED" s syntab("CHANGE","SEGMENT","ALLOCATION","TYPE")="TNUMBER" s syntab("CHANGE","SEGMENT","BLOCK_SIZE")="REQUIRED" s syntab("CHANGE","SEGMENT","BLOCK_SIZE","TYPE")="TNUMBER" s syntab("CHANGE","SEGMENT","BUCKET_SIZE")="REQUIRED" s syntab("CHANGE","SEGMENT","BUCKET_SIZE","TYPE")="TNUMBER" s syntab("CHANGE","SEGMENT","DEFER")="NEGATABLE" i ver'="VMS" s syntab("CHANGE","SEGMENT","ENCRYPTION_FLAG")="NEGATABLE" s syntab("CHANGE","SEGMENT","EXTENSION_COUNT")="REQUIRED" s syntab("CHANGE","SEGMENT","EXTENSION_COUNT","TYPE")="TNUMBER" s syntab("CHANGE","SEGMENT","FILE_NAME")="REQUIRED" s syntab("CHANGE","SEGMENT","FILE_NAME","TYPE")="TFSPEC" s syntab("CHANGE","SEGMENT","GLOBAL_BUFFER_COUNT")="REQUIRED" s syntab("CHANGE","SEGMENT","GLOBAL_BUFFER_COUNT","TYPE")="TNUMBER" s syntab("CHANGE","SEGMENT","LOCK_SPACE")="REQUIRED" s syntab("CHANGE","SEGMENT","LOCK_SPACE","TYPE")="TNUMBER" s syntab("CHANGE","SEGMENT","RESERVED_BYTES")="REQUIRED" s syntab("CHANGE","SEGMENT","RESERVED_BYTES","TYPE")="TNUMBER" s syntab("CHANGE","SEGMENT","WINDOW_SIZE")="REQUIRED" s syntab("CHANGE","SEGMENT","WINDOW_SIZE","TYPE")="TNUMBER" s syntab("TEMPLATE","REGION")="" s syntab("TEMPLATE","REGION","COLLATION_DEFAULT")="REQUIRED" s syntab("TEMPLATE","REGION","COLLATION_DEFAULT","TYPE")="TNUMBER" s syntab("TEMPLATE","REGION","STDNULLCOLL")="NEGATABLE" s syntab("TEMPLATE","REGION","DYNAMIC_SEGMENT")="REQUIRED" s syntab("TEMPLATE","REGION","DYNAMIC_SEGMENT","TYPE")="TSEGMENT" i ver'="VMS" s syntab("TEMPLATE","REGION","INST_FREEZE_ON_ERROR")="NEGATABLE" s syntab("TEMPLATE","REGION","JOURNAL")="NEGATABLE,REQUIRED,LIST" s syntab("TEMPLATE","REGION","JOURNAL","ALLOCATION")="REQUIRED" s syntab("TEMPLATE","REGION","JOURNAL","ALLOCATION","TYPE")="TNUMBER" s syntab("TEMPLATE","REGION","JOURNAL","AUTOSWITCHLIMIT")="REQUIRED" s syntab("TEMPLATE","REGION","JOURNAL","AUTOSWITCHLIMIT","TYPE")="TNUMBER" s syntab("TEMPLATE","REGION","JOURNAL","BUFFER_SIZE")="REQUIRED" s syntab("TEMPLATE","REGION","JOURNAL","BUFFER_SIZE","TYPE")="TNUMBER" s syntab("TEMPLATE","REGION","JOURNAL","BEFORE_IMAGE")="NEGATABLE" s syntab("TEMPLATE","REGION","JOURNAL","EXTENSION")="REQUIRED" s syntab("TEMPLATE","REGION","JOURNAL","EXTENSION","TYPE")="TNUMBER" s syntab("TEMPLATE","REGION","JOURNAL","FILE_NAME")="REQUIRED" s syntab("TEMPLATE","REGION","JOURNAL","FILE_NAME","TYPE")="TFSPEC" ;s syntab("TEMPLATE","REGION","JOURNAL","STOP_ENABLED")="NEGATABLE" s syntab("TEMPLATE","REGION","KEY_SIZE")="REQUIRED" s syntab("TEMPLATE","REGION","KEY_SIZE","TYPE")="TNUMBER" s syntab("TEMPLATE","REGION","NULL_SUBSCRIPTS")="NEGATABLE,REQUIRED" s syntab("TEMPLATE","REGION","NULL_SUBSCRIPTS","TYPE")="TNULLSUB" s syntab("TEMPLATE","REGION","NULL_SUBSCRIPTS","TYPE","VALUES")=nullsubs i ver'="VMS" s syntab("TEMPLATE","REGION","QDBRUNDOWN")="NEGATABLE" s syntab("TEMPLATE","REGION","RECORD_SIZE")="REQUIRED" s syntab("TEMPLATE","REGION","RECORD_SIZE","TYPE")="TNUMBER" s syntab("TEMPLATE","SEGMENT")="" s syntab("TEMPLATE","SEGMENT","ACCESS_METHOD")="REQUIRED" s syntab("TEMPLATE","SEGMENT","ACCESS_METHOD","TYPE")="TACCMETH" s syntab("TEMPLATE","SEGMENT","ACCESS_METHOD","TYPE","VALUES")=accmeth s syntab("TEMPLATE","SEGMENT","ALLOCATION")="REQUIRED" s syntab("TEMPLATE","SEGMENT","ALLOCATION","TYPE")="TNUMBER" s syntab("TEMPLATE","SEGMENT","BLOCK_SIZE")="REQUIRED" s syntab("TEMPLATE","SEGMENT","BLOCK_SIZE","TYPE")="TNUMBER" s syntab("TEMPLATE","SEGMENT","BUCKET_SIZE")="REQUIRED" s syntab("TEMPLATE","SEGMENT","BUCKET_SIZE","TYPE")="TNUMBER" s syntab("TEMPLATE","SEGMENT","DEFER")="NEGATABLE" i ver'="VMS" s syntab("TEMPLATE","SEGMENT","ENCRYPTION_FLAG")="NEGATABLE" s syntab("TEMPLATE","SEGMENT","EXTENSION_COUNT")="REQUIRED" s syntab("TEMPLATE","SEGMENT","EXTENSION_COUNT","TYPE")="TNUMBER" s syntab("TEMPLATE","SEGMENT","FILE_NAME")="REQUIRED" s syntab("TEMPLATE","SEGMENT","FILE_NAME","TYPE")="TFSPEC" s syntab("TEMPLATE","SEGMENT","GLOBAL_BUFFER_COUNT")="REQUIRED" s syntab("TEMPLATE","SEGMENT","GLOBAL_BUFFER_COUNT","TYPE")="TNUMBER" s syntab("TEMPLATE","SEGMENT","LOCK_SPACE")="REQUIRED" s syntab("TEMPLATE","SEGMENT","LOCK_SPACE","TYPE")="TNUMBER" s syntab("TEMPLATE","SEGMENT","RESERVED_BYTES")="REQUIRED" s syntab("TEMPLATE","SEGMENT","RESERVED_BYTES","TYPE")="TNUMBER" s syntab("TEMPLATE","SEGMENT","WINDOW_SIZE")="REQUIRED" s syntab("TEMPLATE","SEGMENT","WINDOW_SIZE","TYPE")="TNUMBER" s syntab("DELETE","NAME")="" s syntab("DELETE","REGION")="" s syntab("DELETE","SEGMENT")="" s syntab("EXIT")="" s syntab("HELP")="" s syntab("LOCKS","REGION")="REQUIRED" s syntab("LOCKS","REGION","TYPE")="TREGION" s syntab("LOG","OFF")="" s syntab("LOG","ON")="OPTIONAL" s syntab("LOG","ON","TYPE")="TFSPEC" s syntab("SETGD","FILE")="REQUIRED" s syntab("SETGD","FILE","TYPE")="TFSPEC" s syntab("SETGD","QUIT")="" s syntab("QUIT")="" s syntab("RENAME","NAME")="" s syntab("RENAME","REGION")="" s syntab("RENAME","SEGMENT")="" s syntab("SHOW")="" s syntab("SHOW","ALL")="" s syntab("SHOW","TEMPLATE")="" s syntab("SHOW","MAP")="" s syntab("SHOW","MAP","REGION")="REQUIRED" s syntab("SHOW","MAP","REGION","TYPE")="TREGION" s syntab("SHOW","NAME")="" s syntab("SHOW","REGION")="" s syntab("SHOW","SEGMENT")="" s syntab("SHOW","COMMANDS")="" s syntab("SHOW","COMMANDS","FILE")="OPTIONAL" s syntab("SHOW","COMMANDS","FILE","TYPE")="TFSPEC" s syntab("SPAWN")="" s syntab("VERIFY","ALL")="" s syntab("VERIFY","MAP")="" s syntab("VERIFY","NAME")="" s syntab("VERIFY","REGION")="" s syntab("VERIFY","SEGMENT")="" s syntab("VERIFY","TEMPLATE")="" q VMS s endian=FALSE s hdrlab="GTCGBLDIR009" ; must be concurrently maintained in gbldirnam.h!!! s tfile="GTM$GBLDIR" s accmeth="\BG\MM\USER" s helpfile="GTM$HELP:GDE.HLB" s defdb="MUMPS" s defgld="MUMPS.GLD",defgldext=".GLD" s defreg="$DEFAULT" s defseg="$DEFAULT" s dbfilpar=".1AN.1""-"".1""_"".1"":"".1""$"".1""["".1""]"".1""<"".1"">"".1""."".1"";""" s filexfm="$tr(filespec,lower,upper)" s sep="TKSLASH" q UNIX: s hdrlab="GTCGBDUNX008" ; must be concurrently maintained in gbldirnam.h!!! i (gtm64=TRUE) s hdrlab="GTCGBDUNX108" ; the high order digit is a 64-bit flag s tfile="$gtmgbldir" s accmeth="\BG\MM" s helpfile="$gtm_dist/gdehelp.gld" s defdb="mumps.dat" s defgld="mumps.gld",defgldext="*.gld" s defreg="DEFAULT" s defseg="DEFAULT" s dbfilpar="1E" s filexfm="filespec" s sep="TKDASH" q fis-gtm-V6.0-003/sr_port/gdelocks.m0000644000032200000250000000100712201176156016002 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; locks: ;implement the verb: LOCKS LOCKS s update=1 s nams("#")=gqual("value") q fis-gtm-V6.0-003/sr_port/gdelog.m0000644000032200000250000000134712201176156015457 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; log: ;implement the verb: LOG LOG i gqual="OFF" s log=0 zm gdeerr("LOGOFF"):logfile q s log=1 i $d(gqual("value")) s logfile=$zparse(gqual("value"),"","",".LOG") o logfile:(newversion:noreadonly) zm gdeerr("LOGON"):logfile q INQUIRE i 'log zm gdeerr("NOLOG"):logfile e zm gdeerr("LOGON"):logfile q fis-gtm-V6.0-003/sr_port/gdemap.m0000644000032200000250000002747212201176156015462 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2010, 2013 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; map: ;create maps for put and show, names for get and show PUTMAKE k lexnams n t1 d SHOWMAKE s s1=$ztr($zj("",SIZEOF("mident"))," ",$zch(255)),t1=$ztr($zj("",SIZEOF("mident"))," ",$zch(0)) f s s2=s1,s1=$o(map(s1),-1),map(s2_$ze(t1,$zl(s2)+1,SIZEOF("mident")))=map(s1) q:s1="$" k map(s1) s map("#)"_$ze(t1,3,SIZEOF("mident")))=map("#)"),map("%"_$ze(t1,2,SIZEOF("mident")))=map("$") f s2="#","#)","$" k map(s2) q ;---------------------------------------------------------------------------------------------------------------------------------- SHOWMAKE n lexnams s s="" f s s=$o(nams(s)) q:'$zl(s) d lexins(s) s map("$")=nams("*"),map("#")=nams("#") s i=1 f s i=$o(lexnams(i)) q:'$zl(i) d showstar(i) s s="" f s s=$o(lexnams(0,s),-1) q:'$zl(s) d pointins(s,lexnams(0,s)) s s1=$o(map(""),-1) f s s2=s1,s1=$o(map(s1),-1) q:s2="$" i map(s1)=map(s2) k map(s2) q ;---------------------------------------------------------------------------------------------------------------------------------- SHOWNAM n lexnams,t1,map d SHOWMAKE s s1=$ztr($zj("",SIZEOF("mident"))," ",$zch(255)),t1=$ztr($zj("",SIZEOF("mident"))," ",$zch(0)) f s s2=s1,s1=$o(map(s1),-1),map(s2)=map(s1) q:s1="$" k map(s1) k map("#") i '$$MAP2NAM(.map) zm gdeerr("GDECHECK")\2*2 q ;---------------------------------------------------------------------------------------------------------------------------------- MAP2NAM(list) n maxMap,currMap,currMapLen,prevMap,prevMapLen,currReg,prevPrefix,currPrefix n namSpc,currNam,currNamLen,stopLoop,i,startMap,midentSize,prevPrevMap s currMap=$o(list("")) q:currMap'="#)" 0 s currMap=$o(list(currMap)) i currMap="%" s list("$")=list("%") ; if "$" is missing, assign it the same value as "%" e q:currMap'="$" 0 s maxMap=$ztr($zj("",SIZEOF("mident"))," ",$zch(255)),currMap=$o(list(""),-1) q:currMap'=maxMap 0 k nams f q:currMap="$" s prevMap=$o(list(currMap),-1) d s currMap=prevMap . s currReg=list(currMap) . ; Note that with the above mapping, all keys in the range [prevMap,currMap) are mapped to currReg. . ; where [ denotes closed interval and ) denotes open interval i.e. prevMap <= key < currMap . ; Case (1a) : If currMap contains ")" (e.g. "abc)"), it most likely means prevMap would be "abc". . ; In this case, just add "abc" as a namespace. No more processing needed for currMap. . ; Case (1b) : But it is also possible prevMap is not "abc". . ; In this case, do the "abc" namespace addition (as if prevMap was "abc"). . ; But also proceed with the current iteration of the for loop as if "currMap" was "abc". . s currMapLen=$zl(currMap) . i $ze(currMap,currMapLen)=")" d q:prevMap=namSpc . . s namSpc=$ze(currMap,1,currMapLen-1),nams(namSpc)=currReg . . i prevMap'=namSpc s currMap=namSpc,currMapLen=currMapLen-1 . ; Case (3) : If prevMap contains ")" (e.g. "abc)"), then check to see if its previous entry (say prevPrevMap) . ; is the same region as currReg. If so, we can coalesce the entire range [prevPrevMap,currMap) into one with the . ; exception of "abc" for which add an explicit namespace. Do this for as many ")" prevMap entries that you can find . ; as long as its prevPrevMap entry is the same region as currReg. This could potentially coalesce a lot of intervals. . ; Note: Need to handle a situation like Case (1b) here too. We do this by keeping prevMap as it is but adjusting . ; just prevMapLen to be 1 byte less (to remove trailing ")"). . s stopLoop=0 . f d q:stopLoop . . s prevMapLen=$zl(prevMap) . . i $ze(prevMap,prevMapLen)'=")" s stopLoop=1 q . . s namSpc=$ze(prevMap,1,$i(prevMapLen,-1)) . . s prevPrevMap=$o(list(prevMap),-1) . . i prevPrevMap'=namSpc s stopLoop=1 q . . s nams(namSpc)=list(prevMap) . . i list(prevMap)'=currReg s stopLoop=1 q . . s prevMap=$o(list(prevMap),-1) . . i prevMap="$" s stoploop=1,prevMapLen=1 q . ; Note: At this point prevMap could contain a trailing ")" but in that case prevMapLen would have been adjusted to . ; not consider that last byte. As long as all following usages of prevMap are of the form $ze(prevMap,1,prevMapLen) . ; we will never see the ")" in prevMap. . ; Case (4) : The map entry "currMap" exists and "prevMap" is the previous map entry. . ; Determine the namespaces that potentially lie between the two map entries. . ; And add them to the "nams" array. . f i=1:1:currMapLen i $ze(currMap,i)'=$ze(prevMap,i) q . s matchLen=i-1 ; the length of the maximal common prefix between prevMap and currMap . ; Subcase (4a) : matchLen == prevMapLen . ; In this case we are guaranteed that prevMapLen < currMapLen, and we need to add only ONE namespace. . ; Example prevMap="ag", currMap="agk". Here, matchLen=2, prevMapLen=2, currMapLen=3. Add only "ag*". . i (matchLen=prevMapLen)&(prevMapLenprevMapLen d . . s currPrefix=prevPrefix_"z",prevPrefix=$ze(prevMap,1,i) . . f q:currPrefix=prevPrefix s namSpc=currPrefix_"*",nams(namSpc)=currReg,currPrefix=$$lexprev(currPrefix) . . ; Do optimization check at each sub-namespaces level. If it succeeds, stop processing any higher level sub-namespaces. . . s startMap=$$findStartMap(currPrefix) . . i list(startMap)=currReg s i=prevMapLen q ; set i to force quit out of for loop . s namSpc=currPrefix_"*",nams(namSpc)=currReg ; Update "nams" variable to contain # of elements in "nams" array ; Take this opportunity to remove redundant namespaces. ; Example : If "a*" and "ab*" both map to the same region, the namespace "ab*" can be safely removed. ; But if "a*" maps to AREG, "aa*" maps to BREG, and "aaa*" maps to AREG, we cannot remove "aaa*" because ; "a*" and "aaa*" maps to the same reg. This is because there is a more restrictive mapping "aa*" which ; maps to a different region than "aaa*". That should prevail. ; Similarly if "ab*" and "abc" both map to the same region, the namespace "abc" can be safely removed. ; But if "abc*" also is mapped and to a different region than "abc", then "abc" cannot be removed. s currNam="",nams=0 ; With SIZEOF("mident")=32, we allow a max of 31-byte global name specifications. ; But with SIZEOF("mident")=8 (for older versions with no longnames support, we allow a max of 8-byte global names. ; Handle this 1-byte discrepancy for the 8-byte case by setting the variable midentSize accordingly. s midentSize=$s(SIZEOF("mident")=8:9,1:SIZEOF("mident")) s nams("*")=list("$") f s currNam=$o(nams(currNam)) q:currNam="" s nams=nams+1 d . s currNamLen=$zl(currNam) . s currReg=nams(currNam) . s killed=0,quitLoop=0 . f i=$s($ze(currNam,currNamLen)="*":(currNamLen-2),1:currNamLen):-1:0 d q:quitLoop . . s currPrefix=$ze(currNam,1,i)_"*" . . s prevReg=$g(nams(currPrefix)) . . i (""'=prevReg) d . . . s quitLoop=1 . . . i currReg=prevReg k nams(currNam) s nams=nams-1,killed=1 . i 'killed,currNamLen'(SIZEOF("file_spec")-1) zm gdeerr("VALUEBAD"):filespec:"file specification" i '$l($zparse(filespec,"","","","SYNTAX_ONLY")) zm gdeerr("VALUEBAD"):filespec:"file specification" s @("value="_$s($l(filexfm):filexfm,1:filespec)) ; do system specific file name translation q TFSPECP ; scan filespec token by token n c,cp1 ; unix filenames must be quoted to avoid / conflicts with qualifiers s cp1=cp-$l(ntoken) f i=0:1 s c=$e(comline,cp1+i) q:c'?@dbfilpar!'$l(c) s filespec=$e(comline,cp1,cp1+i-1),cp=cp1+i q TACCMETH d GETTOK^GDESCAN i toktype'="TKIDENT" zm gdeerr("VALUEBAD"):token:qual s value=$tr(token,lower,upper) i @s@(qual,"TYPE","VALUES")'[("\"_value) zm gdeerr("VALUEBAD"):token:qual q TNULLSUB d GETTOK^GDESCAN i toktype'="TKIDENT" zm gdeerr("VALUEBAD"):token:qual s value=$tr(token,lower,upper) i @s@(qual,"TYPE","VALUES")'[("\"_value) zm gdeerr("VALUEBAD"):token:qual q TREGION n REGION d REGION s value=REGION q TSEGMENT n SEGMENT d SEGMENT s value=SEGMENT q NAME k NAME i ntoktype="TKEOL" zm gdeerr("OBJREQD"):"name" n c,cp1 s cp1=cp-$l(ntoken) f i=0:1 s c=$e(comline,cp1+i) q:c'?.1"%".1AN.1"*"!'$l(c) s NAME=$e(comline,cp1,cp1+i-1),cp=cp1+i d GETTOK^GDESCAN ; put the scanner back on track i '$l(NAME) zm gdeerr("VALUEBAD"):token:"name" i $l(NAME)'=$zl(NAME) zm gdeerr("NONASCII"):NAME:"name" ; error if the name is non-ascii i NAME'="*" s x=$e(NAME) i x'="%",x'?1A zm gdeerr("NAMSTARTBAD"):NAME i $e(NAME,2,999)'?.AN.1"*" zm gdeerr("VALUEBAD"):NAME:"name" i $l(NAME)>PARNAMLN zm gdeerr("VALTOOLONG"):NAME:PARNAMLN:"name" q REGION k REGION i ntoktype="TKEOL" zm gdeerr("OBJREQD"):renpref_"region" n c,cp1 s cp1=cp-$l(ntoken) f i=0:1 s c=$e(comline,cp1+i) q:c'?.1AN.1"$".1"_"!'$l(c) s REGION=$tr($e(comline,cp1,cp1+i-1),lower,upper),cp=cp1+i d GETTOK^GDESCAN ; put the scanner back on track i '$l(REGION) zm gdeerr("VALUEBAD"):token:renpref_"region" i $l(REGION)'=$zl(REGION) zm gdeerr("NONASCII"):REGION:"region" ; error if the name of the region is non-ascii i REGION=defreg q s x=$e(REGION) i x'?1A zm gdeerr("PREFIXBAD"):REGION:renpref_"region" i $l(REGION)>PARREGLN zm gdeerr("VALTOOLONG"):REGION:PARREGLN:renpref_"region" q SEGMENT k SEGMENT i ntoktype="TKEOL" zm gdeerr("OBJREQD"):renpref_"segment" n c,cp1 s cp1=cp-$l(ntoken) f i=0:1 s c=$e(comline,cp1+i) q:c'?.1AN.1"$".1"_"!'$l(c) s SEGMENT=$tr($e(comline,cp1,cp1+i-1),lower,upper),cp=cp1+i d GETTOK^GDESCAN ; put the scanner back on track i '$l(SEGMENT) zm gdeerr("VALUEBAD"):token:renpref_"segment" i $l(SEGMENT)'=$zl(SEGMENT) zm gdeerr("NONASCII"):SEGMENT:"segment" ; error if the name of the segment is non-ascii i SEGMENT=defseg q s x=$e(SEGMENT) i x'?1A zm gdeerr("PREFIXBAD"):SEGMENT:renpref_"segment" i $l(SEGMENT)>PARSEGLN zm gdeerr("VALTOOLONG"):SEGMENT:PARSEGLN:renpref_"segment" q matchtok:(tok,ent) d GETTOK^GDESCAN i toktype=tok q zm gdeerr("VALUEBAD"):token:ent q checkkw:(kw,ent,kwlist) n x1,x2 s kw=$tr(kw,lower,upper) i $e(kw,1,2)="NO" s negated=1,kw=$e(kw,3,999) e s negated=0 s x1="" f s x1=$o(@kwlist@(x1)) q:kw=$e(x1,1,$l(kw))!'$l(x1) i '$l(x1) zm gdeerr("KEYWRDBAD"):kw:ent s x2=x1 f s x2=$o(@kwlist@(x2)) q:kw=$e(x2,1,$l(kw))!'$l(x2) i $l(x2) zm gdeerr("KEYWRDAMB"):kw:ent s kw=x1 q getqual: d qual(.lqual,"Local qualifier","syntab("""_verb_""","""_gqual_""")") i '$d(lquals(lqual)) s lquals(lqual)=$g(lqual("value")) e zm gdeerr("QUALDUP"):lqual q getlitm: d qual(.lqual,"Local qualifier","syntab("""_verb_""","""_gqual_""","""_lhead_""")") i '$d(lquals(lqual)) s lquals(lqual)=$g(lqual("value")) e zm gdeerr("QUALDUP"):lqual q ;----------------------------------------------------------------------------------------------------------------------------------- ADD CHANGE d qual(.gqual,"Global qualifier","syntab("""_verb_""")"),@gqual f q:ntoktype="TKEOL" d getqual d @gqual^@("GDE"_$e(verb,1,5)) q RENAME d qual(.gqual,"Global qualifier","syntab("""_verb_""")") n renpref s renpref="old " d @gqual s old=@gqual s renpref="new " d @gqual s new=@gqual s renpref="" d matchtok("TKEOL","End of line") d @gqual^GDERENAM(old,new) q TEMPLATE d qual(.gqual,"Global qualifier","syntab("""_verb_""")") f q:ntoktype="TKEOL" d getqual d @gqual^GDETEMPL q DELETE d qual(.gqual,"Global qualifier","syntab("""_verb_""")"),@gqual,matchtok("TKEOL","End of line"),@gqual^GDEDELET q LOCKS d qual(.gqual,"Global qualifier","syntab("""_verb_""")"),matchtok("TKEOL","End of line"),LOCKS^GDELOCKS q LOG i ntoktype="TKEOL" d INQUIRE^GDELOG q d qual(.gqual,"Global qualifier","syntab("""_verb_""")"),matchtok("TKEOL","End of line"),LOG^GDELOG q SHOW i ntoktype="TKEOL" d ALL^GDESHOW q d qual(.gqual,"Global qualifier","syntab("""_verb_""")") s t="NAMEREGIONSEGMENT"[gqual i t,ntoktype="TKEOL" d @("ALL"_$e(gqual,1,5))^GDESHOW q n mapreg i gqual="MAP",ntoktype'="TKEOL" d getqual s mapreg=$g(lquals("REGION")) i 't,"COMMANDS"=gqual,ntoktype'="TKEOL" d getqual s cfile=$g(lquals("FILE")) d @gqual:t,matchtok("TKEOL","End of line"),@gqual^GDESHOW q VERIFY i ntoktype="TKEOL" s x=$$ALL^GDEVERIF q d qual(.gqual,"Global qualifier","syntab("""_verb_""")") i "ALL|MAP"[gqual s x=$$ALL^GDEVERIF q n verified s verified=1 i ntoktype="TKEOL" d @("ALL"_$e(gqual,1,3))^GDEVERIF i 1 e i "NAMEREGIONSEGMENT"[gqual d @gqual,@gqual^GDEVERIF i 1 e zm gdeerr("NOVALUE"):gqual i $d(verified) zm gdeerr("VERIFY"):$s(verified:"OK",1:"FAILED") w ! q EXIT QUIT d matchtok("TKEOL","End of line") d ^@("GDE"_$tr(verb,lower,upper)) q SETGD f d q:ntoktype="TKEOL" . d qual(.gqual,"Global qualifier","syntab("""_verb_""")") s:gqual="FILE" tfile=gqual("value") s:gqual="QUIT" update=0 d GDESETGD^GDESETGD q HELP SPAWN d ^@("GDE"_$tr(verb,lower,upper)) q fis-gtm-V6.0-003/sr_port/gdequit.m0000644000032200000250000000101712201176156015652 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; quit: ;implement the verb: QUIT QUIT zm gdeerr("NOACTION"):$zparse(tfile,"",defgldext) h fis-gtm-V6.0-003/sr_port/gderenam.m0000644000032200000250000000275012201176156015777 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rename: ;implement the verb: RENAME NAME(old,new) i old=new q i old="*" zm gdeerr("LVSTARALON") i '$d(nams(old)) d error1 i $d(nams(new)) d error2 s update=1,nams(new)=nams(old),s="" f s s=$o(nams(old,s)) q:'$l(s) s nams(new,s)=nams(old,s) k nams(old) q REGION(old,new) i old=new q i '$d(regs(old)) d error1 i $d(regs(new)) d error2 s update=1,s="" f s s=$o(regs(old,s)) q:'$l(s) s regs(new,s)=regs(old,s) k regs(old) f s s=$o(nams(s)) q:'$l(s) i nams(s)=old s nams(s)=new q SEGMENT(old,new) i old=new q i '$d(segs(old)) d error1 i $d(segs(new)) d error2 n lquals s update=1,am=segs(old,"ACCESS_METHOD"),s="" f s s=$o(segs(old,s)) q:'$l(s) s segs(new,s)=segs(old,s),lquals(s)=segs(old,s) i '$$SQUALS^GDEVERIF(am,.lquals) k segs(new) zm gdeerr("OBJNOTCHG"):"segment":old s segs(new,"ACCESS_METHOD")=am k segs(old) f s s=$o(regs(s)) q:'$l(s) i regs(s,"DYNAMIC_SEGMENT")=old s regs(s,"DYNAMIC_SEGMENT")=new q error1: zm gdeerr("OBJNOTFND"):"Old "_$tr(gqual,upper,lower):old q error2: zm gdeerr("OBJDUP"):"New "_$tr(gqual,upper,lower):new q fis-gtm-V6.0-003/sr_port/gdescan.m0000644000032200000250000000323612201176156015621 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001, 2010 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; gdescan: ;scanner used by gdeparse GETTOK n c s token=ntoken,toktype=ntoktype f cp=cp:1 s c=$e(comline,cp) q:(c'=" ")&(c'=TAB) i $c(10,13)[c,cp=$l(comline) s c="" s ntoktype=$s(c?1A:"TKIDENT",c?1N:"TKNUMLIT",c="":"TKEOL",$d(tokens(c)):tokens(c),1:"TKOTHER") d @ntoktype q shotoks: ; for debugging only w !," toktype: ",toktype,?24," token: '",token,"'" w ?48," ntoktype: ",ntoktype,?72,"ntoken: '",ntoken,"'" q TKIDENT n i f i=1:1 s c=$e(comline,cp+i) q:(c'?1A)&(c'="_") s ntoken=$e(comline,cp,cp+i-1),cp=cp+i q TKNUMLIT n i f i=1:1 q:$e(comline,cp+i)'?1N s ntoken=$e(comline,cp,cp+i-1),cp=cp+i q TKSTRLIT n i f i=1:1:$l(comline)-cp q:$e(comline,cp+i)="""" s ntoken=$e(comline,cp,cp+i),cp=cp+i+1 q TKAMPER TKASTER TKCOLON TKCOMMA TKDASH ; see below for more UNIXy alternative TKDOLLAR TKEQUAL TKLANGLE TKLBRACK TKLPAREN TKPCT TKPERIOD TKRANGLE TKRBRACK TKRPAREN TKSCOLON TKSLASH TKUSCORE s ntoken=c,cp=cp+1 q TKEXCLAM s ntoktype="TKEOL" s ntoken="" s cp=$l(comline) q ;TKDASH - more UNIXy handling disabled for compatibility with other utilities s ntoken=c,cp=cp+1 i sep="TKDASH",$e(comline,cp)?1A s c=$e(comline,cp-2) i c=" "!(c=TAB) q zm gdeerr("ILLCHAR"):"-" q TKEOL s ntoken="" q TKOTHER zm gdeerr("ILLCHAR"):c fis-gtm-V6.0-003/sr_port/gdesetgd.m0000644000032200000250000000176512201176156016010 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; gdesetgd: ;implement the verb: SETGD GDESETGD i update,'$$ALL^GDEVERIF zm gdeerr("GDNOTSET") q i update,'$$GDEPUT^GDEPUT zm gdeerr("GDNOTSET") q d GDFIND,CREATE^GDEGET:create,LOAD^GDEGET:'create q GDFIND s file=$zparse(tfile,"",defgldext) i file="" s file=$ztrnlnm(tfile) s:file="" file=tfile zm gdeerr("INVGBLDIR"):file:defgld s tfile=defgld s file=$zsearch($zparse(tfile,"",defgldext)) i file="" s file=$zsearch($zparse(tfile,"",defgldext)) i file="" s file=$zparse(tfile,"",defgldext),create=1 zm gdeerr("GDUSEDEFS"):file e s create=0 zm gdeerr("LOADGD"):file q fis-gtm-V6.0-003/sr_port/gdeshow.m0000644000032200000250000003257612201176156015666 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001, 2013 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; show: ;implement the verb: SHOW ALL d TEMPLATE,ALLNAME,ALLREGIO,ALLSEGME,MAP q COMMANDS s BOL="!" set delim=$select("VMS"=ver:"/",1:"-") i $l($get(cfile)) o cfile:(newversion:exc="w !,$ztatus c cfile zgoto $zl:cfilefail") u cfile d . d namec,segmentc,regionc,templatec . c cfile cfilefail: f i="@useio",$s(log:"@uself",1:"") q:'$l(i) u @i d templatec,namec,regionc,segmentc s BOL="" q NAME i '$d(nams(NAME)) zm gdeerr("OBJNOTFND"):"Name":NAME q d n2 i log s BOL="!" u @uself w BOL d n2 w ! u @useio s BOL="" q n2: d namehd w !,BOL,?x(1),NAME,?x(2),nams(NAME) q ALLNAME d SHOWNAM^GDEMAP d n1 i log s BOL="!" u @uself w BOL d n1 w ! u @useio s BOL="" q n1: d namehd s s="#" f s s=$o(nams(s)) q:'$l(s) w !,BOL,?x(1),s,?x(2),nams(s) q namec: d SHOWNAM^GDEMAP s s="#" w !,"LOCKS "_delim_"REGION=",nams(s) f s s=$o(nams(s)) q:'$l(s) d . i "*"'=s w !,"ADD "_delim_"NAME ",s," "_delim_"REGION=",nams(s) q . i defreg'=nams(s) w !,"CHANGE "_delim_"NAME "_s_" "_delim_"REGION=",nams(s) w ! q REGION i '$d(regs(REGION)) zm gdeerr("OBJNOTFND"):"Region":REGION q d r2 i log s BOL="!" u @uself w BOL d r2 w ! u @useio s BOL="" q r2: d regionhd s s=REGION d onereg i regs(s,"JOURNAL") d jnlhd d onejnl q ALLREGIO d r1 i log s BOL="!" u @uself w BOL d r1 w ! u @useio s BOL="" q r1: d regionhd s jnl=0,s="" f s s=$o(regs(s)) q:'$l(s) d onereg i regs(s,"JOURNAL") s jnl=1 i jnl d jnlhd s s="" f s s=$o(regs(s)) q:'$l(s) i regs(s,"JOURNAL") d onejnl q onereg: w !,BOL,?x(1),s,?x(2),regs(s,"DYNAMIC_SEGMENT"),?x(3),$j(regs(s,"COLLATION_DEFAULT"),4) i ver'="VMS" w ?x(4),$j(regs(s,"RECORD_SIZE"),7) e w ?x(4),$j(regs(s,"RECORD_SIZE"),5) w ?x(5),$j(regs(s,"KEY_SIZE"),5) w ?x(6),$s(regs(s,"NULL_SUBSCRIPTS")=1:"ALWAYS",regs(s,"NULL_SUBSCRIPTS")=2:"EXISTING",1:"NEVER") w ?x(7),$s(regs(s,"STDNULLCOLL"):"Y",1:"N") w ?x(8),$s(regs(s,"JOURNAL"):"Y",1:"N") i ver'="VMS" w ?x(9),$s(regs(s,"INST_FREEZE_ON_ERROR"):"ENABLED",1:"DISABLED") i ver'="VMS" w ?x(10),$s(regs(s,"QDBRUNDOWN"):"ENABLED",1:"DISABLED") q onejnl: w !,BOL,?x(1),s,?x(2),$s($l(regs(s,"FILE_NAME")):regs(s,"FILE_NAME"),1:"") i $x'<(x(3)-1) w !,BOL w ?x(3),$s(regs(s,"BEFORE_IMAGE"):"Y",1:"N"),?x(4),$j(regs(s,"BUFFER_SIZE"),5) w ?x(5),$j(regs(s,"ALLOCATION"),10) i ver="VMS" w ?x(6),$j(regs(s,"EXTENSION"),5) e w ?x(6),$j(regs(s,"EXTENSION"),10),?x(7),$j(regs(s,"AUTOSWITCHLIMIT"),13) w !,BOL q regionc: n defseen,cmd s s="",defseen=FALSE f s s=$o(regs(s)) q:'$l(s) d . i s=defreg s defseen=TRUE,cmd="CHANGE" . e s cmd="ADD" . w !,cmd," "_delim_"REGION ",s," "_delim_"DYNAMIC=",regs(s,"DYNAMIC_SEGMENT") . f q="COLLATION_DEFAULT","RECORD_SIZE","KEY_SIZE" w " "_delim,q,"=",regs(s,q) . w " "_delim_"NULL_SUBSCRIPTS=",$s(regs(s,"NULL_SUBSCRIPTS")=1:"ALWAYS",regs(s,"NULL_SUBSCRIPTS")=2:"EXISTING",1:"NEVER") . i regs(s,"STDNULLCOLL") w " "_delim_"STDNULLCOLL" . i regs(s,"JOURNAL") d .. w " "_delim_"JOURNAL=(",$s(regs(s,"BEFORE_IMAGE"):"",1:"NO"),"BEFORE_IMAGE",",BUFFER_SIZE=",regs(s,"BUFFER_SIZE") .. w ",ALLOCATION=",regs(s,"ALLOCATION"),",EXTENSION=",regs(s,"EXTENSION") .. i ver'="VMS" w ",AUTOSWITCHLIMIT=",regs(s,"AUTOSWITCHLIMIT") .. i $l(regs(s,"FILE_NAME")) w ",FILE=""",regs(s,"FILE_NAME"),"""" .. w ")" . else w " "_delim_"NOJOURNAL" . i (ver'="VMS") w " "_delim_$s(regs(s,"INST_FREEZE_ON_ERROR"):"",1:"NO")_"INST_FREEZE_ON_ERROR" . i (ver'="VMS") w " "_delim_$s(regs(s,"QDBRUNDOWN"):"",1:"NO")_"QDBRUNDOWN" i (FALSE=defseen) w !,"DELETE "_delim_"REGION "_defreg w !,BOL q SEGMENT i '$d(segs(SEGMENT)) zm gdeerr("OBJNOTFND"):"Segment":SEGMENT q d s2 i log s BOL="!" u @uself w BOL d s2 w ! u @useio s BOL="" q s2: d seghd s s=SEGMENT s am=segs(s,"ACCESS_METHOD") d oneseg q ALLSEGME d s1 i log s BOL="!" u @uself w BOL d s1 w ! u @useio s BOL="" q s1: d seghd s s="" f s s=$o(segs(s)) q:'$l(s) s am=segs(s,"ACCESS_METHOD") d oneseg q oneseg: w !,BOL,?x(1),s,?x(2),segs(s,"FILE_NAME") i $x'<(x(3)-1) w !,BOL w ?x(3),segs(s,"ACCESS_METHOD") i am="USER" q w ?x(4),$s(segs(s,"FILE_TYPE")="DYNAMIC":"DYN",1:"STA") w ?x(5),$j(segs(s,"BLOCK_SIZE"),5),?x(6),$j(segs(s,"ALLOCATION"),10),?x(7),$j(segs(s,"EXTENSION_COUNT"),5) d @am q BG w ?x(8),"GLOB=",$j(segs(s,"GLOBAL_BUFFER_COUNT"),4) w !,BOL,?x(8),"LOCK=",$j(segs(s,"LOCK_SPACE"),4) w !,BOL,?x(8),"RES =",$j(segs(s,"RESERVED_BYTES"),4) ; For non-encryption platforms, always show FLAG as OFF. For VMS dont even display this line i $ZVersion'["VMS" w !,BOL,?x(8),"ENCR=",$S((encsupportedplat=TRUE&segs(s,"ENCRYPTION_FLAG")):"ON",1:"OFF") q MM w ?x(8),$s(segs(s,"DEFER"):"DEFER",1:"NODEFER") w !,BOL,?x(8),"LOCK=",$j(segs(s,"LOCK_SPACE"),4) w !,BOL,?x(8),"RES = ",$j(segs(s,"RESERVED_BYTES"),4) i $ZVersion'["VMS" w !,BOL,?x(8),"ENCR=OFF" q segmentc: n defseen,cmd s s="",defseen=FALSE f s s=$o(segs(s)) q:'$l(s) s am=segs(s,"ACCESS_METHOD") d . i s=defseg s defseen=TRUE,cmd="CHANGE" . e s cmd="ADD" . w !,cmd," "_delim_"SEGMENT ",s," "_delim_"ACCESS_METHOD=",segs(s,"ACCESS_METHOD") . i am="USER" q . f q="BLOCK_SIZE","ALLOCATION","EXTENSION_COUNT","LOCK_SPACE","RESERVED_BYTES" w " "_delim,q,"=",segs(s,q) . i "BG"=am d .. w " "_delim_"GLOBAL_BUFFER_COUNT=",segs(s,"GLOBAL_BUFFER_COUNT") .. i $zver'["VMS",encsupportedplat=TRUE,segs(s,"ENCRYPTION_FLAG") w " "_delim_"ENCRYPT" . i "MM"=am w " "_delim,$s(segs(s,"DEFER"):"DEFER",1:"NODEFER") . w " "_delim_"FILE=",segs(s,"FILE_NAME") i (FALSE=defseen) w !,"DELETE "_delim_"SEGMENT "_defseg w !,BOL q MAP n map i '$d(mapreg) n mapreg s mapreg="" e i '$d(regs(mapreg)) zm gdeerr("OBJNOTFND"):"Region":mapreg q d SHOWMAKE^GDEMAP d m1 i log s BOL="!" u @uself w BOL d m1 w ! u @useio s BOL="" q m1: n l1,s1,s2 d maphd s s1=$o(map("$")) i s1'="%" s map("%")=map("$"),s1="%" f s s2=s1,s1=$o(map(s2)) q:'$l(s1) d onemap(s1,s2) d onemap("...",s2) i $d(nams("#")) s s2="LOCAL LOCKS",map(s2)=nams("#") d onemap("",s2) k map(s2) q onemap:(s1,s2) i $l(mapreg),mapreg'=map(s2) q s l1=$l(s1) i $l(s2)=l1,$e(s1,l1)=0,$e(s2,l1)=")",$e(s1,1,l1-1)=$e(s2,1,l1-1) q w !,BOL,?x(1),$tr(s2,")","0"),?x(2),$tr(s1,")","0"),?x(3),"REG = ",map(s2) i '$d(regs(map(s2),"DYNAMIC_SEGMENT")) d q . w !,BOL,?x(3),"SEG = NONE",!,BOL,?x(3),"FILE = NONE" s j=regs(map(s2),"DYNAMIC_SEGMENT") w !,BOL,?x(3),"SEG = ",j i '$d(segs(j,"ACCESS_METHOD")) w !,BOL,?x(3),"FILE = NONE" e s s=segs(j,"FILE_NAME") w !,BOL,?x(3),"FILE = ",s q TEMPLATE d t1 i log s BOL="!" u @uself w BOL d t1 w ! u @useio s BOL="" q t1: d tmpreghd w !,BOL,?x(1),"",?x(3),$j(tmpreg("COLLATION_DEFAULT"),4) i ver'="VMS" w ?x(4),$j(tmpreg("RECORD_SIZE"),7) e w ?x(4),$j(tmpreg("RECORD_SIZE"),5) w ?x(5),$j(tmpreg("KEY_SIZE"),5) w ?x(6),$s(tmpreg("NULL_SUBSCRIPTS")=1:"ALWAYS",tmpreg("NULL_SUBSCRIPTS")=2:"EXISTING",1:"NEVER") w ?x(7),$s(tmpreg("STDNULLCOLL"):"Y",1:"N") w ?x(8),$s(tmpreg("JOURNAL"):"Y",1:"N") i ver'="VMS" w ?x(9),$s(tmpreg("INST_FREEZE_ON_ERROR"):"ENABLED",1:"DISABLED") i ver'="VMS" w ?x(10),$s(tmpreg("QDBRUNDOWN"):"ENABLED",1:"DISABLED") i tmpreg("JOURNAL") d tmpjnlhd,tmpjnlbd d tmpseghd w !,BOL,?x(1),"",?x(2),$s(tmpacc="BG":" *",1:""),?x(3),"BG" w ?x(4),$s(tmpseg("BG","FILE_TYPE")="DYNAMIC":"DYN",1:"STA"),?x(5),$j(tmpseg("BG","BLOCK_SIZE"),5) w ?x(6),$j(tmpseg("BG","ALLOCATION"),10),?x(7),$j(tmpseg("BG","EXTENSION_COUNT"),5) w ?x(8),"GLOB =",$j(tmpseg("BG","GLOBAL_BUFFER_COUNT"),3) w !,BOL,?x(8),"LOCK =",$j(tmpseg("BG","LOCK_SPACE"),3) w !,BOL,?x(8),"RES =",$j(tmpseg("BG","RESERVED_BYTES"),4) i $ZVersion'["VMS" w !,BOL,?x(8),"ENCR = ",$s((encsupportedplat=TRUE&tmpseg("BG","ENCRYPTION_FLAG")):"ON",1:"OFF") w !,BOL,?x(1),"",?x(2),$s(tmpacc="MM":" *",1:""),?x(3),"MM" w ?x(4),$s(tmpseg("MM","FILE_TYPE")="DYNAMIC":"DYN",1:"STA"),?x(5),$j(tmpseg("MM","BLOCK_SIZE"),5) w ?x(6),$j(tmpseg("MM","ALLOCATION"),10),?x(7),$j(tmpseg("MM","EXTENSION_COUNT"),5) w ?x(8),$s(tmpseg("MM","DEFER"):"DEFER",1:"NODEFER") w !,BOL,?x(8),"LOCK =",$j(tmpseg("MM","LOCK_SPACE"),3) q tmpjnlbd: w !,BOL,?x(1),"",?x(2),$s($l(tmpreg("FILE_NAME")):tmpreg("FILE_NAME"),1:"") i $x'<(x(3)-1) w !,BOL w ?x(3),$s(tmpreg("BEFORE_IMAGE"):"Y",1:"N"),?x(4),$j(tmpreg("BUFFER_SIZE"),5) w ?x(5),$j(tmpreg("ALLOCATION"),10) i ver="VMS" w ?x(6),$j(tmpreg("EXTENSION"),5) e w ?x(6),$j(tmpreg("EXTENSION"),10),?x(7),$j(tmpreg("AUTOSWITCHLIMIT"),13) w !,BOL q templatec: f am="MM","BG" w !,"TEMPLATE "_delim_"SEGMENT "_delim_"ACCESS_METHOD=",am d . f q="BLOCK_SIZE","ALLOCATION","EXTENSION_COUNT","LOCK_SPACE","RESERVED_BYTES" w " "_delim,q,"=",tmpseg(am,q) . i "BG"=am d .. w " "_delim_"GLOBAL_BUFFER_COUNT=",tmpseg("BG","GLOBAL_BUFFER_COUNT") .. i $zver'["VMS",encsupportedplat=TRUE,tmpseg("BG","ENCRYPTION_FLAG") w " "_delim_"ENCRYPT" . i "MM"=am w " ",$s(tmpseg("MM","DEFER"):delim,1:delim_"NO"),"DEFER" w !,"TEMPLATE "_delim_"REGION" f q="RECORD_SIZE","KEY_SIZE" w " "_delim,q,"=",tmpreg(q) w " "_delim_"NULL_SUBSCRIPTS=",$s(tmpreg("NULL_SUBSCRIPTS")=1:"ALWAYS",tmpreg("NULL_SUBSCRIPTS")=2:"EXISTING",1:"NEVER") i tmpreg("STDNULLCOLL") w " "_delim_"STDNULLCOLL" i (ver'="VMS") w " "_delim_$s(tmpreg("INST_FREEZE_ON_ERROR"):"",1:"NO")_"INST_FREEZE_ON_ERROR" i (ver'="VMS") w " "_delim_$s(tmpreg("QDBRUNDOWN"):"",1:"NO")_"QDBRUNDOWN" i tmpreg("JOURNAL") d . w !,"TEMPLATE "_delim_"REGION "_delim_"JOURNAL=(" . w $s(tmpreg("BEFORE_IMAGE"):"",1:"NO"),"BEFORE_IMAGE,BUFFER_SIZE=",tmpreg("BUFFER_SIZE") . w ",ALLOCATION=",tmpreg("ALLOCATION"),",EXTENSION=",tmpreg("EXTENSION") . i ver'="VMS" w ",AUTOSWITCHLIMIT=",tmpreg("AUTOSWITCHLIMIT") . w ")" i $l(tmpreg("FILE_NAME")) w ",FILE=",tmpreg("FILE_NAME") w !,BOL q ;----------------------------------------------------------------------------------------------------------------------------------- namehd: s x(0)=9,x(1)=1,x(2)=36 w !,BOL,!,BOL,?x(0),"*** NAMES ***",!,BOL,?x(1),"Global",?x(2),"Region" w !,BOL,?x(1),$tr($j("",78)," ","-") q regionhd: s x(0)=32,x(1)=1,x(2)=33,x(3)=65,x(4)=71 i ver'="VMS" s x(5)=79,x(6)=85,x(7)=96,x(8)=101,x(9)=105,x(10)=114 e s x(5)=77,x(6)=83,x(7)=94,x(8)=104 w !,BOL,!,BOL,?x(0),"*** REGIONS ***" w !,BOL,?x(7),"Std" i ver'="VMS" w ?x(9),"Inst" w !,BOL,?x(2),"Dynamic",?x(3),$j("Def",4) i ver'="VMS" w ?x(4),$j("Rec",7) e w ?x(4),$j("Rec",5) w ?x(5),$j("Key",5),?x(6),"Null",?x(7),"Null" i ver'="VMS" w ?x(9),"Freeze" i ver'="VMS" w ?x(10),"Qdb" w !,BOL,?x(1),"Region",?x(2),"Segment",?x(3),$j("Coll",4) if ver'="VMS" w ?x(4),$j("Size",7) e w ?x(4),$j("Size",5) w ?x(5),$j("Size",5) w ?x(6),"Subs",?x(7),"Coll",?x(8),"Jnl" i ver'="VMS" w ?x(9),"on Error" i ver'="VMS" w ?x(10),"Rndwn" i ver'="VMS" w !,BOL,?x(1),$tr($j("",122)," ","-") e w !,BOL,?x(1),$tr($j("",107)," ","-") q jnlhd: s x(0)=26,x(1)=1,x(2)=33,x(3)=59,x(4)=65,x(5)=71,x(6)=82,x(7)=$s(ver="VMS":88,1:91) w !,BOL,!,BOL,?x(0),"*** JOURNALING INFORMATION ***" w !,BOL,?x(1),"Region",?x(2),"Jnl File (def ext: .mjl)" w ?x(3),"Before",?x(4),$j("Buff",5),?x(5),$j("Alloc",10) i ver="VMS" w ?x(6),"Exten" ;?x(7),"Stop" e w ?x(6),$j("Exten",10),?x(7),$j("AutoSwitch",13) w !,BOL,?x(1),$tr($j("",$s(ver="VMS":87,1:104))," ","-") q seghd: s x(0)=32,x(1)=1,x(2)=33,x(3)=53,x(4)=57,x(5)=61,x(6)=67,x(7)=78,x(8)=84 w !,BOL,!,BOL,?x(0),"*** SEGMENTS ***" w !,BOL,?x(1),"Segment",?x(2),"File (def ext: .dat)",?x(3),"Acc",?x(4),"Typ",?x(5),"Block",?x(6),$j("Alloc",10) w ?x(7),"Exten",?x(8),"Options" w !,BOL,?x(1),$tr($j("",91)," ","-") q maphd: s x="*** MAP"_$s($l(mapreg):" for region "_mapreg,1:"")_" ***" s x(0)=80-$l(x)*.5,x(1)=1,x(2)=33,x(3)=66,x(4)=98,x(5)=130 w !,BOL,!,BOL,?x(0),x w !,BOL,?x(1)," - - - - - - - - - - Names - - - - - - - - - -" w !,BOL,?x(1),"From",?x(2),"Up to",?x(3),"Region / Segment / File(def ext: .dat)" w !,BOL,?x(1),$tr($j("",122)," ","-") q tmpreghd: s x(0)=31,x(1)=1,x(2)=19,x(3)=44,x(4)=49 i ver'="VMS" s x(5)=57,x(6)=63,x(7)=74,x(8)=79,x(9)=83,x(10)=92 e s x(5)=55,x(6)=61,x(7)=72,x(8)=82 w !,BOL,!,BOL,?x(0),"*** TEMPLATES ***" w !,BOL,?x(7),"Std" i ver'="VMS" w ?x(9),"Inst" w !,BOL,?x(3),$j("Def",4) i ver'="VMS" w ?x(4),$j("Rec",7) e w ?x(4),$j("Rec",5) w ?x(5),$j("Key",5),?x(6),"Null",?x(7),"Null" i ver'="VMS" w ?x(9),"Freeze" i ver'="VMS" w ?x(10),"Qdb" w !,BOL,?x(1),"Region",?x(3),$j("Coll",4) i ver'="VMS" w ?x(4),$j("Size",7) e w ?x(4),$j("Size",5) w ?x(5),$j("Size",5) w ?x(6),"Subs",?x(7),"Coll",?x(8),"Jnl" i ver'="VMS" w ?x(9),"on Error" i ver'="VMS" w ?x(10),"Rndwn" i ver'="VMS" w !,BOL,?x(1),$tr($j("",100)," ","-") e w !,BOL,?x(1),$tr($j("",85)," ","-") q tmpjnlhd: s x(0)=26,x(1)=1,x(2)=18,x(3)=44,x(4)=51,x(5)=57,x(6)=68,x(7)=74 w !,BOL,?x(2),"Jnl File (def ext: .mjl)" w ?x(3),"Before",?x(4),$j("Buff",5),?x(5),$j("Alloc",10) i ver="VMS" w ?x(6),"Exten" e w ?x(6),$j("Exten",10),?x(7),$j("AutoSwitch",13) i ver="VMS" w !,BOL,?x(1),$tr($j("",78)," ","-") e w !,BOL,?x(1),$tr($j("",90)," ","-") q tmpseghd: s x(0)=32,x(1)=1,x(2)=18,x(3)=38,x(4)=42,x(5)=46,x(6)=52,x(7)=63,x(8)=69 w !,BOL,!,BOL,?x(1),"Segment",?x(2),"Active",?x(3),"Acc",?x(4),"Typ",?x(5),"Block",?x(6),$j("Alloc",10) w ?x(7),"Exten",?x(8),"Options" w !,BOL,?x(1),$tr($j("",78)," ","-") q fis-gtm-V6.0-003/sr_port/gdespawn.m0000644000032200000250000000110512201176156016016 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; spawn: ;implement the verb: SPAWN SPAWN n spawnline s spawnline=$e(comline,cp-$l(ntoken),999) u io:ctrap=$c(3,25) zsy spawnline u @useio q fis-gtm-V6.0-003/sr_port/gdetempl.m0000644000032200000250000000216112201176156016012 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; template: ;implement the verb: TEMPLATE REGION i $d(lquals("JOURNAL")),lquals("JOURNAL"),'tmpreg("JOURNAL"),'$d(lquals("BEFORE_IMAGE")) d . zm gdeerr("QUALREQD"):"Before_image" i $d(lquals("NULL_SUBSCRIPTS")) d NQUALS^GDEVERIF(.lquals) i '$$TRQUALS^GDEVERIF(.lquals) zm gdeerr("OBJNOTCHG"):"region":"template" s update=1,s="" f s s=$o(lquals(s)) q:'$l(s) s tmpreg(s)=lquals(s) i s="ALLOCATION" s tmpreg("EXTENSION")=lquals(s)\10 q SEGMENT i $d(lquals("ACCESS_METHOD")) s am=lquals("ACCESS_METHOD") e s am=tmpacc i '$$TSQUALS^GDEVERIF(am,.lquals) zm gdeerr("OBJNOTCHG"):"segment":"template" s update=1,s="",tmpacc=am f s s=$o(lquals(s)) q:'$l(s) s tmpseg(tmpacc,s)=lquals(s) q fis-gtm-V6.0-003/sr_port/gds_blk_downgrade.c0000644000032200000250000000507212201176156017642 0ustar librarygtc/**************************************************************** * * * Copyright 2005, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdlib.h" #include "gtm_string.h" #include "gdsroot.h" #include "v15_gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsblk.h" #include "gdsbt.h" #include "v15_gdsbt.h" #include "gdsfhead.h" #include "v15_gdsfhead.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" #include "gds_blk_downgrade.h" #ifdef VMS #include "copy.h" #endif #define SPACE_NEEDED (SIZEOF(blk_hdr) - SIZEOF(v15_blk_hdr)) GBLREF boolean_t dse_running; void gds_blk_downgrade(v15_blk_hdr_ptr_t gds_blk_trg, blk_hdr_ptr_t gds_blk_src) { sm_uc_ptr_t trg_p, src_p; v15_trans_num v15tn; trans_num tn; uint4 bsiz, levl; int movesize; /* Note that this routine is written in such a fashion that it is possible for the source and target blocks to point to the same area. */ assert(gds_blk_trg); assert(gds_blk_src); assert(SIZEOF(v15_blk_hdr) > gds_blk_src->bver); /* Check it is a GDSVCURR blk to begin with */ assert(0 == ((long)gds_blk_trg & 0x7)); /* Buffer alignment checks (8 byte) */ assert(0 == ((long)gds_blk_src & 0x7)); trg_p = (sm_uc_ptr_t)gds_blk_trg + SIZEOF(v15_blk_hdr); src_p = (sm_uc_ptr_t)gds_blk_src + SIZEOF(blk_hdr); bsiz = gds_blk_src->bsiz; assert(MAX_BLK_SZ >= bsiz); assert(SIZEOF(blk_hdr) <= bsiz); tn = gds_blk_src->tn; assert((MAX_TN_V4 >= tn) || dse_running); levl = gds_blk_src->levl; movesize = bsiz - SIZEOF(blk_hdr); if ((sm_uc_ptr_t)gds_blk_trg != (sm_uc_ptr_t)gds_blk_src) { /* Normal case, downgrade is to a new buffer. Our simple check is quicker than just always doing memmove() would be. But assert they are at least one block away just in case... */ DEBUG_ONLY( if ((sm_uc_ptr_t)gds_blk_trg > (sm_uc_ptr_t)gds_blk_src) assert((sm_uc_ptr_t)gds_blk_trg >= ((sm_uc_ptr_t)gds_blk_src + bsiz)); else assert((sm_uc_ptr_t)gds_blk_src >= ((sm_uc_ptr_t)gds_blk_trg + bsiz)); ) memcpy(trg_p, src_p, movesize); } else memmove(trg_p, src_p, movesize); gds_blk_trg->bsiz = bsiz - SPACE_NEEDED; gds_blk_trg->levl = levl; v15tn = (v15_trans_num) tn; UNIX_ONLY(gds_blk_trg->tn = v15tn); VMS_ONLY(PUT_ULONG(&gds_blk_trg->tn, v15tn)); } fis-gtm-V6.0-003/sr_port/gds_blk_downgrade.h0000644000032200000250000000124712201176156017647 0ustar librarygtc/**************************************************************** * * * Copyright 2005 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GDS_BLK_UPGRADE_INCLUDED #define GDS_BLK_UPGRADE_INCLUDED void gds_blk_downgrade(v15_blk_hdr_ptr_t gds_blk_trg, blk_hdr_ptr_t gds_blk_src); #define IS_GDS_BLK_DOWNGRADE_NEEDED(ondskblkver) (GDSV4 == (ondskblkver)) #endif fis-gtm-V6.0-003/sr_port/gds_blk_upgrade.c0000644000032200000250000000534712201176156017324 0ustar librarygtc/**************************************************************** * * * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "v15_gdsroot.h" #include "gdsblk.h" #include "gdsdbver.h" #include "gds_blk_upgrade.h" #include "iosp.h" #include "copy.h" #define SPACE_NEEDED (SIZEOF(blk_hdr) - SIZEOF(v15_blk_hdr)) GBLREF boolean_t gtm_blkupgrade_override; GBLREF uint4 gtm_blkupgrade_flag; /* control whether dynamic upgrade is attempted or not */ error_def(ERR_DYNUPGRDFAIL); int4 gds_blk_upgrade(sm_uc_ptr_t gds_blk_src, sm_uc_ptr_t gds_blk_trg, int4 blksize, enum db_ver *ondsk_blkver) { blk_hdr_ptr_t bp; v15_blk_hdr_ptr_t v15bp; v15_trans_num v15tn; uint4 v15bsiz, v15levl; assert(gds_blk_src); assert(gds_blk_trg); /* Assert that the input buffer is 8-byte aligned for us to freely de-reference 8-byte tn fields from the buffer header. * If not, we should have had to use GET/PUT_xxxx macros from copy. * Note that in GDSV4 format in VMS, the "tn" field in the block-header is not 4-byte offset aligned so we * need to use the GET_ULONG macro to fetch the field from the block header. But since "tn" is 8-byte * offset aligned in the new format, there is no need of any such macro while assigning bp->tn. */ assert(0 == ((long)gds_blk_src & 0x7)); /* Assume 8 byte alignment */ assert(0 == ((long)gds_blk_trg & 0x7)); v15bp = (v15_blk_hdr_ptr_t)gds_blk_src; bp = (blk_hdr_ptr_t)gds_blk_trg; assert((SIZEOF(v15_blk_hdr) <= v15bp->bsiz) || (UPGRADE_ALWAYS == gtm_blkupgrade_flag)); UNIX_ONLY(v15tn = v15bp->tn); VMS_ONLY(GET_ULONG(v15tn, &v15bp->tn)); v15bsiz = v15bp->bsiz; if (v15bsiz > blksize) /* Exceeds maximum block size. Not a valid V4 block. Return without upgrading */ { assert(UPGRADE_NEVER != gtm_blkupgrade_flag); if (UPGRADE_IF_NEEDED == gtm_blkupgrade_flag) { if (NULL != ondsk_blkver) *ondsk_blkver = GDSV6; return SS_NORMAL; } else { if (NULL != ondsk_blkver) *ondsk_blkver = GDSV4; return ERR_DYNUPGRDFAIL; } } if (NULL != ondsk_blkver) *ondsk_blkver = GDSV4; v15bsiz += SPACE_NEEDED; if (v15bsiz > blksize) /* Exceeds maximum block size */ return ERR_DYNUPGRDFAIL; v15levl = v15bp->levl; memmove((gds_blk_trg + SPACE_NEEDED), gds_blk_src, v15bp->bsiz); /* Shift/copy block requisite amount */ bp->tn = v15tn; bp->bsiz = v15bsiz; bp->levl = v15levl; bp->bver = GDSV6; return SS_NORMAL; } fis-gtm-V6.0-003/sr_port/gds_blk_upgrade.h0000644000032200000250000002007012201176156017317 0ustar librarygtc/**************************************************************** * * * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GDS_BLK_UPGRADE_INCLUDED #define GDS_BLK_UPGRADE_INCLUDED #define UPGRADE_IF_NEEDED 0 /* default */ #define UPGRADE_NEVER 1 #define UPGRADE_ALWAYS 2 int4 gds_blk_upgrade(sm_uc_ptr_t gds_blk_src, sm_uc_ptr_t gds_blk_trg, int4 bsiz, enum db_ver *ondsk_blkver); GBLREF uint4 gtm_blkupgrade_flag; /* control whether dynamic upgrade is attempted or not */ GBLREF boolean_t dse_running; /* See if block needs to be converted to current version. Assume buffer is at least short aligned. * Note: csd->fully_upgraded is not derived within the macro but instead passed in as a parameter to ensure whichever * function (dsk_read currently) references this does that once and copies the value into a local variable that is used * in all further usages. This way multiple usages are guaranteed to see the same value. Using csd->fully_upgraded in * each of those cases could cause different values to be seen (since csd can be concurrently updated). */ #define GDS_BLK_UPGRADE_IF_NEEDED(blknum, srcbuffptr, trgbuffptr, curcsd, ondskblkver, upgrdstatus, fully_upgraded) \ { \ /* In order to detect if a block needs to be upgraded or not, we do the following series of tests. \ * If DSE, the variable "gtm_blkupgrade_flag" controls whether upgrade is attempted or not. \ * If it is UPGRADE_NEVER, we never attempt upgrade. \ * Likewise, if it is UPGRADE_ALWAYS, we unconditionally upgrade. \ * If it is UPGRADE_IF_NEEDED, then the following checks are done. \ * 1) If the file-header has "fully_upgraded" set to TRUE, we know for sure no block needs to be upgraded. \ * This check is performed in this macro itself as it is a quick check and avoids a function call. \ * 2) Else, the block might or might not need an upgrade. To decide, we do some more checks. \ * V5 onwards, the first 2 bytes of the block header is the version indicator. It is 1 in V5. \ * In V4, the first 2 bytes of the block header was the block-size which is guaranteed to be \ * at least SIZEOF(v15_blk_hdr) (the size of the V4 blk_hdr structure) which is 8 bytes in Unix \ * and 7 bytes in VMS. We use the first 2 bytes in the block header as a first level check. \ * If they are >= SIZEOF(v15_blk_hdr), we decide it is a V4 format block and try to upgrade. \ * This check is performed in this macro itself as it is a quick check and avoids a function call. \ * 3) It is quite possible that we might conclude the format incorrectly based on just the above checks. \ * This can be due to any one of the following. \ * => A V4 format block might have a corrupt block-header where the first 2 bytes are exactly 1. \ * => A V5 format block might have a corrupt block-header where the first 2 bytes are not 1. \ * => We might be reading an unused block (marked free/recycled in the bitmap) from disk. \ * This is possible due to a variety of reasons including concurrency issues while \ * traversing the B-tree that cause us to end up in a restartable situation. \ * If we read such a block, then the block contents (including the header) is not valid. \ * In VMS it contains uninitialized data. In Unix it contains 0s. \ * In all the above cases, we have no definitive way of determining exactly which format the block is. \ * For the case where we incorrectly conclude it is V5 format, we dont do much. \ * But for the other case, we do better by checking if the V4 block has enough room to accommodate \ * the extra space needed for the upgrade. \ * If yes, we go ahead with the upgrade. \ * If not, we check if the V4 block size is less than the database block size. \ * If yes, then we believe it is a valid V4 block that is just too big to be upgraded. \ * We therefore issue a DYNUPGRDFAIL error. \ * If no, this is a corrupt block and we decide not to upgrade. \ * Something to consider for the future is to invoke block certification on this block. \ * This check is involved and hence is done in the function "gds_blk_upgrade" (invoked from this macro). \ * This is not a theoretically foolproof solution but for all practical purposes should be good enough. \ * Note that for a database that has been completely upgraded to V5 format, we do not have any inconclusiveness. \ * \ * Note the clearing of srcbuffptr is done as a flag that gds_blk_upgrd was run (used by dsk_read). \ */ \ if (!dse_running || (UPGRADE_IF_NEEDED == gtm_blkupgrade_flag)) \ { \ if ((fully_upgraded) || (SIZEOF(v15_blk_hdr) > ((v15_blk_hdr_ptr_t)(srcbuffptr))->bsiz)) \ { \ upgrdstatus = SS_NORMAL; \ if (NULL != (ondskblkver)) \ *(ondskblkver) = GDSV6; \ } else \ { \ upgrdstatus = gds_blk_upgrade((sm_uc_ptr_t)(srcbuffptr), (sm_uc_ptr_t)(trgbuffptr), \ (curcsd)->blk_size, (ondskblkver)); \ if (srcbuffptr != trgbuffptr) \ srcbuffptr = NULL; \ } \ } else if (UPGRADE_NEVER == gtm_blkupgrade_flag) \ { \ upgrdstatus = SS_NORMAL; \ if (NULL != (ondskblkver)) \ *(ondskblkver) = GDSV6; \ } else if (UPGRADE_ALWAYS == gtm_blkupgrade_flag) \ { \ upgrdstatus = gds_blk_upgrade((sm_uc_ptr_t)(srcbuffptr), (sm_uc_ptr_t)(trgbuffptr), \ (curcsd)->blk_size, (ondskblkver)); \ if (NULL != (ondskblkver)) \ *(ondskblkver) = GDSV4; \ if (srcbuffptr != trgbuffptr) \ srcbuffptr = NULL; \ } \ } /* This macro is invoked by dsk_read.c when we know for sure we are reading a valid block. This checks that the block * we read from disk contains a valid block header. It also checks that we CANNOT have read a V4 format reused block * if the database has been fully upgraded. It uses checks similar to those used in the GDS_BLK_UPGRADE_IF_NEEDED * macro to determine if it is a V4 or V5 format block header. * Note: csd->fully_upgraded is not derived within the macro but instead passed in as a parameter to ensure whichever * function (dsk_read currently) references this does that once and copies the value into a local variable that is used * in all further usages. This way multiple usages are guaranteed to see the same value. Using csd->fully_upgraded in * each of those cases could cause different values to be seen (since csd can be concurrently updated). */ #define GDS_BLK_HDR_CHECK(csd, v5_blk_hdr, fully_upgraded) \ { \ v15_blk_hdr_ptr_t v4_blk_hdr; \ \ v4_blk_hdr = (v15_blk_hdr_ptr_t)v5_blk_hdr; \ if (!(fully_upgraded) || (SIZEOF(v15_blk_hdr) > v4_blk_hdr->bsiz)) \ { /* V5 formatted buffer in shared memory (even though might be V4 format in disk) */ \ assert((unsigned)GDSVLAST > (unsigned)v5_blk_hdr->bver); \ assert((LCL_MAP_LEVL == v5_blk_hdr->levl) || ((unsigned)MAX_BT_DEPTH > (unsigned)v5_blk_hdr->levl)); \ assert((unsigned)size >= (unsigned)v5_blk_hdr->bsiz); \ assert(csd->trans_hist.curr_tn >= v5_blk_hdr->tn); \ } else \ { /* V4 formatted buffer in shared memory (not converted because fully_upgraded is TRUE). \ * Possible if we are reading a recycled block that is in V4 format from a fully upgraded database. \ * But all recycled blocks are now upgraded by MUPIP REORG UPGRADE so this should be impossible. \ */ \ assert(FALSE); \ } \ } #endif fis-gtm-V6.0-003/sr_port/gds_map_moved.c0000644000032200000250000000603012201176156017002 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdskill.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdscc.h" #include "filestruct.h" #include "jnl.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "gds_map_moved.h" #include "hashtab_mname.h" GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF gv_namehead *gv_target_list; void gds_map_moved(sm_uc_ptr_t new_base, sm_uc_ptr_t old_base, sm_uc_ptr_t old_top, size_t mmap_sz) { int hist_index; sm_long_t adj; srch_hist *hist, *hist1, *hist2; gv_namehead *gvt; sgmnt_addrs *csa; csa = cs_addrs; assert(csa->now_crit); assert(cs_data == csa->hdr); assert((NULL == csa->sgm_info_ptr) || (csa->hdr == csa->sgm_info_ptr->tp_csd)); assert(csa->bmm == MM_ADDR(cs_data)); assert(csa->ti == &cs_data->trans_hist); csa->db_addrs[1] = new_base + mmap_sz - 1; /* The following adjustment needs to be done only if new_base is different from old_base */ if (new_base == old_base) return; adj = (sm_long_t)(new_base - old_base); assert(0 != adj); /* Scan the list of gvts allocated by this process in its lifetime and see if they map to the current csa. * If so adjust their clues (in the histories) as appropriate to reflect the remapping of the database file. */ for (gvt = gv_target_list; NULL != gvt; gvt = gvt->next_gvnh) { if ((csa == gvt->gd_csa) && (0 < gvt->clue.end)) { hist1 = &gvt->hist; hist2 = gvt->alt_hist; for (hist = hist1; (NULL != hist); hist = (hist == hist1) ? hist2 : NULL) { for (hist_index = 0; HIST_TERMINATOR != hist->h[hist_index].blk_num; hist_index++) { assert(MAX_BT_DEPTH >= hist_index); if ((old_base <= hist->h[hist_index].buffaddr) && (old_top > hist->h[hist_index].buffaddr)) { hist->h[hist_index].buffaddr += adj; assert(new_base <= hist->h[hist_index].buffaddr); } else if ((hist == hist2) && (0 < gvt->clue.end)) { /* alt_hist is not updated when clue is set so the buffaddr can * point to a prior instance of the file's mapping. So, reset alt_hist. */ hist->h[hist_index].blk_num = HIST_TERMINATOR; } else { /* It's already been adjusted or it has to be a private copy */ assert(((new_base <= hist->h[hist_index].buffaddr) && (hist->h[hist_index].buffaddr < new_base + (old_top - old_base))) || (0 != hist->h[hist_index].first_tp_srch_status) || (0 != ((off_chain *)&(hist->h[hist_index].blk_num))->flag)); } } } } } return; } fis-gtm-V6.0-003/sr_port/gds_map_moved.h0000644000032200000250000000121612201176156017010 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GDS_MAP_MOVED_INCLUDED #define GDS_MAP_MOVED_INCLUDED void gds_map_moved(sm_uc_ptr_t new_base, sm_uc_ptr_t old_base, sm_uc_ptr_t old_top, size_t mmap_sz); #endif /* GDS_MAP_MOVED_INCLUDED */ fis-gtm-V6.0-003/sr_port/gds_rundown.h0000644000032200000250000000303212201176156016533 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GDS_RUNDOWN_INCLUDED #define GDS_RUNDOWN_INCLUDED #ifdef UNIX int4 gds_rundown(void); #define CAN_BYPASS(SEMVAL, CANCELLED_TIMER, INST_IS_FROZEN) \ (((IS_GTM_IMAGE && csd->mumps_can_bypass) && !CANCELLED_TIMER && (PROC_FACTOR * (num_additional_processors + 1) < SEMVAL)) \ || ((2 < SEMVAL) && (IS_LKE_IMAGE || IS_DSE_IMAGE)) || INST_IS_FROZEN) #define CANCEL_DB_TIMERS(region, csa, cancelled_timer, cancelled_dbsync_timer) \ { \ if (csa->timer) \ { \ cancel_timer((TID)region); \ if (NULL != csa->nl) \ DECR_CNT(&csa->nl->wcs_timers, &csa->nl->wc_var_lock); \ cancelled_timer = TRUE; \ csa->timer = FALSE; \ } \ if (csa->dbsync_timer) \ { \ CANCEL_DBSYNC_TIMER(csa); \ cancelled_dbsync_timer = TRUE; \ } \ } /* A multiplicative factor to the # of processors used in determining if a GT.M process in gds_rundown can bypass semaphores */ #ifdef DEBUG # define PROC_FACTOR 2 #else # define PROC_FACTOR 20 #endif #else void gds_rundown(void); #endif #endif /* GDS_RUNDOWN_INCLUDED */ fis-gtm-V6.0-003/sr_port/gdsbgtr.h0000644000032200000250000000222212201176156015636 0ustar librarygtc/**************************************************************** * * * Copyright 2005, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* Define macros to keep statistics of certain parts of code we pass * through, some only if we are in debug mode. * * Although the incremented counters are generally in shared storage, * we will not do interlock adds to them because even though there * may be some interference, most will succeed and we are only looking * for trends from these numbers anyway, not exact counts. */ #define BG_TRACE_PRO_ANY(C, X) {C->hdr->X##_cntr++; C->hdr->X##_tn = C->hdr->trans_hist.curr_tn ;} #define BG_TRACE_PRO(Q) BG_TRACE_PRO_ANY(cs_addrs, Q) #ifdef DEBUG #define BG_TRACE_ANY(C, X) BG_TRACE_PRO_ANY(C, X) #define BG_TRACE(Q) BG_TRACE_ANY(cs_addrs, Q) #else #define BG_TRACE_ANY(C, X) #define BG_TRACE(Q) #endif fis-gtm-V6.0-003/sr_port/gdsblk.h0000644000032200000250000001524012201176156015454 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GDSBLK_H__ #define __GDSBLK_H__ /* gdsblk.h */ #include #define BML_LEVL ((unsigned char)-1) #define CST_BSIZ(b) ((b)->bsiz - SIZEOF(blk_hdr)) #define CST_RSIZ(r) ((r)->rsiz - SIZEOF(rec_hdr)) #define CST_TOR(r) ((uchar_ptr_t)(r) + (r)->rsiz) #define CST_TOB(b) ((uchar_ptr_t)(b) + (b)->bsiz) #define CST_RIB(r,b) ((uchar_ptr_t)(r) + (r)->rsiz <= CST_TOB(b)) #define CST_1ST_REC(b) ((rec_hdr_ptr_t)((uchar_ptr_t)(b) + SIZEOF(blk_hdr))) #define CST_NXT_REC(r) ((uchar_ptr_t)(r) + (r)->rsiz) #define CST_BOK(r) ((uchar_ptr_t)(r) + SIZEOF(rec_hdr)) #define CST_USAR(b, r) ((b)->bsiz - ((uchar_ptr_t(r) + (r)->rsiz - (uchar_ptr_t)(b))) #define CST_KSIZ (gv_curr_key->end - gv_curr_key->base + 1) #define BSTAR_REC_SIZE INTCAST((SIZEOF(rec_hdr) + SIZEOF(block_id))) #define BSTAR_REC(r) ((rec_hdr_ptr_t)(r))->rsiz = BSTAR_REC_SIZE; SET_CMPC((rec_hdr_ptr_t)(r), 0); #define IS_LEAF(b) (0 == ((blk_hdr_ptr_t)(b))->levl) #define IS_BML(b) (BML_LEVL == ((blk_hdr_ptr_t)(b))->levl) #define IS_BSTAR_REC(r) ((r)->rsiz == BSTAR_REC_SIZE) #define GAC_RSIZE(rsize,r,tob) if ((uchar_ptr_t)(r) + ((rsize) = ((rec_hdr_ptr_t)(r))->rsiz) > tob) return(-1) #define MIN_DATA_SIZE 1 + 2 /* 1 byte of key + 2 nulls for terminator */ #define MAX_EXTN_COUNT 65535 #define MIN_EXTN_COUNT 0 #define MAX_DB_BLK_SIZE ((1 << 16) - 512) /* 64Kb - 512 (- 512 to take care of VMS's max I/O capabilities) */ /* Note: EVAL_CMPC not to be confused with the previously existing GET_CMPC macro in mu_reorg.h! * The maximum key size in V5 was 255 bytes, including the two null bytes at the end. Two distinct keys * could have a common prefix of at most 252.The 255 limit was imposed because the record header was * 3 bytes and had only 1 byte for compression count. But on UNIX the record header is actually 4 bytes * (see pragmas below), leaving an unused filler byte. To accommodate larger keys while * maintaining compatibility with V5, we can overload the previously unused values of cmpc * to get compression counts of up to 1020, which will support keys up to 1023 bytes. * As in V5 compression counts of between 0 and 252, inclusive, are stored in the first byte. * rp->cmpc values of 253, 254, and 255 indicate information is stored in the second byte. * * There are several constants used below. They are very specific and ONLY used here. We don't #define them * because that implies you can change one and the logic will still work. But that's not the case. * 253 --- cmpc value just beyond the highest possible in V5 (252). 253 = OLD_MAX_KEY_SZ - two terminators. * 256 --- Number of distinct compression counts that can be stored when cmpc is either 253, 254, or 255. * Corresponds to the one extra byte, which can store 256 values. * 0x03FF --- Equals 1023. We want to avoid having EVAL_CMPC return huge values due to concurrent changes * to block contents. This limits the result, preventing unintentionally large memcpy's in e.g. gvcst_put. */ #ifdef UNIX # define EVAL_CMPC(RP) ((253 > (RP)->cmpc) \ ? (RP)->cmpc \ : (253 + ((RP)->cmpc - 253) * 256 + (int)(RP)->cmpc2) & 0x03FF) # define EVAL_CMPC2(RP, VAR) \ { /* Usage note: make sure VAR is an int */ \ VAR = (RP)->cmpc; \ if (253 <= VAR) \ VAR = (253 + ((VAR) - 253) * 256 + (int)(RP)->cmpc2) & 0x03FF; \ } # define SET_CMPC(RP, VAL) \ { \ int lcl_cmpc_val; \ \ lcl_cmpc_val = (VAL); \ if (253 > lcl_cmpc_val) \ (RP)->cmpc = (unsigned char)lcl_cmpc_val; \ else \ { \ (RP)->cmpc = (unsigned char)(253 + (lcl_cmpc_val - 253) / 256); \ (RP)->cmpc2 = (unsigned char)((lcl_cmpc_val - 253) & 0xFF); \ } \ } #else # define EVAL_CMPC(RP) ((int)(RP)->cmpc) # define EVAL_CMPC2(RP, VAR) \ { /* Usage note: make sure VAR is an int */ \ VAR = (RP)->cmpc; \ } # define SET_CMPC(RP, VAL) \ { \ (RP)->cmpc = (unsigned char)(VAL); \ } #endif #if defined(__alpha) && defined(__vms) # pragma member_alignment save # pragma nomember_alignment #endif /* Version 4 block header */ typedef struct { unsigned short bsiz; /* block size */ unsigned char levl; /* block level. level 0 is data level. level 1 is * first index level. etc. */ uint4 tn; /* transaction number when block was written */ } v15_blk_hdr; /* Current block header */ typedef struct { unsigned short bver; /* block version - overlays V4 block size */ unsigned char filler; unsigned char levl; /* block level. level 0 is data level. level 1 is * first index level. etc. */ unsigned int bsiz; /* block size */ trans_num tn; /* transaction number when block was written */ } blk_hdr; typedef struct { unsigned short rsiz; unsigned char cmpc; # ifdef UNIX unsigned char cmpc2; /* extra byte allows compression count up to 1020 */ # endif } rec_hdr; #if defined(__alpha) && defined(__vms) # pragma member_alignment restore #endif /* Define pointer types to above structures */ #ifdef DB64 # ifdef __osf__ # pragma pointer_size(save) # pragma pointer_size(long) # else # error UNSUPPORTED PLATFORM # endif #endif typedef v15_blk_hdr *v15_blk_hdr_ptr_t; /* From jnl format 15 used in last GT.M V4 version */ typedef blk_hdr *blk_hdr_ptr_t; typedef rec_hdr *rec_hdr_ptr_t; #ifdef DB64 # ifdef __osf__ # pragma pointer_size(restore) # endif #endif #define MAX_RESERVE_B(X) ((X)->blk_size - (X)->max_rec_size - SIZEOF(blk_hdr)) #define CHKRECLEN(r,b,n) ((unsigned int)((n) + (uchar_ptr_t)(r) - (uchar_ptr_t)(b)) <= (unsigned int)((blk_hdr_ptr_t)(b))->bsiz) /********************************************************************* read record size from REC_BASE (temp_ushort must be defined) *********************************************************************/ #define GET_RSIZ(REC_SIZE, REC_BASE) \ GET_USHORT(temp_ushort, &(((rec_hdr_ptr_t)(REC_BASE))->rsiz)); \ REC_SIZE = temp_ushort int4 bm_find_blk(int4 hint, sm_uc_ptr_t base_addr, int4 total_bits, boolean_t *used); void bm_setmap(block_id bml, block_id blk, int4 busy); void bml_newmap(blk_hdr_ptr_t ptr, uint4 size, trans_num curr_tn); /* End of gdsblk.h */ #endif fis-gtm-V6.0-003/sr_port/gdsblkops.h0000644000032200000250000002751112201176156016202 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GDSBLK_OPS_H__ #define __GDSBLK_OPS_H__ /* Block segment array holds the list of memcpys needed to build the updated block. The first entry in the array holds the length of the updated block and the address of the last entry in the array that holds valid data. The arrays are processed at t_end time, and the copies are done starting with the last element in the array */ /* HEADER-FILE-DEPENDENCIES : min_max.h */ typedef struct { sm_uc_ptr_t addr; sm_ulong_t len; } blk_segment; #define BLK_SEG_ARRAY_SIZE 20 /* although kills may have MAX_BT_DEPTH * 2 - 1 elements, each element is limited to key_size and gives a smaller max than puts */ /* *************************************************************************** * The following is the splitup of the calculation of maximum-update-array-size for one non-TP action (for a PUT) * * BLK_INIT, BLK_FINI space ---> CDB_CW_SET_SIZE * (BLK_SEG_ARRAY_SIZE * SIZEOF(blk_segment)) * BLK_ADDR leaf-level space---> 2 * cs_data->blk_size (for current and new sibling) * BLK_ADDR index-level space--> (MAX_BT_DEPTH - 1) * (2 * (MAX_KEY_SZ + SIZEOF(rec_hdr) + SIZEOF(block_id)) + SIZEOF(rec_hdr)) * 2 extra space ---> cs_data->blk_size + BSTAR_REC_SIZE (needed in case of global-variable creation) * Bitmap BLK_ADDR space ---> (MAX_BT_DEPTH + 1) * (SIZEOF(block_id) * (BLKS_PER_LMAP + 1)) * */ #define UPDATE_ELEMENT_ALIGN_SIZE 8 #define UPDATE_ARRAY_ALIGN_SIZE (1 << 14) /* round up the update array to a 16K boundary */ #define MAX_BITMAP_UPDATE_ARRAY_SIZE ((MAX_BT_DEPTH + 1) * ROUND_UP2(SIZEOF(block_id) * (BLKS_PER_LMAP + 1), \ UPDATE_ELEMENT_ALIGN_SIZE)) #define MAX_NON_BITMAP_UPDATE_ARRAY_SIZE(csd) \ (CDB_CW_SET_SIZE * ROUND_UP2(BLK_SEG_ARRAY_SIZE * SIZEOF(blk_segment), UPDATE_ELEMENT_ALIGN_SIZE) \ + 2 * ROUND_UP2(csd->blk_size, UPDATE_ELEMENT_ALIGN_SIZE) \ + (MAX_BT_DEPTH - 1) * \ (3 * ROUND_UP2(SIZEOF(rec_hdr), UPDATE_ELEMENT_ALIGN_SIZE) \ + 2 * ROUND_UP2(SIZEOF(block_id), UPDATE_ELEMENT_ALIGN_SIZE) + 2 * ROUND_UP2(MAX_KEY_SZ, 8)) \ + ROUND_UP2(csd->blk_size, UPDATE_ELEMENT_ALIGN_SIZE) + ROUND_UP2(BSTAR_REC_SIZE, UPDATE_ELEMENT_ALIGN_SIZE)) #define UA_SIZE(X) (uint4)(X->max_update_array_size) #define UA_NON_BM_SIZE(X) (uint4)(X->max_non_bm_update_array_size) #define ENSURE_UPDATE_ARRAY_SPACE(space_needed) \ { \ GBLREF ua_list *first_ua, *curr_ua; \ GBLREF char *update_array, *update_array_ptr; \ GBLREF uint4 update_array_size, cumul_update_array_size; \ GBLREF uint4 dollar_tlevel; \ ua_list *tmpua; \ \ assert((0 != update_array_size) && (NULL != update_array)); \ if (ROUND_DOWN2(update_array + update_array_size - update_array_ptr, UPDATE_ELEMENT_ALIGN_SIZE) < (space_needed)) \ { /* the space remaining is too small for safety - chain on a new array */ \ assert((NULL != first_ua) && (NULL != curr_ua)); \ if ((NULL == curr_ua) || (NULL == curr_ua->next_ua)) \ { \ /* care should be taken to ensure things will work right even if malloc() errors out with ERR_MEMORY. \ * that is why multiple assignments are not done in a single line that has a malloc() call in it. \ * in addition, the field taking in the result of malloc() should be initialized to NULL before the \ * call. This is because tp_clean_up() (invoked in case of error handling) relies on the integrity of \ * this update array linked list in order to do its cleanup. Not following the above rules will cause \ * difficult-to-debug memory related problems (even corruption) */ \ tmpua = (ua_list *)malloc(SIZEOF(ua_list)); \ memset(tmpua, 0, SIZEOF(ua_list)); /* initialize tmpua->update_array and tmpua->next_ua to NULL */ \ /* it is important that all parameters in the MIN-MAX calculation below be unsigned numbers */ \ tmpua->update_array_size = MIN(MAX(cumul_update_array_size, (space_needed)), BIG_UA); \ tmpua->update_array = (char *)malloc(tmpua->update_array_size); \ /* update globals only after above mallocs succeed */ \ cumul_update_array_size += tmpua->update_array_size; \ if (NULL == curr_ua) /* in PRO, don't take chances, reset first_ua/curr_ua to newly created upd array */\ { \ if (dollar_tlevel && (NULL != first_ua)) /* if already in TP, we will lose all updates until now\ if we reset first_ua. do not proceed in this case */\ GTMASSERT; \ first_ua = curr_ua = tmpua; \ } else \ curr_ua = curr_ua->next_ua = tmpua; \ } else \ { /* No need to do malloc as curr_ua->next_ua could be REUSED */ \ curr_ua = curr_ua->next_ua; \ /* No need to reset cumul_update_array_size as no ua_list is deleted/added from/to the first_ua \ * linked list */ \ } \ assert((NULL != first_ua) && (NULL != curr_ua)); \ update_array_size = curr_ua->update_array_size; \ update_array = update_array_ptr = curr_ua->update_array; \ } \ } /* The following macro resets update_array_ptr to point to update_array. * This needs to be done before using any BLK_* macros as part of a non-TP transaction. */ #define RESET_UPDATE_ARRAY \ { \ GBLREF char *update_array, *update_array_ptr; \ \ assert(NULL != update_array); \ /* reset update_array to the start */ \ update_array_ptr = update_array; \ } /* the following macro does what RESET_UPDATE_ARRAY does and additionally does some integrity checks */ #define CHECK_AND_RESET_UPDATE_ARRAY \ { \ GBLREF uint4 dollar_tlevel; \ GBLREF unsigned char cw_set_depth; \ \ assert(!dollar_tlevel); /* TP should never use this update_array */ \ assert(0 == cw_set_depth); /* ensure we never reset an active update_array */ \ RESET_UPDATE_ARRAY; \ } /* *************************************************************************** * BLK_INIT(BNUM, ARRAY) allocates: * blk_segment ARRAY[BLK_SEG_ARRAY_SIZE] * at the next octaword-aligned location in the update array and sets * BNUM = &ARRAY[1] */ #define BLK_INIT(BNUM, ARRAY) \ { \ GBLREF char *update_array, *update_array_ptr; \ \ update_array_ptr = (char*)ROUND_UP2((INTPTR_T)update_array_ptr, UPDATE_ELEMENT_ALIGN_SIZE); \ (ARRAY) = (blk_segment*)update_array_ptr; \ update_array_ptr += (BLK_SEG_ARRAY_SIZE * SIZEOF(blk_segment)); \ assert((update_array + update_array_size) - update_array_ptr >= 0); \ (BNUM) = (ARRAY + 1); \ blk_seg_cnt = SIZEOF(blk_hdr); \ } /* *************************************************************************** * BLK_SEG(BNUM, ADDR, LEN) adds a new entry to the blk_segment array */ #define BLK_SEG(BNUM, ADDR, LEN) \ { \ sm_ulong_t lcl_len1; \ GBLREF uint4 dollar_tlevel; \ \ /* Note that name of len variable "lcl_len1" should be different \ * from the name used in the REORG_BLK_SEG macro as otherwise \ * the below assignment will leave lcl_len1 uninitialized. \ */ \ lcl_len1 = (LEN); \ /* The function "gvcst_blk_build" (which uses this update array to build the block) relies on "len" to \ * be positive. This macro is called from both non-TP and TP code. In non-TP, we know of a few callers \ * (dse etc.) that could pass in a negative length to the BLK_SEG macro. Those are okay since we are \ * guaranteed the validation (in t_end inside of crit) would catch this case and force a restart thus \ * avoiding a call to gvcst_blk_build. But in TP, validations happen before commit time in tp_hist and \ * it has a few optimizations where for globals with NOISOLATION turned ON, it allows validation to \ * succeed even if the block contents changed concurrently. This means update arrays with negative \ * lengths could find their way to gvcst_blk_build even after tp_hist. Since those lengths are passed \ * directly to memmove which treats it as an unsigned quantity, it means huge memmoves that are likely \ * to cause memory corruption and/or SIG-11. Therefore it is absolutely necessary that if we are in TP \ * the caller does not pass in a negative length. Assert that. \ */ \ assert(!dollar_tlevel || (0 <= (sm_long_t)lcl_len1)); \ (BNUM)->addr = (ADDR); \ (BNUM)->len = lcl_len1; \ blk_seg_cnt += (int)lcl_len1; \ assert((char *)BNUM - update_array_ptr < 0); \ (BNUM)++; \ } /* *************************************************************************** * BLK_FINI(BNUM,ARRAY) finishes the update array by * BNUM->addr = 0 * BNUM-- * if the blk_seg_cnt is within range, then * ARRAY[0].addr = BNUM (address of last entry containing data) * ARRAY[0].len = blk_seg_cnt (total size of all block segments) * and it returns the value of blk_seg_cnt, * otherwise, it returns zero and the caller should invoke t_retry */ #define BLK_FINI(BNUM,ARRAY) \ ( \ (BNUM--)->addr = (uchar_ptr_t)0, \ (blk_seg_cnt <= blk_size && blk_seg_cnt >= SIZEOF(blk_hdr)) \ ? (ARRAY)[0].addr = (uchar_ptr_t)(BNUM), (ARRAY)[0].len = blk_seg_cnt \ : 0 \ ) /* *************************************************************************** * BLK_ADDR(X,Y,Z) allocates a space of length Y in the update array * and sets pointer X (of type Z) to the beginning of that space */ #ifdef DEBUG #define BLK_ADDR(X,Y,Z) \ ( \ update_array_ptr = (char*)(((INTPTR_T)update_array_ptr + 7) & ~7), \ assert((update_array + update_array_size - Y) - update_array_ptr >= 0), \ (X) = (Z*)update_array_ptr, update_array_ptr += (INTPTR_T)Y \ ) #else #define BLK_ADDR(X,Y,Z) \ ( \ update_array_ptr = (char*)(((INTPTR_T)update_array_ptr + 7) & ~7), \ (X) = (Z*)update_array_ptr, update_array_ptr += (INTPTR_T)Y \ ) #endif /* ******************************************************************************** * REORG_BLK_SEG(BNUM, ADDR, LEN) is the same as the BLK_SEG macro * except that it takes a private copy of the input memory and adds that * to the update array. This is necessary in case of MUPIP REORG for two * operations (Coalesce and Swap). In either cases, the contents of one block * will rely on the contents of itself and another block. This is not currently * supported by t_end where the assumption is that all contents needed to build * a buffer are available in that buffer itself (this greatly simplifies the * process of pinning of buffers in shared memory). To avoid cross-links to other * buffers, we need to take a copy of the other buffer's contents from shared * memory into private memory before adding it to the update array. This macro * should be called only by MUPIP REORG. An assert has been added to that effect. */ #define REORG_BLK_SEG(BNUM, ADDR, LEN) \ { \ char *lcl_ptr; \ sm_ulong_t lcl_len; \ \ GBLREF boolean_t mu_reorg_process; \ \ assert(mu_reorg_process); \ lcl_len = (LEN); \ if ((0 > (sm_long_t)lcl_len) || ((blk_seg_cnt + lcl_len) > blk_size)) \ { \ assert(CDB_STAGNATE > t_tries); \ return cdb_sc_blkmod; \ } \ BLK_ADDR(lcl_ptr, lcl_len, char); \ memcpy(lcl_ptr, (ADDR), lcl_len); \ BLK_SEG((BNUM), (sm_uc_ptr_t)lcl_ptr, lcl_len); \ } #endif fis-gtm-V6.0-003/sr_port/gdsbml.h0000644000032200000250000001261512201176156015461 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #define SIXTEEN_BLKS_FREE 0x55555555 #define FOUR_BLKS_FREE 0x55 #define THREE_BLKS_FREE 0x54 #define LCL_MAP_LEVL 0xFF #define BLK_BUSY 0x00 #define BLK_FREE 0x01 #define BLK_MAPINVALID 0x02 #define BLK_RECYCLED 0x03 #define BML_BITS_PER_BLK 2 #define THREE_BLKS_BITMASK 0x3F #define TWO_BLKS_BITMASK 0x0F #define ONE_BLK_BITMASK 0x03 #define BMP_EIGHT_BLKS_FREE 255 /* returns the bitmap status (BLK_BUSY|BLK_FREE|etc.) of the "blknum"th block within the local bitmap block "bp" in bml_status */ #define GET_BM_STATUS(bp, blknum, bml_status) \ { \ sm_uc_ptr_t ptr; \ \ ptr = ((sm_uc_ptr_t)(bp) + SIZEOF(blk_hdr) + ((blknum * BML_BITS_PER_BLK) / BITS_PER_UCHAR)); \ bml_status = (*ptr >> ((blknum * BML_BITS_PER_BLK) % BITS_PER_UCHAR)) & ((1 << BML_BITS_PER_BLK) - 1); \ } /* sets bitmap status (BLK_BUSY|BLK_FREE etc.) for the "blknum"th block within the local bitmap block "bp" from new_bml_status */ #define SET_BM_STATUS(bp, blknum, new_bml_status) \ { \ sm_uc_ptr_t ptr; \ \ assert(2 == BML_BITS_PER_BLK); \ ptr = ((sm_uc_ptr_t)(bp) + SIZEOF(blk_hdr) + ((blknum * BML_BITS_PER_BLK) / BITS_PER_UCHAR)); \ *ptr = (*ptr & ~(0x03 << ((blknum * BML_BITS_PER_BLK) % BITS_PER_UCHAR))) \ | ((new_bml_status & 0x03) << ((blknum * BML_BITS_PER_BLK) % BITS_PER_UCHAR)); \ } #define BM_MINUS_BLKHDR_SIZE(bplm) ((bplm) / (BITS_PER_UCHAR / BML_BITS_PER_BLK)) #define BM_SIZE(bplm) (SIZEOF(blk_hdr) + BM_MINUS_BLKHDR_SIZE(bplm)) #define VALIDATE_BM_BLK(blk, bp, csa, region, status) \ { \ error_def(ERR_DBBMLCORRUPT); /* BYPASSOK */ \ \ assert(BITS_PER_UCHAR % BML_BITS_PER_BLK == 0); /* assert this for the BM_MINUS_BLKHDR_SIZE macro */ \ if (IS_BITMAP_BLK(blk) && ((LCL_MAP_LEVL != (bp)->levl) || (BM_SIZE(csa->hdr->bplmap) != (bp)->bsiz)) \ UNIX_ONLY(DEBUG_ONLY(|| (gtm_white_box_test_case_enabled \ && (WBTEST_ANTIFREEZE_DBBMLCORRUPT == gtm_white_box_test_case_number))))) \ { \ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_DBBMLCORRUPT, 7, DB_LEN_STR(region), \ blk, (bp)->bsiz, (bp)->levl, &(bp)->tn, &csa->ti->curr_tn); \ status = FALSE; \ } else \ status = TRUE; \ } #define NO_FREE_SPACE -1 /* MAP_RD_FAIL is hard coded into the file BML_GET_FREE.MAR */ #define MAP_RD_FAIL -2 #define EXTEND_SUSPECT -3 #define FILE_EXTENDED -4 #define FINAL_RETRY_FREEZE_PROG -5 #define GET_CDB_SC_CODE(gdsfilext_code, status) \ { \ if (MAP_RD_FAIL == gdsfilext_code) \ status = (enum cdb_sc)rdfail_detail; \ else if (EXTEND_SUSPECT == gdsfilext_code) \ status = (enum cdb_sc)cdb_sc_extend; \ else if (NO_FREE_SPACE == gdsfilext_code) \ status = cdb_sc_gbloflow; \ else if (FINAL_RETRY_FREEZE_PROG == gdsfilext_code) \ status = cdb_sc_needcrit; \ } #define MASTER_MAP_BITS_PER_LMAP 1 #define DETERMINE_BML_FUNC_COMMON(FUNC, CS, CSA) \ { \ FUNC = (CS->reference_cnt > 0) ? bml_busy : (CSA->hdr->db_got_to_v5_once ? bml_recycled : bml_free); \ } #ifndef UNIX #define DETERMINE_BML_FUNC(FUNC, CS, CSA) DETERMINE_BML_FUNC_COMMON(FUNC, CS, CSA) #else # define DETERMINE_BML_FUNC(FUNC, CS, CSA) \ { \ GBLREF boolean_t mu_reorg_upgrd_dwngrd_in_prog; \ \ if (CSA->nl->trunc_pid) \ { /* A truncate is in progress. If we are acquiring a block, we need to update cnl->highest_lbm_with_busy_blk to \ * avoid interfering with the truncate. If we are truncate doing a t_recycled2free mini-transaction, we need to \ * select bml_free. \ */ \ if (cs->reference_cnt > 0) \ { \ FUNC = bml_busy; \ CSA->nl->highest_lbm_with_busy_blk = MAX(CS->blk, CSA->nl->highest_lbm_with_busy_blk); \ } else if (cs->reference_cnt < 0) \ { \ if (CSA->hdr->db_got_to_v5_once && (CSE_LEVEL_DRT_LVL0_FREE != CS->level)) \ FUNC = bml_recycled; \ else \ { /* always set the block as free when gvcst_bmp_mark_free a level-0 block in DIR tree; reset \ * level since t_end will call bml_status_check which has an assert for bitmap block level \ */ \ FUNC = bml_free; \ CS->level = LCL_MAP_LEVL; \ } \ } else /* cs->reference_cnt == 0 */ \ { \ if (CSA->hdr->db_got_to_v5_once && mu_reorg_upgrd_dwngrd_in_prog) \ FUNC = bml_recycled; \ else \ FUNC = bml_free; \ } \ } else /* Choose bml_func as it was chosen before truncate feature. */ \ DETERMINE_BML_FUNC_COMMON(FUNC, CS, CSA); \ } #endif int4 bml_find_free(int4 hint, uchar_ptr_t base_addr, int4 total_bits); int4 bml_init(block_id bml); uint4 bml_busy(uint4 setbusy, sm_uc_ptr_t map); uint4 bml_free(uint4 setfree, sm_uc_ptr_t map); uint4 bml_recycled(uint4 setfree, sm_uc_ptr_t map); fis-gtm-V6.0-003/sr_port/gdsbt.h0000644000032200000250000006422612201176156015321 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GDSBT_H #define GDSBT_H /* this requires gdsroot.h */ #include #ifdef MUTEX_MSEM_WAKE #ifdef POSIX_MSEM # include #else # include #endif #endif #ifdef VMS # include /* for SS$_WASSET */ # include "ast.h" /* for ENABLE/DISABLE */ #elif defined(UNIX) # include /* for _POSIX_HOST_NAME_MAX */ # if defined(__osf__) # include /* for _POSIX_HOST_NAME_MAX */ # elif defined(SUNOS) && !defined(_POSIX_HOST_NAME_MAX) # include /* for MAXHOSTNAMELEN (Solaris 9) */ # endif #endif #include "gvstats_rec.h" #define CR_NOTVALID (-1L) #define GTM64_WC_MAX_BUFFS (2*1024*1024)-1 /* to fit in an int4 */ #define WC_MAX_BUFFS 64*1024 #define WC_DEF_BUFFS 128 #define WC_MIN_BUFFS 64 #define MAX_LOCK_SPACE 65536 /* need to change these whenever global directory defaults change */ #define MIN_LOCK_SPACE 10 #define MAX_REL_NAME 36 #define MAX_MCNAMELEN 256 /* We do not support hostname truncation */ #if defined(UNIX) # if defined(_POSIX_HOST_NAME_MAX) # if MAX_MCNAMELEN <= _POSIX_HOST_NAME_MAX /* _POSIX_HOST_NAME_MAX excludes terminating NULL */ # error MAX_MCNAMELEN is not greater than _POSIX_HOST_NAME_MAX. # endif # elif defined(MAXHOSTNAMELEN) # if MAX_MCNAMELEN < MAXHOSTNAMELEN /* MAXHOSTNAMELEN includes terminating NULL */ # error MAX_MCNAMELEN is less than MAXHOSTNAMELEN. # endif # else # error _POSIX_HOST_NAME_MAX or MAXHOSTNAMELEN not defined. # endif #endif #define GDS_LABEL_SZ 12 #define MAX_DB_WTSTARTS 2 /* Max number of "flush-timer driven" simultaneous writers in wcs_wtstart */ #define MAX_WTSTART_PID_SLOTS 4 * MAX_DB_WTSTARTS /* Max number of PIDs for wcs_wtstart to save */ #define MAX_KIP_PID_SLOTS 8 #define BT_FACTOR(X) (X) #define FLUSH_FACTOR(X) ((X)-(X)/16) #define BT_QUEHEAD (-2) #define BT_NOTVALID (-1) #define BT_MAXRETRY 3 #define BT_SIZE(X) ((((sgmnt_data_ptr_t)X)->bt_buckets + 1 + ((sgmnt_data_ptr_t)X)->n_bts) * SIZEOF(bt_rec)) /* parameter is *sgmnt_data*/ /* note that the + 1 above is for the th_queue head which falls between the hash table and the */ /* actual bts */ #define HEADER_UPDATE_COUNT 1024 #define LAST_WBOX_SEQ_NUM 1000 typedef struct { trans_num curr_tn; trans_num early_tn; trans_num last_mm_sync; /* Last tn where a full mm sync was done */ char filler_8byte[8]; /* previously header_open_tn but no longer used. * cannot remove as this is part of database file header */ trans_num mm_tn; /* Used to see if CCP must update master map */ uint4 lock_sequence; /* Used to see if CCP must update lock section */ uint4 ccp_jnl_filesize; /* Passes size of journal file if extended */ volatile uint4 total_blks; /* Placed here so can be passed to other machines on cluster */ volatile uint4 free_blocks; } th_index; typedef struct { struct { sm_off_t fl; sm_off_t bl; /* self-relative queue entry */ } blkque, tnque; /* for block number hash, lru queue */ trans_num tn; /* transaction # #*/ trans_num killtn; /* last transaction when this block was updated as part of an M-kill */ block_id blk; /* block #*/ int4 cache_index; bool flushing; /* buffer is being flushed after a machine switch on a cluster */ char filler[3]; int4 filler_int4; /* maintain 8 byte alignment */ } bt_rec; /* block table record */ /* This structure is used to access the transaction queue. It points at all but the first two longwords of a bt_rec. CAUTION: there is no such thing as a queue of th_recs, they are always bt_recs, and the extra two longwords are always there */ typedef struct { struct { sm_off_t fl; sm_off_t bl; } tnque; trans_num tn; trans_num killtn; /* last transaction when this block was updated as part of an M-kill */ block_id blk; int4 cache_index; bool flushing; char filler[3]; int4 filler_int4; /* maintain 8 byte alignment */ } th_rec; /* This structure is used to maintain all cache records. The BT queue contains a history of those blocks that have been updated. */ /* * Definitions for GT.M Mutex Control * * See MUTEX.MAR for VMS functional implementation */ typedef struct { struct { sm_off_t fl, bl; } que; int4 pid; void *super_crit; #if defined(UNIX) /* * If the following fields are to be made part of VMS too, change * size of mutex_que_entry in mutex.mar (lines 118, 152). * Make sure that the size of mutex_que_entry is a multiple of 8 bytes * for quadword alignment requirements of remqhi and insqti. */ int4 mutex_wake_instance; int4 filler1; /* for dword alignment */ #ifdef MUTEX_MSEM_WAKE #ifdef POSIX_MSEM sem_t mutex_wake_msem; /* Not two ints .. somewhat larger */ #else msemaphore mutex_wake_msem; /* Two ints (incidentally two int4s) */ #endif #endif #endif } mutex_que_entry; typedef struct { struct { sm_off_t fl, bl; } que; global_latch_t latch; } mutex_que_head; typedef struct { #if defined(UNIX) FILL8DCL(uint4, crit_cycle, 1); global_latch_t semaphore; CACHELINE_PAD(8 + SIZEOF(global_latch_t), 2) /* 8 for the FILL8DCL */ FILL8DCL(latch_t, crashcnt, 3); global_latch_t crashcnt_latch; CACHELINE_PAD(8 + SIZEOF(global_latch_t), 4) /* 8 for the FILL8DCL */ compswap_time_field stuckexec; CACHELINE_PAD(SIZEOF(compswap_time_field), 5) FILL8DCL(latch_t, queslots, 6); CACHELINE_PAD(SIZEOF(latch_t) + SIZEOF(latch_t), 7) mutex_que_head prochead; CACHELINE_PAD(SIZEOF(mutex_que_head), 8) mutex_que_head freehead; CACHELINE_PAD(SIZEOF(mutex_que_head), 9) #elif defined(VMS) short semaphore; unsigned short wrtpnd; short crashcnt, queslots; #ifdef __alpha /* use constant instead of defining CACHELINE_SIZE since we do not want to affect other structures the 64 must match padding in mutex.mar and mutex_stoprel.mar */ char filler1[64 - SIZEOF(short)*4]; #endif mutex_que_entry prochead; #ifdef __alpha char filler2[64 - SIZEOF(mutex_que_entry)]; #endif mutex_que_entry freehead; #else #error UNSUPPORTED PLATFORM #endif } mutex_struct; typedef struct { /* keep this structure and member offsets defined in sr_avms/mutex.mar in sync */ int4 mutex_hard_spin_count; int4 mutex_sleep_spin_count; int4 mutex_spin_sleep_mask; /* currently unused */ int4 mutex_que_entry_space_size; /* total number of entries */ } mutex_spin_parms_struct; enum crit_ops { crit_ops_gw = 1, /* grab [write] crit */ crit_ops_rw, /* rel [write] crit */ crit_ops_nocrit /* did a rel_crit when now_crit flag was off */ }; typedef struct { caddr_t call_from; enum crit_ops crit_act; int4 epid; trans_num curr_tn; } crit_trace; typedef struct { sm_off_t cr_off; trans_num cr_tn; uint4 process_id; block_id blk; uint4 cycle; } dskread_trace; #define OP_LOCK_SIZE 4 /* Structure to hold lock history */ typedef struct { sm_int_ptr_t lock_addr; /* Address of actual lock */ caddr_t lock_callr; /* Address of (un)locker */ int4 lock_pid; /* Process id of (un)locker */ int4 loop_cnt; /* iteration count of lock retry loop */ char lock_op[OP_LOCK_SIZE]; /* Operation performed (either OBTN or RLSE) */ } lockhist; enum ftok_ops { ftok_ops_lock = 1, ftok_ops_release }; typedef struct { enum ftok_ops ftok_oper; uint4 process_id; trans_num cr_tn; } ftokhist; #define DSKREAD_OPS_ARRAY_SIZE 512 #define CRIT_OPS_ARRAY_SIZE 512 #define LOCKHIST_ARRAY_SIZE 512 #define SECSHR_OPS_ARRAY_SIZE 1023 /* 1 less than 1K to accommodate the variable secshr_ops_index */ #define FTOK_OPS_ARRAY_SIZE 512 /* SECSHR_ACCOUNTING macro assumes csa->nl is dereferencible and does accounting if variable "do_accounting" is set to TRUE */ #define SECSHR_ACCOUNTING(value) \ { \ if (do_accounting) \ { \ if (csa->nl->secshr_ops_index < SECSHR_OPS_ARRAY_SIZE) \ csa->nl->secshr_ops_array[csa->nl->secshr_ops_index] = (gtm_uint64_t)(value); \ csa->nl->secshr_ops_index++; \ } \ } /* Mapped space local to each node on the cluster */ typedef struct node_local_struct { unsigned char label[GDS_LABEL_SZ]; /* 12 signature for GDS shared memory */ unsigned char fname[MAX_FN_LEN + 1]; /* 256 filename of corresponding database */ char now_running[MAX_REL_NAME]; /* 36 current active GT.M version stamp */ char machine_name[MAX_MCNAMELEN]; /* 256 machine name for clustering */ sm_off_t bt_header_off; /* (QW alignment) offset to hash table */ sm_off_t bt_base_off; /* bt first entry */ sm_off_t th_base_off; sm_off_t cache_off; sm_off_t cur_lru_cache_rec_off; /* current LRU cache_rec pointer offset */ sm_off_t critical; sm_off_t jnl_buff; sm_off_t shmpool_buffer; /* Shared memory buffer pool area */ sm_off_t lock_addrs; sm_off_t hdr; /* Offset to file-header (BG mode ONLY!) */ volatile int4 in_crit; int4 in_reinit; unsigned short ccp_cycle; unsigned short filler; /* Align for ccp_cycle. Not changing to int as that would perturb to many things at this point */ boolean_t ccp_crit_blocked; int4 ccp_state; boolean_t ccp_jnl_closed; boolean_t glob_sec_init; uint4 wtstart_pid[MAX_WTSTART_PID_SLOTS]; /* Maintain pids of wcs_wtstart processes */ volatile boolean_t wc_blocked; /* Set to TRUE by process that knows it is leaving the cache in a * possibly inconsistent state. Next process grabbing crit will do * cache recovery. This setting also stops all concurrent writers * from working on the cache. In MM mode, it is used to call * wcs_recover during a file extension */ global_latch_t wc_var_lock; /* latch used for access to various wc_* ref counters */ CACHELINE_PAD(SIZEOF(global_latch_t), 1) /* Keep these two latches in separate cache lines */ global_latch_t db_latch; /* latch for interlocking on hppa and tandem */ CACHELINE_PAD(SIZEOF(global_latch_t), 2) int4 cache_hits; int4 wc_in_free; /* number of write cache records in free queue */ /* All counters below (declared using CNTR4DCL) are 2 or 4-bytes, depending on platform, but always stored in 4 bytes. * CACHELINE_PAD doesn't use SIZEOF because misses any padding added by CNTR4DCL. We want to keep the counters in * separate cachelines on load-lock/store-conditional platforms particularly and on other platforms too, just to be safe. */ volatile CNTR4DCL(wcs_timers, 1); /* number of write cache timers in use - 1 */ CACHELINE_PAD(4, 3) volatile CNTR4DCL(wcs_active_lvl, 2); /* number of entries in active queue */ CACHELINE_PAD(4, 4) volatile CNTR4DCL(wcs_staleness, 3); CACHELINE_PAD(4, 5) volatile CNTR4DCL(ref_cnt, 4); /* reference count. How many people are using the database */ CACHELINE_PAD(4, 6) volatile CNTR4DCL(intent_wtstart, 5); /* Count of processes that INTEND to enter wcs_wtstart code */ CACHELINE_PAD(4, 7) volatile CNTR4DCL(in_wtstart, 6); /* Count of processes that are INSIDE wcs_wtstart code */ CACHELINE_PAD(4, 8) volatile CNTR4DCL(wcs_phase2_commit_pidcnt, 7); /* number of processes actively finishing phase2 commit */ CACHELINE_PAD(4, 9) int4 mm_extender_pid; /* pid of the process executing gdsfilext in MM mode */ int4 highest_lbm_blk_changed; /* Records highest local bit map block that changed so we know how much of master bit map to write out. Modified only under crit */ int4 nbb; /* Next backup block -- for online backup */ int4 lockhist_idx; /* (DW alignment) "circular" index into lockhists array */ int4 crit_ops_index; /* "circular" index into crit_ops_array */ int4 dskread_ops_index; /* "circular" index into dskread_ops_array */ int4 ftok_ops_index; /* "circular" index into ftok_ops_array */ lockhist lockhists[LOCKHIST_ARRAY_SIZE]; /* Keep lock histories here */ crit_trace crit_ops_array[CRIT_OPS_ARRAY_SIZE]; /* space for CRIT_TRACE macro to record info */ dskread_trace dskread_ops_array[DSKREAD_OPS_ARRAY_SIZE]; /* space for DSKREAD_TRACE macro to record info */ unique_file_id unique_id; uint4 owner_node; volatile int4 wcsflu_pid; /* pid of the process executing wcs_flu in BG mode */ int4 creation_date_time4; /* Lower order 4-bytes of database's creation time to be * compared at sm attach time */ int4 inhibit_kills; /* inhibit new KILLs while MUPIP BACKUP, INTEG or FREEZE are * waiting for kill-in-progress to become zero */ boolean_t remove_shm; /* can this shm be removed by the last process to rundown */ union { gds_file_id jnl_file_id; /* needed on UNIX to hold space */ unix_file_id u; /* from gdsroot.h even for VMS */ } jnl_file; /* Note that in versions before V4.3-001B, "jnl_file" used to be a member of sgmnt_data. * Now it is a filler there and rightly used here since it is non-zero only when shared memory is active. */ boolean_t donotflush_dbjnl; /* whether database and journal can be flushed to disk or not (TRUE for mupip recover) */ int4 n_pre_read; char replinstfilename[MAX_FN_LEN + 1];/* 256 : Name of the replication instance file corresponding to this db. * In VMS, this is the name of the corresponding global directory. */ int4 secshr_ops_index; gtm_uint64_t secshr_ops_array[SECSHR_OPS_ARRAY_SIZE]; /* taking up 8K */ gvstats_rec_t gvstats_rec; trans_num last_wcsflu_tn; /* curr_tn when last wcs_flu was done on this database */ sm_off_t encrypt_glo_buff_off; /* offset from unencrypted global buffer to its encrypted counterpart */ global_latch_t snapshot_crit_latch; /* To be acquired by any process that wants to clean up an orphaned snapshot or * initiate a new snapshot */ long ss_shmid; /* Identifier of the shared memory for the snapshot that started * recently. */ uint4 ss_shmcycle; /* incremented everytime a new snapshot creates a new shared memory identifier */ boolean_t snapshot_in_prog; /* Tells GT.M if any snapshots are in progress */ uint4 num_snapshots_in_effect; /* how many snapshots are currently in place for this region */ uint4 wbox_test_seq_num; /* used to coordinate with sequential testing steps */ NON_GTM64_ONLY(int4 filler_8byte_align;) /* To align the following member at an 8-byte boundry on 32-bit platforms */ UNIX_ONLY(pid_t kip_pid_array[MAX_KIP_PID_SLOTS];) /* Processes actively doing kill (0 denotes empty slots) */ gtm_uint64_t sec_size; /* Upon going to larger shared memory sizes, we realized that this does not */ /* need to be in the file header but the node local since it can be calculated */ /* from info in the file header. */ int4 jnlpool_shmid; /* copy of jnlpool.repl_inst_filehdr->jnlpool_shmid to prevent mixing of multiple * journal pools within the same database. */ boolean_t lockspacefull_logged; /* Avoids flooding syslog with LOCKSPACEFULL messages. * If TRUE: LOCKSPACEFULL is written to the syslog. * If FALSE: Do not write LOCKSPACEFULL to syslog. * Set this to FALSE if free space ratio is above * LOCK_SPACE_FULL_SYSLOG_THRESHOLD (defined in mlk_unlock.h). * We exclude mlk_shrsub, and only consider mlk_prcblk & mlk_shrblk. */ uint4 trunc_pid; /* Operating truncate. */ block_id highest_lbm_with_busy_blk; /* Furthest lmap block known to have had a busy block during truncate. */ # if defined(UNIX) ftokhist ftok_ops_array[FTOK_OPS_ARRAY_SIZE]; volatile uint4 root_search_cycle; /* incremented online rollback ends and mu_swap_root */ volatile uint4 onln_rlbk_cycle; /* incremented everytime an online rollback ends */ volatile uint4 db_onln_rlbkd_cycle; /* incremented everytime an online rollback takes the database back in time */ volatile uint4 onln_rlbk_pid; /* process ID of currently running online rollback. */ uint4 dbrndwn_ftok_skip; /* # of processes that skipped FTOK semaphore in gds_rundown due to too many MUMPS processes */ uint4 dbrndwn_access_skip; /* # of processes that skipped access control semaphore in gds_rundown due to a concurrent online rollback or too many MUMPS processes */ boolean_t fastinteg_in_prog; /* Tells GT.M if fast integrity is in progress */ uint4 wtstart_errcnt; /* Note that although the below two fields are dbg-only, they are defined for pro since we want to keep the shared * memory layout the same for both pro and dbg. There is some code that relies on this assumption. */ boolean_t fake_db_enospc; /* used only by dbg versions to simulate ENOSPC scenarios in the database file */ boolean_t fake_jnl_enospc; /* used only by dbg versions to simulate ENOSPC scenarios in the journal file */ # endif } node_local; #define DSKREAD_TRACE(CSA, CR_OFF, CR_TN, PID, BLK, CYCLE) \ { \ int4 doidx; \ node_local_ptr_t cnl; \ assert((NULL != CSA)&& (NULL != (CSA->nl))); \ cnl = CSA->nl; \ doidx = ++cnl->dskread_ops_index; \ if (DSKREAD_OPS_ARRAY_SIZE <= doidx) \ doidx = cnl->dskread_ops_index = 0; \ cnl->dskread_ops_array[doidx].cr_off = CR_OFF; \ cnl->dskread_ops_array[doidx].cr_tn = CR_TN; \ cnl->dskread_ops_array[doidx].process_id = PID; \ cnl->dskread_ops_array[doidx].blk = BLK; \ cnl->dskread_ops_array[doidx].cycle = CYCLE; \ } #ifdef DEBUG /* The following macro does not use a separate semaphore to protect its maintenance of the shared memory * value crit_ops_index (which would complicate precisely the situation it was created to examine) therefore, * in order to to maximize the chances of gathering meaningful data, it seems better placed after grab_crit * and before rel_crit. Also we will increment the index first and cache it so we can shorten our exposure window. */ #define CRIT_TRACE(X) \ { \ int4 coidx; \ node_local_ptr_t cnl; \ boolean_t in_ast; \ unsigned int ast_status; \ \ assert((NULL != csa) && (NULL !=(csa->nl))); \ cnl = csa->nl; \ coidx = ++cnl->crit_ops_index; \ if (CRIT_OPS_ARRAY_SIZE <= coidx) \ coidx = cnl->crit_ops_index = 0; \ VMS_ONLY( \ in_ast = lib$ast_in_prog(); \ if (!in_ast) \ ast_status = sys$setast(DISABLE); \ ) \ cnl->crit_ops_array[coidx].call_from = (caddr_t)caller_id(); \ VMS_ONLY( \ if ((!in_ast) && (SS$_WASSET == ast_status)) \ sys$setast(ENABLE); \ ) \ cnl->crit_ops_array[coidx].epid = process_id; \ cnl->crit_ops_array[coidx].crit_act = (X); \ cnl->crit_ops_array[coidx].curr_tn = (NULL != csa->hdr) ? \ csa->hdr->trans_hist.curr_tn : 0; \ } /* The following macro checks that curr_tn and early_tn are equal right before beginning a transaction commit. * The only exception we know of is if a process in the midst of commit had been killed (kill -9 or STOP/ID) * after having incremented early_tn but before it finished the commit (and therefore incremented curr_tn). * In that case another process that did a rundown (and executed secshr_db_clnup) at around the same time * could have cleaned up the CRIT lock (sensing that the crit holder pid is no longer alive) making the crit * lock available for other processes. To check if that is the case, we need to go back the crit_ops_array and check that * a) the most recent crit operation was a grab crit done by the current pid (crit_act == crit_ops_gw) AND * b) the immediately previous crit operation should NOT be a release crit crit_ops_rw but instead should be a crit_ops_gw * c) there are two exceptions to this and they are * (i) that there could be one or more crit_ops_nocrit actions from processes that tried releasing crit * even though they dont own it (cases we know of are in gds_rundown and in t_end/tp_tend if * t_commit_cleanup completes the transaction after a mid-commit error). * (ii) there could be one or more crit_ops_gw/crit_ops_rw pair of operations by a pid in between. */ #define ASSERT_CURR_TN_EQUALS_EARLY_TN(csa, currtn) \ { \ GBLREF uint4 process_id; \ \ assert((currtn) == csa->ti->curr_tn); \ if (csa->ti->early_tn != (currtn)) \ { \ int4 coidx, lcnt; \ node_local_ptr_t cnl; \ uint4 expect_gw_pid = 0; \ \ cnl = csa->nl; \ assert(NULL != (node_local_ptr_t)cnl); \ coidx = cnl->crit_ops_index; \ assert(CRIT_OPS_ARRAY_SIZE > coidx); \ assert(crit_ops_gw == cnl->crit_ops_array[coidx].crit_act); \ assert(process_id == cnl->crit_ops_array[coidx].epid); \ for (lcnt = 0; CRIT_OPS_ARRAY_SIZE > lcnt; lcnt++) \ { \ if (coidx) \ coidx--; \ else \ coidx = CRIT_OPS_ARRAY_SIZE - 1; \ if (crit_ops_nocrit == cnl->crit_ops_array[coidx].crit_act) \ continue; \ if (crit_ops_rw == cnl->crit_ops_array[coidx].crit_act) \ { \ assert(0 == expect_gw_pid); \ expect_gw_pid = cnl->crit_ops_array[coidx].epid; \ } else if (crit_ops_gw == cnl->crit_ops_array[coidx].crit_act) \ { \ if (!expect_gw_pid) \ break; /* found lone grab-crit */ \ assert(expect_gw_pid == cnl->crit_ops_array[coidx].epid); \ expect_gw_pid = 0;/* found paired grab-crit. continue search */ \ } \ } \ assert(CRIT_OPS_ARRAY_SIZE > lcnt); /* assert if did not find lone grab-crit */ \ } \ } /* * The following macro places lock history entries in an array for debugging. * NOTE: Users of this macro, set either of the following prior to using this macro. * (i) gv_cur_region to the region whose history we are storing. * (ii) global variable "locknl" to correspond to the node-local of the region whose history we are storing. * If "locknl" is non-NULL, it is used to store the lock history. If not only then is gv_cur_region used. */ #define LOCK_HIST(OP, LOC, ID, CNT) \ { \ GBLREF node_local_ptr_t locknl; \ \ int lockidx; \ node_local_ptr_t lcknl; \ \ if (NULL == locknl) \ { \ assert(NULL != gv_cur_region); \ lcknl = FILE_INFO(gv_cur_region)->s_addrs.nl; \ assert(NULL != lcknl); \ } else \ lcknl = locknl; \ lockidx = ++lcknl->lockhist_idx; \ if (LOCKHIST_ARRAY_SIZE <= lockidx) \ lockidx = lcknl->lockhist_idx = 0; \ GET_LONGP(&lcknl->lockhists[lockidx].lock_op[0], (OP)); \ lcknl->lockhists[lockidx].lock_addr = (sm_int_ptr_t)(LOC); \ lcknl->lockhists[lockidx].lock_callr = (caddr_t)caller_id(); \ lcknl->lockhists[lockidx].lock_pid = (int4)(ID); \ lcknl->lockhists[lockidx].loop_cnt = (int4)(CNT); \ } #define DUMP_LOCKHIST() dump_lockhist() #else #define CRIT_TRACE(X) #define ASSERT_CURR_TN_EQUALS_EARLY_TN(csa, currtn) #define LOCK_HIST(OP, LOC, ID, CNT) #define DUMP_LOCKHIST() #endif #define FTOK_TRACE(CSA, CR_TN, FTOK_OPER, PID) \ { \ node_local_ptr_t cnl; \ int4 foindx; \ assert(NULL != CSA); \ if (cnl = (CSA->nl)) \ { \ foindx = ++cnl->ftok_ops_index; \ if (FTOK_OPS_ARRAY_SIZE <= cnl->ftok_ops_index) \ foindx = cnl->ftok_ops_index = 0; \ cnl->ftok_ops_array[foindx].process_id = PID; \ cnl->ftok_ops_array[foindx].cr_tn = CR_TN; \ cnl->ftok_ops_array[foindx].ftok_oper = FTOK_OPER; \ } \ } #define BT_NOT_ALIGNED(bt, bt_base) (!IS_PTR_ALIGNED((bt), (bt_base), SIZEOF(bt_rec))) #define BT_NOT_IN_RANGE(bt, bt_lo, bt_hi) (!IS_PTR_IN_RANGE((bt), (bt_lo), (bt_hi))) #define MIN_CRIT_ENTRY 1024 #define MAX_CRIT_ENTRY 32768 #define DEFAULT_NUM_CRIT_ENTRY 1024 #define NUM_CRIT_ENTRY(CSD) (CSD)->mutex_spin_parms.mutex_que_entry_space_size #define CRIT_SPACE(ENTRIES) ((ENTRIES) * SIZEOF(mutex_que_entry) + SIZEOF(mutex_struct)) #define JNLPOOL_CRIT_SPACE CRIT_SPACE(DEFAULT_NUM_CRIT_ENTRY) #define NODE_LOCAL_SIZE (ROUND_UP(SIZEOF(node_local), OS_PAGE_SIZE)) #define NODE_LOCAL_SPACE(CSD) (ROUND_UP(CRIT_SPACE(NUM_CRIT_ENTRY(CSD)) + NODE_LOCAL_SIZE, OS_PAGE_SIZE)) #define MIN_NODE_LOCAL_SPACE (ROUND_UP(CRIT_SPACE(MIN_CRIT_ENTRY) + NODE_LOCAL_SIZE, OS_PAGE_SIZE)) /* In order for gtmsecshr not to pull in OTS library, NODE_LOCAL_SIZE_DBS is used in secshr_db_clnup instead of NODE_LOCAL_SIZE */ #define NODE_LOCAL_SIZE_DBS (ROUND_UP(SIZEOF(node_local), DISK_BLOCK_SIZE)) #define INIT_NUM_CRIT_ENTRY_IF_NEEDED(CSD) \ { /* The layout of shared memory depends on the number of mutex queue entries specified in the file header. Thus in \ * order to set, for example, csa->critical or csa->shmpool_buffer, we need to know this number. However, this \ * number can be zero if we have not yet done db_auto_upgrade. So go ahead and upgrade to the value that will \ * eventually be used, which is DEFAULT_NUM_CRIT_ENTRY. \ */ \ /* Be safe in PRO and check if we need to initialize crit entries, even for GDSMV60002 and later. */ \ if (0 == NUM_CRIT_ENTRY(CSD)) \ NUM_CRIT_ENTRY(CSD) = DEFAULT_NUM_CRIT_ENTRY; \ } /* Define pointer types for above structures that may be in shared memory and need 64 bit pointers. */ #ifdef DB64 # ifdef __osf__ # pragma pointer_size(save) # pragma pointer_size(long) # else # error UNSUPPORTED PLATFORM # endif #endif typedef bt_rec *bt_rec_ptr_t; typedef th_rec *th_rec_ptr_t; typedef th_index *th_index_ptr_t; typedef mutex_struct *mutex_struct_ptr_t; typedef mutex_spin_parms_struct *mutex_spin_parms_ptr_t; typedef mutex_que_entry *mutex_que_entry_ptr_t; typedef node_local *node_local_ptr_t; #define OLDEST_HIST_TN(CSA) (DBG_ASSERT(CSA->hdr) DBG_ASSERT(CSA->hdr->acc_meth != dba_mm) \ ((th_rec_ptr_t)((sm_uc_ptr_t)CSA->th_base + CSA->th_base->tnque.fl))->tn) #define SET_OLDEST_HIST_TN(CSA, TN) (DBG_ASSERT(CSA->hdr) DBG_ASSERT(CSA->hdr->acc_meth != dba_mm) \ ((th_rec_ptr_t)((sm_uc_ptr_t)CSA->th_base + CSA->th_base->tnque.fl))->tn = TN) #ifdef DB64 # ifdef __osf__ # pragma pointer_size(restore) # endif #endif #include "cdb_sc.h" bt_rec_ptr_t bt_get(int4 block); void dump_lockhist(void); void wait_for_block_flush(bt_rec *bt, block_id block); #endif fis-gtm-V6.0-003/sr_port/gdscc.h0000644000032200000250000002757112201176156015303 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GDSCC_H__ #define __GDSCC_H__ /* this requires gdsroot.h gtm_facilit.h fileinfo.h gdsbt.h gdsfhead.h gdir.h gdskey.h */ #include /* BIG_UA is the maximum size of a single update array specified as an unsigned quantity (usages rely on this). It is 16MB. */ #define BIG_UA (uint4)16777216 #define CDB_R_SET_SIZE 32 #define CDB_CW_SET_SIZE (MAX_BT_DEPTH * 3 + 1 + 2) #define CDB_W_SET_SIZE 16 /* CDB_CW_SET_SIZE = 24 * 3 for all the levels (including updated block, newly created sibling and possible bitmap update) * 1 extra for the root level (to take care of gds_t_write_root case) * 2 in the case of creation of a new global variable (1 index block with a * key and 1 data block * containing the key) */ #define CDB_T_CREATE 0 #define CDB_T_WRITE 1 #define CDB_T_WRITE_ROOT 2 /* The following defines the write_type for a block that is going to be updated. * GDS_WRITE_PLAIN is the default type for most updates. * GDS_WRITE_BLOCK_SPLIT is set in case of a block update due to a block split. It is currently not used anywhere in the code. * GDS_WRITE_KILLTN requires a little more explanation. * * The TP commit logic ("tp_tend") makes use of an optimization referred to as the "indexmod" optimization. * This optimization tries to avoid a restart in the case where a TP transaction does a SET to a data block and later finds * at TCOMMIT time that the index block which was part of the SET had been updated by a concurrent SET (or a REORG split * operation) to a different data block (that also had the same index block as an ancestor) which resulted in a block split * causing the index block to be updated. In this case there is no reason to restart. The index block could have been * modified by other operations as well (e.g. M-kill, REORG coalesce or swap operations or any DSE command or a block split * operation that caused the height of the global variable tree to increase [C9B11-001813]). In these cases, we dont want * this optimization to take effect as we cant be sure everything that was relied upon for the TP transaction was still valid. * These disallowed operations are generically referred to as "kill" type of operations. This optimization is implemented by * having a field "killtn" (name derived from "kill" type of operations) in the bt (block-table) structure for each block. * This field is assigned the same value as the "tn" whenever an index block gets updated due to one of the disallowed operations. * Otherwise it stays untouched (i.e. killtn <= tn at all times). It is the "killtn" (and not "tn") that is used in the * cdb_sc_blkmod validation check in tp_tend if we are validating a index block. Since KILLs, MUPIP REORG and/or DSE operations * are usually rare compared to SET activity, most of the cases we expect the indexmod optimization to be in effect and * therefore help reduce the # of TP restarts due to index block changes. Note that each SET/GET/KILL operation in TP goes * through an intermediate validation routine tp_hist which does the cdb_sc_blkmod validation using "tn" (not "killtn"). * Only if that passed, do we relax the commit time validation for index blocks. * * The operations that are not allowed to use this optimization (M-kill, REORG or DSE) are supposed to make sure they * set the write_type of the cw-set-element to GDS_WRITE_KILLTN. Failing to do so cause "killtn" in the bt to NOT be uptodate * which in turn can cause false validation passes (in the cdb_sc_blkmod check) causing GT.M processes to incorrectly commit * when they should not. This can lead to GT.M/application level data integrity errors. */ #define GDS_WRITE_PLAIN 0 #define GDS_WRITE_KILLTN 1 #define GDS_WRITE_BLOCK_SPLIT 2 /* blk_prior_state's last bit indicates whether the block was free before update * BLOCK FREE: 0b*******1, BLOCK NOT FREE: 0b*******0 */ #define BIT_SET_FREE(X) ((X) |= 0x00000001) #define BIT_CLEAR_FREE(X) ((X) &= 0xfffffffe) #define WAS_FREE(X) ((X) & 0x00000001) /* blk_prior_state's last but one bit indicates whether the block was recycled before update * BLOCK RECYCLED: 0b******1*, BLOCK NOT RECYCLED: 0b******0* */ #define BIT_SET_RECYCLED_AND_CLEAR_FREE(X) ((X) = ((X) & 0xfffffffc) + 0x00000002) #define BIT_CLEAR_RECYCLED_AND_SET_FREE(X) ((X) = ((X) & 0xfffffffc) + 0x00000001) #define BIT_CLEAR_RECYCLED(X) ((X) &= 0xfffffffd) #define BIT_SET_RECYCLED(X) ((X) |= 0x00000002) #define WAS_RECYCLED(X) (((X) & 0x00000002)) /* blk_prior_state's last but two bit indicates whether the block was in directory tree or global variable tree * IN_GV_TREE: 0b*****1**, IN_DIR_TREE: 0b*****0** */ #define IN_GV_TREE 4 #define IN_DIR_TREE 0 #define BIT_SET_DIR_TREE(X) ((X) &= 0xfffffffb) #define BIT_SET_GV_TREE(X) ((X) |= 0x00000004) #define KEEP_TREE_STATUS 0x00000004 /* macro to traverse to the end of an horizontal cw_set_element list */ #define TRAVERSE_TO_LATEST_CSE(x) \ { \ GBLREF uint4 dollar_tlevel; \ \ assert(dollar_tlevel); \ if (x) \ for ( ; (x)->high_tlevel; x = (x)->high_tlevel) \ ; \ } typedef uint4 block_offset; typedef int4 block_index; /* If a new mode is added to the table below, make sure pre-existing mode usages in the current codebase are examined to see * if the new mode needs to be added there as well. For example, there is code in tp_incr_commit.c and tp_incr_clean_up.c * where gds_t_create and kill_t_create are used explicitly. If the new mode is yet another *create* type, then it might need * to be added in those places as well. */ enum gds_t_mode { gds_t_noop = 0, /* there is code that initializes stuff to 0 relying on it being equal to gds_t_noop */ gds_t_create, gds_t_write, gds_t_write_recycled, /* modify a recycled block (currently only done by MUPIP REORG UPGRADE/DOWNGRADE) */ gds_t_acquired, gds_t_writemap, gds_t_committed, /* t_end relies on this particular placement */ gds_t_write_root, /* t_end relies on this being AFTER gds_t_committed */ gds_t_busy2free, /* t_end relies on this being AFTER gds_t_committed */ gds_t_recycled2free, /* t_end relies on this being AFTER gds_t_committed */ n_gds_t_op, /* tp_tend and other routines rely on this being BEFORE kill_t* modes and AFTER all gds_t_* modes */ kill_t_create, /* tp_tend relies on this being AFTER n_gds_t_op */ kill_t_write, /* tp_tend relies on this being AFTER n_gds_t_op */ }; typedef struct key_value_struct { gv_key key; /* note that the following array holds the actual key contents */ char key_contents[DBKEYSIZE(MAX_KEY_SZ)]; mstr value; struct key_value_struct *next; } key_cum_value; /* Create/write set element. This is used to describe modification of a database block */ typedef struct cw_set_element_struct { trans_num tn; /* transaction number for bit maps */ sm_uc_ptr_t old_block; /* Address of 'before-image' of block to be over-written */ cache_rec_ptr_t cr; struct cw_set_element_struct *next_cw_set; struct cw_set_element_struct *prev_cw_set; /* linked list (vertical) of cw_set_elements with one link per block */ struct cw_set_element_struct *high_tlevel; struct cw_set_element_struct *low_tlevel; /* linked list (horizontal) of cw_set elements for a given block with * different transaction levels. Latest cw_set_elements (for a given block) * are inserted at the beginning of the horizontal list */ off_jnl_t jnl_freeaddr; /* journal update address */ uint4 write_type; /* can be GDS_WRITE_PLAIN or GDS_WRITE_KILLTN or GDS_WRITE_BLOCK_SPLIT * or bit-wise-or of both */ key_cum_value *recompute_list_head; /* pointer to a list of keys (with values) that need to be recomputed */ key_cum_value *recompute_list_tail; /* pointer to a list of keys (with values) that need to be recomputed */ enum gds_t_mode mode; /* Create, write, or write root */ block_id blk; /* Block number or a hint block number for creates */ unsigned char *upd_addr; /* Address of the block segment array containing update info * for this block */ unsigned char *new_buff; /* Address of a buffer created for each global mentioned inside of a * transaction more then once (for tp) */ gv_namehead *blk_target; /* address of the "gv_target" associated with a new_buff * used to invalidate clues that point to malloc'ed copies */ int4 cycle; /* When a block splits a new block must be created and the parent must be updated to * to have a record pointing to the new block. The created block number will not be * known until the last possible moment. Thus it is not possible to completely modify * the parent. The following 2 fields are used in such a case. "ins_off" tells where * the created block's number should be put in the parent block. "index" tells which * element of the create/write set is being created. */ block_offset first_off; block_offset ins_off; /* Insert block number offset */ block_offset next_off; block_index index; /* Insert block number index */ int4 reference_cnt; /* Relevant only for a bitmap block. * > 0 => # of non-bitmap blocks to be allocated in this bitmap; * < 0 => # of non-bitmap blocks to be freed up in this bitmap; * == 0 => change to bitmap block without any non-bitmap block change * Used to update csd->free_blocks when the bitmap block is built */ int4 level; /* Block level for newly created blocks */ boolean_t done; /* Has this update been done already? */ boolean_t first_copy; /* If overlaying same buffer, set if first copy needed */ /* just an optimisation - avoids copying first few bytes, if anyway * we are just overlaying the new_buff in the same transaction */ boolean_t forward_process; /* Need to process update array from front when doing kills */ uint4 t_level; /* transaction level associated with cw element, for incremental rollback */ enum db_ver ondsk_blkver; /* Actual block version from block header as it exists on disk. * If "cse->mode" is gds_t_write_root, this is uninitialized. * If "cse->mode" is gds_t_create/gds_t_acquired, this is GDSVCURR. * Otherwise, this is set to cr->ondsk_blkver (cr is got from the history). * Whenever "cse->old_block" is reset, this needs to be reset too (except * in the case of gds_t_create/gds_t_acquired). */ int4 old_mode; /* Saved copy of "cse->mode" before being reset to gds_t_committed. * Is negated at end of bg_update_phase1 to indicate (to secshr_db_clnup) * that phase1 is complete. Is negated back to the postive value at end * of bg_update_phase2. Since this can take on negative values, its type * is int4 (signed) and not enum gds_t_mode (which is unsigned). */ /* The following two fields aid in rolling back the transactions. 'undo_next_off' holds the * original next_off in the blk buffer that would be if another nested transaction was not * started. 'undo_offset' holds the offset at which 'undo_next_off' should be applied in case * of an undo due to trollback. * A 'kill' might change the next_off field at most in two places in the blk buffer. So, is * an array of size two. */ block_offset undo_next_off[2]; block_offset undo_offset[2]; uint4 blk_checksum; /*blk_prior_state:the block was in global variable tree/directory tree and was free/busy before update*/ uint4 blk_prior_state; } cw_set_element; #endif fis-gtm-V6.0-003/sr_port/gdsdbver.h0000644000032200000250000000615612201176156016014 0ustar librarygtc/**************************************************************** * * * Copyright 2005, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GDSDBVER_H_INCLUDED #define GDSDBVER_H_INCLUDED /* Database version related definitions */ /* Values for bytes 10 and 11 of the GDS Label (first field in the database file header) */ #ifdef VMS # define GDS_V20 "02" # define GDS_X21 "03" # define GDS_V23 "04" # define GDS_V24 "05" # define GDS_V25 "06" # define GDS_V254 "07" # define GDS_V255 "08" # define GDS_V30 "09" # define GDS_V40 "10" # define GDS_V50 "11" #else # define GDS_V40 "02" # define GDS_V50 "03" #endif #define GDS_CURR GDS_V50 /* Database major version as an enum quantity. Used to index the dbversion table in mtables.c */ enum db_ver { GDSNOVER = -1, GDSV4 = 0, GDSV5 = 1, GDSV6 = 1, /*GDSV5 and GDSV6 have same value because block format is same for these two version*/ GDSVLAST }; #define GDSVCURR ((enum db_ver)(GDSVLAST - 1)) /* Database minor version as an enum quantity. This is an ever increasing number that may skip actual * releases as it is only added to when a file-header field is added or changed or if there is a * significant API difference in the version. This number can be incremented only by adding an entry * at the end, just before GDSMVLAST. Note these entries need corresponding updates in * db_auto_upgrade.c. */ enum mdb_ver { GDSMV4, /* Applies to all V4 versions (no minor versions defined) */ GDSMV50000, GDSMV51000, /* Multi-site available (for databases created by V51000 - see V51000ALT */ GDSMV51000ALT, /* Upgrade from a previous version upgraded to this value for V51000 due to bug */ GDSMV52000, /* Unicode .. no real header changes but db contents could be unusable by previous versions */ GDSMV53000, /* M-Itanium release. secshr_ops_array and index is been copied from sgmnt_data to node_local. */ GDSMV53003, /* ZSHOW "G" release: Db Statistics rearranged in file header */ GDSMV53004, /* New fields(is_encrypted, encryption_hash) for encryption */ GDSMV54000, /* New fields(db_trigger_cycle) for triggers */ GDSMV54002, /* New statistical counter field for ZTRIGGER command */ GDSMV54002B, /* New fields(turn_around_point, jnl_eovtn) for backward recovery */ GDSMV55000, /* New fields(strm_reg_seqno, save_strm_reg_seqno, intrpt_recov_resync_strm_seqno) * for supplementary instances. * New fields(before_trunc_total_blks, after_trunc_total_blks, before_trunc_free_blocks * before_trunc_file_size) for fixing interrupted MUPIP REORG -TRUNCATE. */ GDSMV60000, /* New freeze_on_fail field for anticipatory freeze; the wc_blocked field moved to shared memory */ GDSMV60001, GDSMV60002, /* New field mutex_spin_parms.mutex_que_entry_space_size for configurable mutex queue size */ GDSMVLAST }; #define GDSMVCURR ((enum mdb_ver)(GDSMVLAST - 1)) #endif fis-gtm-V6.0-003/sr_port/gdsfhead.h0000644000032200000250000053446212201176156015767 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GDSFHEAD_H_INCLUDED #define GDSFHEAD_H_INCLUDED /* gdsfhead.h */ /* this requires gdsroot.h gtm_facility.h fileinfo.h gdsbt.h */ #include #include "gdsdbver.h" #include "gtm_unistd.h" #include "gtm_limits.h" #include "gtm_stdlib.h" #include "gtm_string.h" #include "send_msg.h" #include "iosp.h" #ifdef UNIX #include "repl_instance.h" #endif #ifdef VMS #include "iosb_disk.h" #endif #ifdef GTM_CRYPT #include "gtmcrypt.h" /* for gtmcrypt_key_t */ #endif #define CACHE_STATE_OFF SIZEOF(que_ent) error_def(ERR_DBCRERR); error_def(ERR_DBENDIAN); error_def(ERR_DBFLCORRP); error_def(ERR_GVIS); error_def(ERR_GVSUBOFLOW); error_def(ERR_MMFILETOOLARGE); error_def(ERR_REPLINSTMISMTCH); error_def(ERR_REPLREQROLLBACK); error_def(ERR_SCNDDBNOUPD); error_def(ERR_SRVLCKWT2LNG); error_def(ERR_SSATTACHSHM); error_def(ERR_SSFILOPERR); error_def(ERR_STACKCRIT); error_def(ERR_STACKOFLOW); error_def(ERR_TNTOOLARGE); error_def(ERR_TNWARN); /* Cache record */ typedef struct cache_rec_struct { struct { sm_off_t fl; sm_off_t bl; } blkque, /* cache records whose block numbers hash to the same location */ state_que; /* cache records in same state (either wip or active) */ union { short semaphore; volatile int4 latch; /* int required for atomic swap on Unix */ /* volatile required as this value is referenced outside of the lock in db_csh_getn() */ } interlock; block_id blk; uint4 refer; /* reference bit for the clock algorithm */ enum db_ver ondsk_blkver; /* Actual block version from block header as it exists on disk (prior to any dynamic conversion that may have occurred when read in). */ /* Keep our 64 bit fields up front */ /* this point should be quad-word aligned */ trans_num dirty; /* block has been modified since last written to disk; used by bt_put, db_csh_getn * mu_rndwn_file wcs_recover, secshr_db_clnup, wr_wrtfin_all and extensively by the ccp */ trans_num flushed_dirty_tn; /* value of dirty at the time of flushing */ trans_num tn; sm_off_t bt_index; /* offset to bt_rec */ sm_off_t buffaddr; /* offset to buffer holding actual data*/ sm_off_t twin; /* (VMS) offset to cache_rec of another copy of the same block from bg_update & wcs_wt_all * (Unix & VMS) offset to cache_rec holding before-image for wcs_recover to backup */ #ifdef VMS sm_off_t shmpool_blk_off; /* Offset to shmpool block containing the reformat buffer for this CR */ int4 backup_cr_off; /* Offset to backup_cr (set/used by bg_update_phase1/2 routines) */ #endif off_jnl_t jnl_addr; /* offset from bg_update to prevent wcs_wtstart from writing a block ahead of the journal */ global_latch_t rip_latch; /* for read_in_progress - note contains extra 16 bytes for HPPA. Usage note: this latch is used on those platforms where read_in_progress is not directly updated by atomic routines/instructions. As such there needs be no cache line padding between this field and read_in_progress. */ /* and now the rest */ int4 image_count; /* maintained with r_epid in vms to ensure that the process has stayed in gt.m */ int4 epid; /* set by wcs_wtstart to id the write initiator; cleared by wcs_wtfini * used by t_commit_cleanup, secshr_db_clnup and wcs_recover */ int4 cycle; /* relative stamp indicates changing versions of the block for concurrency checking */ int4 r_epid; /* set by db_csh_getn, cleared by t_qread, bg_update, wcs_recover or secshr_db_clnup * used to check for process leaving without releasing the buffer * must be word aligned on the VAX */ #ifdef VMS io_status_block_disk iosb; /* used on VMS write */ #endif CNTR4DCL(read_in_progress, 10); /* -1 for normal and 0 for rip used by t_qread and checked by others */ uint4 in_tend; /* non-zero pid from bg_update indicates secshr_db_clnup should finish update */ uint4 in_cw_set; /* non-zero pid from t_end, tp_tend or bg_update protects block from db_csh_getn; * returned to 0 by t_end, tp_tend or t_commit_cleanup */ uint4 data_invalid; /* non-zero pid from bg_update indicates t_commit_cleanup/wcs_recover should invalidate */ boolean_t stopped; /* TRUE indicates to wcs_recover that secshr_db_clnup built the block */ boolean_t wip_stopped; /* TRUE indicates to wcs_recover, wcs_wtfini, wcs_get_blk and gds_rundown * that secshr_db_clnup cancelled the qio */ } cache_rec; /* A note about cache line separation of the latches contained in these blocks. Because this block is duplicated many (ptentially tens+ of) thousands of times in a running system, we have decided against providing cacheline padding so as to force each cache record into a separate cacheline (due to it containing a latch and/or atomic counter field) to prevent processes from causing interference with each other. We decided that the probability of two processes working on adjacent cache records simultaneously was low enough that the interference was minimal whereas increasing the cache record size to prevent that interference could cause storage problems on some platforms where processes are already running near the edge. */ /* cache_state record */ typedef struct { struct { sm_off_t fl; sm_off_t bl; } state_que; /* WARNING from this point, this structure must be identical to a cache_rec */ union { short semaphore; volatile int4 latch; /* int required for atomic swap on Unix */ /* volatile required as this value is referenced outside of the lock in db_csh_getn() */ } interlock; block_id blk; uint4 refer; /* reference bit for the LRU algorithm */ enum db_ver ondsk_blkver; /* Actual block version from block header as it exists on disk (prior to any dynamic conversion that may have occurred when read in). */ /* Keep our 64 bit fields up front */ /* this point should be quad-word aligned */ trans_num dirty; /* block has been modified since last written to disk; used by bt_put, db_csh_getn * mu_rndwn_file wcs_recover, secshr_db_clnup, wr_wrtfin_all and extensively by the ccp */ trans_num flushed_dirty_tn; /* value of dirty at the time of flushing */ trans_num tn; sm_off_t bt_index; /* offset to bt_rec */ sm_off_t buffaddr; /* offset to buffer holding actual data*/ sm_off_t twin; /* (VMS) offset to cache_rec of another copy of the same block from bg_update & wcs_wt_all * (Unix & VMS) offset to cache_rec holding before-image for wcs_recover to backup */ #ifdef VMS sm_off_t shmpool_blk_off; /* Offset to shmpool block containing the reformat buffer for this CR */ int4 backup_cr_off; /* Offset to backup_cr (set/used by bg_update_phase1/2 routines) */ #endif off_jnl_t jnl_addr; /* offset from bg_update to prevent wcs_wtstart from writing a block ahead of the journal */ global_latch_t rip_latch; /* for read_in_progress - note contains extra 16 bytes for HPPA. Usage note: this latch is used on those platforms where read_in_progress is not directly updated by atomic routines/instructions. As such there needs be no cache line padding between this field and read_in_progress. */ /* and now the rest */ int4 image_count; /* maintained with r_epid in vms to ensure that the process has stayed in gt.m */ int4 epid; /* set by wcs_start to id the write initiator; cleared by wcs_wtfini * used by t_commit_cleanup, secshr_db_clnup and wcs_recover */ int4 cycle; /* relative stamp indicates changing versions of the block for concurrency checking */ int4 r_epid; /* set by db_csh_getn, cleared by t_qread, bg_update, wcs_recover or secshr_db_clnup * used to check for process leaving without releasing the buffer * must be word aligned on the VAX */ #ifdef VMS io_status_block_disk iosb; /* used on VMS write */ #endif CNTR4DCL(read_in_progress, 10); /* -1 for normal and 0 for rip used by t_qread and checked by others */ uint4 in_tend; /* non-zero pid from bg_update indicates secshr_db_clnup should finish update */ uint4 in_cw_set; /* non-zero pid from t_end, tp_tend or bg_update protects block from db_csh_getn; * returned to 0 by t_end, tp_tend or t_commit_cleanup */ uint4 data_invalid; /* non-zero pid from bg_update indicates t_commit_cleanup/wcs_recover should invalidate */ boolean_t stopped; /* TRUE indicates to wcs_recover that secshr_db_clnup built the block */ boolean_t wip_stopped; /* TRUE indicates to wcs_recover, wcs_wtfini, wcs_get_blk and gds_rundown * that secshr_db_clnup cancelled the qio */ } cache_state_rec; #define CR_BLKEMPTY -1 #define MBR_BLKEMPTY -1 #define FROZEN_BY_ROOT (uint4)(0xFFFFFFFF) #define BACKUP_NOT_IN_PROGRESS 0x7FFFFFFF #define DB_CSH_RDPOOL_SZ 0x20 /* These many non-dirty buffers exist at all points in time in shared memory */ typedef struct { cache_que_head cacheq_wip, /* write-in-progress queue -- unused in Unix */ cacheq_active; /* active queue */ cache_rec cache_array[1]; /*the first cache record*/ } cache_que_heads; /* Define pointer types to some previously defined structures */ #ifdef DB64 # ifdef __osf__ # pragma pointer_size(save) # pragma pointer_size(long) # else # error UNSUPPORTED PLATFORM # endif #endif typedef cache_que_head *cache_que_head_ptr_t; typedef cache_rec *cache_rec_ptr_t; typedef cache_rec **cache_rec_ptr_ptr_t; typedef cache_state_rec *cache_state_rec_ptr_t; typedef cache_que_heads *cache_que_heads_ptr_t; void verify_queue_lock(que_head_ptr_t qhdr); void verify_queue(que_head_ptr_t qhdr); #ifdef DB64 # ifdef __osf__ # pragma pointer_size(restore) # endif #endif #ifdef DEBUG_QUEUE #define VERIFY_QUEUE(base) verify_queue(base) #define VERIFY_QUEUE_LOCK(base,latch) verify_queue_lock(base,latch) #else #define VERIFY_QUEUE(base) #define VERIFY_QUEUE_LOCK(base,latch) #endif #define BLK_ZERO_OFF(CSD) ((CSD->start_vbn - 1) * DISK_BLOCK_SIZE) #ifdef UNIX # ifdef GTM64 # define CHECK_LARGEFILE_MMAP(REG, MMAP_SZ) # else # define CHECK_LARGEFILE_MMAP(REG, MMAP_SZ) \ { \ assert(SIZEOF(gtm_uint64_t) == SIZEOF(MMAP_SZ)); \ assert(0 < MMAP_SZ); \ if (MAXUINT4 < (gtm_uint64_t)(MMAP_SZ)) \ rts_error_csa(CSA_ARG(REG2CSA(REG)) VARLSTCNT(6) ERR_MMFILETOOLARGE, 4, REG_LEN_STR(REG), \ DB_LEN_STR(REG)); \ } # endif # define MMAP_FD(FD, SIZE, OFFSET, READ_ONLY) mmap((caddr_t)NULL, SIZE, MM_PROT_FLAGS(READ_ONLY), GTM_MM_FLAGS, FD, OFFSET) # define MSYNC(BEGPTR, ENDPTR) (BEGPTR ? DBG_ASSERT(BEGPTR < ENDPTR) msync(BEGPTR, (ENDPTR - BEGPTR), MS_SYNC) \ : 0) # define MM_PROT_FLAGS(READ_ONLY) (READ_ONLY ? PROT_READ : (PROT_READ | PROT_WRITE)) # define MM_BASE_ADDR(CSA) (sm_uc_ptr_t)CSA->db_addrs[0] # define SET_MM_BASE_ADDR(CSA, CSD) #else # define MM_BASE_ADDR(CSA) (sm_uc_ptr_t)CSA->acc_meth.mm.base_addr # define SET_MM_BASE_ADDR(CSA, CSD) \ { \ CSA->acc_meth.mm.base_addr = (sm_uc_ptr_t)((sm_long_t)CSD + (off_t)(CSD->start_vbn - 1) * DISK_BLOCK_SIZE); \ } #endif /* The following 3 macros were introduced while solving a problem with $view where a call to $view in */ /* mumps right after a change to $zgbldir gave the old global directory - not the new one. On VMS it */ /* caused a core dump. If one were to access a global variable via $data right after the change, however, */ /* the $view worked correctly. The solution was to make sure the gd_map information matched the current */ /* gd_header in op_fnview.c. The code used as a template for this change was in gvinit.c. The first */ /* macro gets the gd_header using an mval. The second macro establishes the gd_map from the gd_header. */ /* The third macro is an assert (when DEBUG_ONLY is defined) for those cases where the gd_header is already */ /* set to make sure the mapping is correct. The first 2 macros are executed when the gd_header is null, */ /* and the 3rd macro is associated with an else clause if it is not. Therefore, they should be maintained */ /* as a group. */ #define SET_GD_HEADER(inmval) \ { \ inmval.mvtype = MV_STR; \ inmval.str.len = 0; \ gd_header = zgbldir(&inmval); \ } #define SET_GD_MAP \ { \ GBLREF gd_binding *gd_map, *gd_map_top; \ \ gd_map = gd_header->maps; \ gd_map_top = gd_map + gd_header->n_maps; \ TREF(gd_targ_addr) = gd_header; \ } #define GD_HEADER_ASSERT \ { \ GBLREF gd_binding *gd_map, *gd_map_top; \ \ assert(gd_map == gd_header->maps); \ assert(gd_map_top == gd_map + gd_header->n_maps); \ assert(TREF(gd_targ_addr) == gd_header); \ } /* If reallocating gv_currkey/gv_altkey, preserve pre-existing values */ #define GVKEY_INIT(GVKEY, KEYSIZE) \ { \ gv_key *new_KEY, *old_KEY; \ int4 keySZ; \ \ old_KEY = GVKEY; \ keySZ = KEYSIZE; \ /* KEYSIZE should have been the output of a DBKEYSIZE command so \ * should be a multiple of 4. Assert that. \ */ \ assert(ROUND_UP2(keySZ, 4) == keySZ); \ new_KEY = (gv_key *)malloc(SIZEOF(gv_key) - 1 + keySZ); \ if (NULL != old_KEY) \ { \ assert(KEYSIZE >= old_KEY->top); \ assert(old_KEY->top > old_KEY->end); \ memcpy(new_KEY, old_KEY, SIZEOF(gv_key) + old_KEY->end); \ free(old_KEY); \ } else \ { \ new_KEY->base[0] = '\0'; \ new_KEY->end = 0; \ new_KEY->prev = 0; \ } \ new_KEY->top = keySZ; \ GVKEY = new_KEY; \ } #define GVKEY_FREE_IF_NEEDED(GVKEY) \ { \ if (NULL != GVKEY) \ { \ free(GVKEY); \ GVKEY = NULL; \ } \ } #define GVKEYSIZE_INCREASE_IF_NEEDED(KEYSIZE) \ { \ int keySIZE; \ \ GBLREF int4 gv_keysize; \ GBLREF gv_key *gv_altkey; \ GBLREF gv_key *gv_currkey; \ \ keySIZE = KEYSIZE; \ /* Have space to store at least MAX_MIDENT_LEN bytes as otherwise name-level $order \ * (see op_gvorder/op_zprevious) could have buffer overflow issues in gv_currkey->base. \ * Do ROUND_UP2(x,4) to keep an assert in GVKEY_INIT macro happy. \ */ \ if ((MAX_MIDENT_LEN + 3) > keySIZE) \ keySIZE = ROUND_UP2(MAX_MIDENT_LEN + 3, 4); \ assert(keySIZE); \ if (keySIZE > gv_keysize) \ { \ gv_keysize = keySIZE; \ GVKEY_INIT(gv_currkey, keySIZE); \ GVKEY_INIT(gv_altkey, keySIZE); \ } else \ assert((NULL != gv_currkey) && (NULL != gv_altkey) && gv_keysize \ && (gv_keysize == gv_currkey->top) && (gv_keysize == gv_altkey->top)); \ } #define WAS_OPEN_TRUE TRUE #define WAS_OPEN_FALSE FALSE /* Below macro sets open, opening and was_open fields of a given region after the corresponding * database for that region is opened. Also, if the region was not already open, the macro * invokes GVKEYSIZE_INCREASE_IF_NEEDED to allocate gv_currkey/gv_altkey based on the region's * max_key_size. */ #define SET_REGION_OPEN_TRUE(REG, WAS_OPEN) \ { \ DEBUG_ONLY(GBLREF int4 gv_keysize;) \ \ assert(!REG->was_open); \ assert(!REG->open); \ REG->open = TRUE; \ REG->opening = FALSE; \ if (WAS_OPEN) \ { \ REG->was_open = TRUE; \ assert(DBKEYSIZE(REG->max_key_size) <= gv_keysize); \ } \ else \ GVKEYSIZE_INCREASE_IF_NEEDED(DBKEYSIZE(REG->max_key_size)); \ } #define SET_CSA_DIR_TREE(csa, keysize, reg) \ { \ if (NULL == csa->dir_tree) \ { \ csa->dir_tree = targ_alloc(keysize, NULL, reg); \ GTMTRIG_ONLY(assert(NULL == csa->hasht_tree)); \ } else \ assert((csa->dir_tree->gd_csa == csa) && (DIR_ROOT == csa->dir_tree->root)); \ } #define FREE_CSA_DIR_TREE(csa) \ { \ sgmnt_addrs *lcl_csa; \ gv_namehead *dir_tree, *hasht_tree; \ \ lcl_csa = csa; \ GTMTRIG_ONLY( \ hasht_tree = lcl_csa->hasht_tree; \ if (NULL != hasht_tree) \ { \ assert(hasht_tree->gd_csa == csa); \ hasht_tree->regcnt--; /* targ_free relies on this */ \ targ_free(hasht_tree); \ lcl_csa->hasht_tree = NULL; \ } \ ) \ dir_tree = lcl_csa->dir_tree; \ assert(NULL != dir_tree); \ dir_tree->regcnt--; /* targ_free relies on this */ \ targ_free(dir_tree); \ lcl_csa->dir_tree = NULL; \ } #define PROCESS_GVT_PENDING_LIST(GREG, CSA, GVT_PENDING_LIST) \ { \ if (NULL != GVT_PENDING_LIST) \ { /* Now that the region has been opened, check if there are any gv_targets that were \ * allocated for this region BEFORE the open. If so, re-allocate them if necessary. \ */ \ process_gvt_pending_list(GREG, CSA); \ } \ } #define T_COMMIT_CRIT_PHASE1 1 /* csa->t_commit_crit gets set to this in during bg_update_phase1 */ #define T_COMMIT_CRIT_PHASE2 2 /* csa->t_commit_crit gets set to this in during bg_update_phase2 */ /* macro to check if we hold crit or are committing (with or without crit) */ #define T_IN_CRIT_OR_COMMIT(CSA) ((CSA)->now_crit || (CSA)->t_commit_crit) /* Macro to check if we hold crit or are committing (with or without crit) or are in wcs_wtstart for this region. * This is used in timer handling code to determine if it is ok to interrupt. We do not want to interrupt if holding * crit or in the midst of commit or in wcs_wtstart (in the last case, we could be causing another process HOLDING CRIT * on the region to wait in bg_update_phase1 if we hold the write interlock). */ #define T_IN_CRIT_OR_COMMIT_OR_WRITE(CSA) (T_IN_CRIT_OR_COMMIT(CSA) || (CSA)->in_wtstart) /* macro to check if a database commit is past the point where it can be successfully rolled back */ #define T_UPDATE_UNDERWAY(CSA) ((CSA)->t_commit_crit) /* the file header has relative pointers to its data structures so each process will malloc * one of these and fill it in with absolute pointers upon file initialization. */ #define GDS_REL2ABS(x) (((sm_uc_ptr_t)cs_addrs->lock_addrs[0] + (sm_off_t)(x))) #define GDS_ABS2REL(x) (sm_off_t)(((sm_uc_ptr_t)(x) - (sm_uc_ptr_t)cs_addrs->lock_addrs[0])) #define GDS_ANY_REL2ABS(w,x) (((sm_uc_ptr_t)(w->lock_addrs[0]) + (sm_off_t)(x))) #define GDS_ANY_ABS2REL(w,x) (sm_off_t)(((sm_uc_ptr_t)(x) - (sm_uc_ptr_t)w->lock_addrs[0])) #ifdef GTM_CRYPT #define GDS_ANY_ENCRYPTGLOBUF(w,x) ((sm_uc_ptr_t)(w) + (sm_off_t)(x->nl->encrypt_glo_buff_off)) #endif #define ASSERT_IS_WITHIN_SHM_BOUNDS(ptr, csa) \ assert((NULL == (ptr)) || (((ptr) >= csa->db_addrs[0]) && ((0 == csa->db_addrs[1]) || ((ptr) < csa->db_addrs[1])))) #ifdef DEBUG #define DBG_ENSURE_PTR_IS_VALID_GLOBUFF(CSA, CSD, PTR) \ { \ cache_rec_ptr_t cache_start; \ long bufindx; \ sm_uc_ptr_t bufstart; \ \ cache_start = &(CSA)->acc_meth.bg.cache_state->cache_array[0]; \ cache_start += CSD->bt_buckets; \ bufstart = (sm_uc_ptr_t)GDS_ANY_REL2ABS((CSA), cache_start->buffaddr); \ assert((PTR) >= bufstart); \ bufindx = (PTR - bufstart) / CSD->blk_size; \ assert(bufindx < CSD->n_bts); \ assert((bufstart + (bufindx * CSD->blk_size)) == (PTR)); \ } #define DBG_ENSURE_PTR_IS_VALID_ENCTWINGLOBUFF(CSA, CSD, PTR) \ { \ cache_rec_ptr_t cache_start; \ long bufindx; \ sm_uc_ptr_t bufstart; \ \ cache_start = &(CSA)->acc_meth.bg.cache_state->cache_array[0]; \ cache_start += CSD->bt_buckets; \ bufstart = (sm_uc_ptr_t)GDS_ANY_REL2ABS((CSA), cache_start->buffaddr); \ bufstart += (gtm_uint64_t)CSD->blk_size * CSD->n_bts; \ assert((PTR) >= bufstart); \ bufindx = (PTR - bufstart) / CSD->blk_size; \ assert(bufindx < CSD->n_bts); \ assert((bufstart + (bufindx * (gtm_uint64_t)CSD->blk_size)) == (PTR)); \ } #define DBG_ENSURE_OLD_BLOCK_IS_VALID(cse, is_mm, csa, csd) \ { \ cache_rec_ptr_t cache_start; \ long bufindx; \ sm_uc_ptr_t bufstart; \ GBLREF boolean_t dse_running, write_after_image; \ \ assert((gds_t_write != cse->mode) && (gds_t_write_recycled != cse->mode) && gds_t_writemap != cse->mode \ || (NULL != cse->old_block)); /* don't miss writing a PBLK */ \ if (NULL != cse->old_block) \ { \ if (!is_mm) \ { \ cache_start = &csa->acc_meth.bg.cache_state->cache_array[0]; \ cache_start += csd->bt_buckets; \ bufstart = (sm_uc_ptr_t)GDS_ANY_REL2ABS(csa, cache_start->buffaddr); \ bufindx = (cse->old_block - bufstart) / csd->blk_size; \ assert(bufindx < csd->n_bts); \ assert(cse->blk == cache_start[bufindx].blk); \ assert(dse_running || write_after_image || (process_id == cache_start[bufindx].in_cw_set)); \ } else \ assert(cse->old_block == MM_BASE_ADDR(csa) + (off_t)cse->blk * csd->blk_size); \ } \ } /* Check if a given address corresponds to a global buffer (BG) in database shared memory AND if * we are in phase2 of commit. If so check whether the corresponding cache-record is pinned. * Used by gvcst_blk_build to ensure the update array points to valid contents even though we dont hold crit. */ #define DBG_BG_PHASE2_CHECK_CR_IS_PINNED(csa, seg) \ { \ cache_rec_ptr_t cache_start; \ long bufindx; \ sm_uc_ptr_t bufstart, bufend, bufaddr; \ \ GBLREF uint4 process_id; \ \ if ((seg)->len && (T_COMMIT_CRIT_PHASE2 == csa->t_commit_crit) && (dba_bg == csa->hdr->acc_meth)) \ { \ cache_start = &csa->acc_meth.bg.cache_state->cache_array[0]; \ cache_start += csa->hdr->bt_buckets; \ bufstart = (sm_uc_ptr_t)GDS_ANY_REL2ABS(csa, cache_start->buffaddr); \ bufend = bufstart + ((gtm_uint64_t)csa->hdr->n_bts * csa->hdr->blk_size); \ bufaddr = (sm_uc_ptr_t)(seg)->addr; \ /* Check if given address is within database shared memory range */ \ if ((bufaddr >= bufstart) && (bufaddr < bufend)) \ { \ bufindx = (bufaddr - bufstart) / csa->hdr->blk_size; \ assert(bufindx < csa->hdr->n_bts); \ /* Assert that we have the cache-record pinned */ \ assert(process_id == cache_start[bufindx].in_cw_set); \ } \ } \ } /* Macro to check that we have not pinned any more buffers than we are updating. * This check is done only for BG access method and in dbg mode. * This is invoked by t_end/tp_tend just before beginning phase2 of commit. */ #define DBG_CHECK_PINNED_CR_ARRAY_CONTENTS(is_mm, crarray, crarrayindex, bplmap) \ { \ GBLREF boolean_t write_after_image; \ \ if (!is_mm) \ { \ int4 crindex; \ \ for (crindex = 0; crindex < crarrayindex; crindex++) \ { \ if (process_id == crarray[crindex]->in_cw_set) \ { /* We have pinned that cache-record implies we are planning on updating it \ * (so should have set in_tend). \ * \ * Since bitmap blocks are done with phase2 inside of crit, they should not \ * show up in the pinned array list at end of phase1 for GT.M. But DSE is an \ * exception as it could operate on a bitmap block as if it is updating a \ * non-bitmap block (i.e. without invoking gvcst_map_build). MUPIP JOURNAL \ * RECOVER also could do the same thing while applying an AIMG record. \ * \ * In addition, VMS has an exception in case this is a twinned cache-record. \ * In that case, for the older twin in_cw_set will be set to non-zero, but \ * in_tend will be set to FALSE. Since we are outside of crit at this point, \ * it is possible cr->twin field might be 0 (could have gotten cleared by \ * wcs_wtfini concurrently) so we cannot assert on the twin field but \ * cr->bt_index should still be 0 since we have not yet finished the \ * update on the newer twin so we can check on that. \ */ \ assert(crarray[crindex]->in_tend \ && ((0 != crarray[crindex]->blk % bplmap) || write_after_image) \ VMS_ONLY(|| !crarray[crindex]->bt_index)); \ } \ } \ } \ } #else #define DBG_ENSURE_PTR_IS_VALID_GLOBUFF(CSA, CSD, PTR) #define DBG_ENSURE_PTR_IS_VALID_ENCTWINGLOBUFF(CSA, CSD, PTR) #define DBG_ENSURE_OLD_BLOCK_IS_VALID(cse, is_mm, csa, csd) #define DBG_BG_PHASE2_CHECK_CR_IS_PINNED(csa, bufaddr) #define DBG_CHECK_PINNED_CR_ARRAY_CONTENTS(is_mm, crarray, crarrayindex, bplmap) #endif /* The TP_CHANGE_REG macro is a replica of the tp_change_reg() routine to be used for performance considerations. * The TP_CHANGE_REG_IF_NEEDED macro tries to optimize on processing if reg is same as gv_cur_region. But it can be * used only if the region passed is not NULL and if gv_cur_region, cs_addrs and cs_data are known to be in sync. * Note that timers can interrupt the syncing and hence any routines that are called by timers should be safe * and use the TP_CHANGE_REG macro only. */ #define TP_CHANGE_REG(reg) \ { \ gv_cur_region = reg; \ if (NULL == gv_cur_region || FALSE == gv_cur_region->open) \ { \ cs_addrs = (sgmnt_addrs *)0; \ cs_data = (sgmnt_data_ptr_t)0; \ } else \ { \ switch (reg->dyn.addr->acc_meth) \ { \ case dba_mm: \ case dba_bg: \ cs_addrs = &FILE_INFO(gv_cur_region)->s_addrs; \ cs_data = cs_addrs->hdr; \ break; \ case dba_usr: \ case dba_cm: \ cs_addrs = (sgmnt_addrs *)0; \ cs_data = (sgmnt_data_ptr_t)0; \ break; \ default: \ GTMASSERT; \ break; \ } \ } \ } #define TP_CHANGE_REG_IF_NEEDED(reg) \ { \ assert(reg); \ if (reg != gv_cur_region) \ { \ gv_cur_region = reg; \ switch (reg->dyn.addr->acc_meth) \ { \ case dba_mm: \ case dba_bg: \ assert(reg->open); \ cs_addrs = &FILE_INFO(gv_cur_region)->s_addrs; \ cs_data = cs_addrs->hdr; \ break; \ case dba_usr: \ case dba_cm: \ cs_addrs = (sgmnt_addrs *)0; \ cs_data = (sgmnt_data_ptr_t)0; \ break; \ default: \ GTMASSERT; \ break; \ } \ } \ assert(&FILE_INFO(gv_cur_region)->s_addrs == cs_addrs && cs_addrs->hdr == cs_data); \ } #define PUSH_GV_CUR_REGION(reg, sav_reg, sav_cs_addrs, sav_cs_data) \ { \ sav_reg = gv_cur_region; \ sav_cs_addrs = cs_addrs; \ sav_cs_data = cs_data; \ TP_CHANGE_REG(reg) \ } #define POP_GV_CUR_REGION(sav_reg, sav_cs_addrs, sav_cs_data) \ { \ gv_cur_region = sav_reg; \ cs_addrs = sav_cs_addrs; \ cs_data = sav_cs_data; \ } /* The TP_TEND_CHANGE_REG macro is a special macro used in tp_tend.c to optimize out the unnecessary checks in * the TP_CHANGE_REG_IF_NEEDED macro. Also it sets cs_addrs and cs_data to precomputed values instead of recomputing * them from the region by dereferencing through a multitude of pointers. It does not check if gv_cur_region is * different from the input region. It assumes it is different enough % of times that the cost of the if check * is not worth the additional unconditional sets. */ #define TP_TEND_CHANGE_REG(si) \ { \ gv_cur_region = si->gv_cur_region; \ cs_addrs = si->tp_csa; \ cs_data = si->tp_csd; \ } #define GTCM_CHANGE_REG(reghead) \ { \ GBLREF cm_region_head *curr_cm_reg_head; \ GBLREF gd_region *gv_cur_region; \ GBLREF sgmnt_data *cs_data; \ GBLREF sgmnt_addrs *cs_addrs; \ \ curr_cm_reg_head = (reghead); \ gv_cur_region = curr_cm_reg_head->reg; \ if ((dba_bg == gv_cur_region->dyn.addr->acc_meth) || (dba_mm == gv_cur_region->dyn.addr->acc_meth)) \ { \ cs_addrs = &FILE_INFO(gv_cur_region)->s_addrs; \ cs_data = cs_addrs->hdr; \ } else \ GTMASSERT; \ } /* Macro to be used whenever cr->data_invalid needs to be set */ #define SET_DATA_INVALID(cr) \ { \ uint4 in_tend, data_invalid; \ \ DEBUG_ONLY(in_tend = cr->in_tend); \ DEBUG_ONLY(data_invalid = cr->data_invalid); \ assert((process_id == in_tend) || (0 == in_tend) && (0 == data_invalid)); \ assert((0 == in_tend) \ || (process_id == in_tend) && ((0 == data_invalid) || (process_id == data_invalid))); \ cr->data_invalid = process_id; \ } /* Macro to be used whenever cr->data_invalid needs to be re-set */ #define RESET_DATA_INVALID(cr) \ { \ uint4 data_invalid; \ \ DEBUG_ONLY(data_invalid = cr->data_invalid); \ assert(process_id == data_invalid); \ cr->data_invalid = 0; \ } /* Macro to be used whenever cr->in_cw_set needs to be set (PIN) inside a TP transaction */ #define TP_PIN_CACHE_RECORD(cr, si) \ { \ assert(0 <= si->cr_array_index); \ assert(si->cr_array_index < si->cr_array_size); \ PIN_CACHE_RECORD(cr, si->cr_array, si->cr_array_index); \ } GBLREF cache_rec_ptr_t pin_fail_cr; /* Pointer to the cache-record that we failed while pinning */ GBLREF cache_rec pin_fail_cr_contents; /* Contents of the cache-record that we failed while pinning */ GBLREF cache_rec_ptr_t pin_fail_twin_cr; /* Pointer to twin of the cache-record that we failed to pin */ GBLREF cache_rec pin_fail_twin_cr_contents; /* Contents of twin of the cache-record that we failed to pin */ GBLREF bt_rec_ptr_t pin_fail_bt; /* Pointer to bt of the cache-record that we failed to pin */ GBLREF bt_rec pin_fail_bt_contents; /* Contents of bt of the cache-record that we failed to pin */ GBLREF int4 pin_fail_in_crit; /* Holder of crit at the time we failed to pin */ GBLREF int4 pin_fail_wc_in_free; /* Number of write cache records in free queue when we failed to pin */ GBLREF int4 pin_fail_wcs_active_lvl; /* Number of entries in active queue when we failed to pin */ GBLREF int4 pin_fail_ref_cnt; /* Reference count when we failed to pin */ GBLREF int4 pin_fail_in_wtstart; /* Count of processes in wcs_wtstart when we failed to pin */ GBLREF int4 pin_fail_phase2_commit_pidcnt; /* Number of processes in phase2 commit when we failed to pin */ /* Macro to be used whenever cr->in_cw_set needs to be set (PIN) outside of a TP transaction */ #define PIN_CACHE_RECORD(cr, crarray, crarrayindex) \ { \ uint4 in_tend, data_invalid, in_cw_set; \ \ DEBUG_ONLY(in_tend = cr->in_tend); \ DEBUG_ONLY(data_invalid = cr->data_invalid); \ assert((process_id == in_tend) || (0 == in_tend)); \ assert((process_id == data_invalid) || (0 == data_invalid)); \ in_cw_set = cr->in_cw_set; \ if (0 != in_cw_set) \ { \ pin_fail_cr = cr; \ pin_fail_cr_contents = *cr; \ if (cr->bt_index) \ { \ pin_fail_bt = (bt_rec_ptr_t)GDS_ANY_REL2ABS(cs_addrs, cr->bt_index); \ pin_fail_bt_contents = *pin_fail_bt; \ } \ if (cr->twin) \ { \ pin_fail_twin_cr = (cache_rec_ptr_t)GDS_ANY_REL2ABS(cs_addrs, cr->twin); \ pin_fail_twin_cr_contents = *pin_fail_twin_cr; \ } \ pin_fail_in_crit = cs_addrs->nl->in_crit; \ pin_fail_wc_in_free = cs_addrs->nl->wc_in_free; \ pin_fail_wcs_active_lvl = cs_addrs->nl->wcs_active_lvl; \ pin_fail_ref_cnt = cs_addrs->nl->ref_cnt; \ pin_fail_in_wtstart = cs_addrs->nl->in_wtstart; \ pin_fail_phase2_commit_pidcnt = cs_addrs->nl->wcs_phase2_commit_pidcnt; \ GTMASSERT; \ } \ /* In VMS we should never set in_cw_set on an OLDER twin. */ \ VMS_ONLY(assert(!cr->twin || cr->bt_index)); \ /* stuff it in the array before setting in_cw_set */ \ crarray[crarrayindex] = cr; \ crarrayindex++; \ cr->in_cw_set = process_id; \ } /* Macro to be used whenever cr->in_cw_set needs to be re-set (UNPIN) in TP or non-TP) */ #define UNPIN_CACHE_RECORD(cr) \ { \ uint4 in_tend, data_invalid, in_cw_set; \ \ in_cw_set = cr->in_cw_set; \ if (process_id == cr->in_cw_set) /* reset in_cw_set only if we hold it */ \ { \ DEBUG_ONLY(in_tend = cr->in_tend); \ DEBUG_ONLY(data_invalid = cr->data_invalid); \ assert((process_id == in_tend) || (0 == in_tend)); \ assert((process_id == data_invalid) || (0 == data_invalid)); \ cr->in_cw_set = 0; \ } \ } /* Macro to reset cr->in_cw_set for the entire cr_array in case of a retry (TP or non-TP) */ #define UNPIN_CR_ARRAY_ON_RETRY(crarray, crarrayindex) \ { \ int4 lcl_crarrayindex; \ cache_rec_ptr_ptr_t cr_ptr; \ cache_rec_ptr_t cr; \ uint4 in_tend, data_invalid, in_cw_set; \ \ lcl_crarrayindex = crarrayindex; \ if (lcl_crarrayindex) \ { \ cr_ptr = (cache_rec_ptr_ptr_t)&crarray[lcl_crarrayindex-1]; \ while (lcl_crarrayindex--) \ { \ cr = *cr_ptr; \ DEBUG_ONLY(in_tend = cr->in_tend); \ DEBUG_ONLY(data_invalid = cr->data_invalid); \ DEBUG_ONLY(in_cw_set = cr->in_cw_set); \ assert(!data_invalid); \ assert(!in_tend); \ assert(process_id == in_cw_set); \ UNPIN_CACHE_RECORD(cr); \ cr_ptr--; \ } \ crarrayindex = 0; \ } \ } /* Macro to reset cr->in_cw_set (UNPIN) for the entire cr_array in case of a commit (TP or non-TP). * Usually in_cw_set is set for all cache-records that we are planning on updating before we start phase1. * After updating each cse in phase2, we reset the corresponding cse->cr->in_cw_set. * Therefore on a successful commit, after completing all cses in phase2, we dont expect any pinned cr->in_cw_set at all. * This is true for Unix but in VMS where we could have twins, both the older and newer twins have the in_cw_set set in * phase1 while only the newer twin's in_cw_set gets reset in phase2 (since only this cr will be stored in cse->cr). * Therefore there could be a few cache-records which need to be unpinned even after all cses are done in phase2. * The following macro unpins those. It is structured such a way that in Unix, it only checks that all have been reset * while it actually does the reset only in VMS. */ #if defined(VMS) #define UNPIN_CR_ARRAY_ON_COMMIT(crarray, crarrayindex) \ { \ int4 lcl_crarrayindex; \ cache_rec_ptr_ptr_t cr_ptr; \ cache_rec_ptr_t cr; \ \ lcl_crarrayindex = crarrayindex; \ if (lcl_crarrayindex) \ { \ cr_ptr = (cache_rec_ptr_ptr_t)&crarray[lcl_crarrayindex-1]; \ while (lcl_crarrayindex--) \ { \ cr = *cr_ptr; \ UNPIN_CACHE_RECORD(cr); \ cr_ptr--; \ } \ crarrayindex = 0; \ } \ } #elif defined(UNIX) # ifdef DEBUG # define UNPIN_CR_ARRAY_ON_COMMIT(crarray, crarrayindex) \ { \ int4 lcl_crarrayindex; \ cache_rec_ptr_ptr_t cr_ptr; \ cache_rec_ptr_t cr; \ \ lcl_crarrayindex = crarrayindex; \ if (lcl_crarrayindex) \ { \ cr_ptr = (cache_rec_ptr_ptr_t)&crarray[lcl_crarrayindex-1]; \ while (lcl_crarrayindex--) \ { \ cr = *cr_ptr; \ assert(process_id != cr->in_cw_set); \ cr_ptr--; \ } \ crarrayindex = 0; \ } \ } # else # define UNPIN_CR_ARRAY_ON_COMMIT(crarray, crarrayindex) \ crarrayindex = 0; # endif #endif /* Every process that initializes journal pool has two aspects of validation. * 1. Validate whether this process can do logical updates to the journal pool that is initialized. If not, the process should * issue SCNDDBNOUPD error. Examples of this would be a GT.M update that happens on a non-supplementary Receiver Side. * * 2. Validate whether the process is attached to the correct journal pool. If not, REPLINSTMISMTCH should be issued. This check * ensures that we only do updates to region that is tied to the journal pool that we initialized. * * The below macro definitions indicate which of the above 2 checks is done by the process for a particular region until now. * The macro VALIDATE_INITIALIZED_JNLPOOL does the actual validation. */ #define JNLPOOL_NOT_VALIDATED 0x00 #define REPLINSTMISMTCH_CHECK_DONE 0x01 #define SCNDDBNOUPD_CHECK_DONE 0x02 #define JNLPOOL_VALIDATED 0x03 #define SCNDDBNOUPD_CHECK_FALSE 0x00 #define SCNDDBNOUPD_CHECK_TRUE 0x01 #define VALIDATE_INITIALIZED_JNLPOOL(CSA, CNL, REG, JNLPOOL_USER, SCNDDBNOUPD_CHECK_NEEDED) \ { \ GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; \ GBLREF boolean_t is_updproc; \ \ unsigned char instfilename_copy[MAX_FN_LEN + 1]; \ sm_uc_ptr_t jnlpool_instfilename; \ int4 jnlpool_shmid; \ uint4 jnlpool_validate_check; \ boolean_t do_REPLINSTMISMTCH_check; \ \ jnlpool_validate_check = CSA->jnlpool_validate_check; \ assert(JNLPOOL_VALIDATED >= jnlpool_validate_check); \ if (JNLPOOL_VALIDATED != jnlpool_validate_check) \ { \ do_REPLINSTMISMTCH_check = (!(REPLINSTMISMTCH_CHECK_DONE & jnlpool_validate_check) \ UNIX_ONLY(&& ((GTMRELAXED != JNLPOOL_USER) || !IS_GTM_IMAGE))); \ if (!(SCNDDBNOUPD_CHECK_DONE & jnlpool_validate_check) && SCNDDBNOUPD_CHECK_NEEDED) \ { \ if (jnlpool_ctl->upd_disabled && !is_updproc) \ { /* Updates are disabled in this journal pool. Detach from journal pool and issue error. */ \ assert(NULL != jnlpool.jnlpool_ctl); \ jnlpool_detach(); \ assert(NULL == jnlpool.jnlpool_ctl); \ assert(FALSE == pool_init); \ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_SCNDDBNOUPD); \ } \ CSA->jnlpool_validate_check |= SCNDDBNOUPD_CHECK_DONE; \ } \ if (do_REPLINSTMISMTCH_check) \ { \ UNIX_ONLY(jnlpool_instfilename = (sm_uc_ptr_t)jnlpool_ctl->jnlpool_id.instfilename;) \ VMS_ONLY(jnlpool_instfilename = (sm_uc_ptr_t)jnlpool_ctl->jnlpool_id.gtmgbldir;) \ if (STRCMP(CNL->replinstfilename, jnlpool_instfilename) \ UNIX_ONLY(|| (CNL->jnlpool_shmid != jnlpool.repl_inst_filehdr->jnlpool_shmid))) \ { \ /* Replication instance filename or jnlpool shmid mismatch. Two possibilities. \ * (a) Database has already been bound with a replication instance file name that is different \ * from the instance file name used by the current process. \ * (b) Database has already been bound with a jnlpool shmid and another jnlpool is about to \ * be bound with the same database. Disallow this mixing of multiple jnlpools. \ * Note that (b) is Unix-only. In VMS, we dont check the shmids currently. \ * Issue error. But before that detach from journal pool. \ * Copy replication instance file name in journal pool to temporary memory before detaching. \ * Actually case (b) subsumes (a) so we assert that below. But in pro we handle both cases \ * just in case. \ */ \ UNIX_ONLY(assert(CNL->jnlpool_shmid != jnlpool.repl_inst_filehdr->jnlpool_shmid);) \ UNIX_ONLY(assert(SIZEOF(instfilename_copy) == SIZEOF(jnlpool_ctl->jnlpool_id.instfilename))); \ VMS_ONLY(assert(SIZEOF(instfilename_copy) == SIZEOF(jnlpool_ctl->jnlpool_id.gtmgbldir))); \ memcpy(&instfilename_copy[0], jnlpool_instfilename, SIZEOF(instfilename_copy)); \ assert(SIZEOF(jnlpool_shmid) == SIZEOF(CNL->jnlpool_shmid)); \ UNIX_ONLY(jnlpool_shmid = jnlpool.repl_inst_filehdr->jnlpool_shmid;) \ VMS_ONLY(jnlpool_shmid = 0;) /* print shmid of 0 for VMS as it is actually a string */ \ assert(NULL != jnlpool.jnlpool_ctl); \ jnlpool_detach(); \ assert(NULL == jnlpool.jnlpool_ctl); \ assert(FALSE == pool_init); \ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(10) ERR_REPLINSTMISMTCH, 8, \ LEN_AND_STR(instfilename_copy), jnlpool_shmid, DB_LEN_STR(REG), \ LEN_AND_STR(CNL->replinstfilename), CNL->jnlpool_shmid); \ } \ CSA->jnlpool_validate_check |= REPLINSTMISMTCH_CHECK_DONE; \ } \ } \ } #define JNLPOOL_INIT_IF_NEEDED(CSA, CSD, CNL) \ { \ GBLREF boolean_t is_replicator; \ GBLREF boolean_t pool_init; \ GBLREF gd_region *gv_cur_region; \ \ if (REPL_ALLOWED(CSD) && is_replicator) \ { \ if (!pool_init) \ jnlpool_init((jnlpool_user)GTMPROC, (boolean_t)FALSE, (boolean_t *)NULL); \ assert(pool_init); \ VALIDATE_INITIALIZED_JNLPOOL(CSA, CNL, gv_cur_region, GTMPROC, SCNDDBNOUPD_CHECK_TRUE); \ } \ } #define ASSERT_VALID_JNLPOOL(CSA) \ { \ GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; \ GBLREF jnlpool_addrs jnlpool; \ \ assert(CSA && CSA->critical && CSA->nl); /* should have been setup in mu_rndwn_replpool */ \ assert(jnlpool_ctl && (jnlpool_ctl == jnlpool.jnlpool_ctl)); \ assert(CSA->critical == (mutex_struct_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLPOOL_CTL_SIZE)); \ assert(CSA->nl == (node_local_ptr_t) ((sm_uc_ptr_t)CSA->critical + JNLPOOL_CRIT_SPACE \ + SIZEOF(mutex_spin_parms_struct))); \ assert(jnlpool_ctl->filehdr_off); \ assert(jnlpool_ctl->srclcl_array_off > jnlpool.jnlpool_ctl->filehdr_off); \ assert(jnlpool_ctl->sourcelocal_array_off > jnlpool.jnlpool_ctl->srclcl_array_off); \ assert(jnlpool.repl_inst_filehdr == (repl_inst_hdr_ptr_t) ((sm_uc_ptr_t)jnlpool_ctl \ + jnlpool_ctl->filehdr_off)); \ assert(jnlpool.gtmsrc_lcl_array == (gtmsrc_lcl_ptr_t)((sm_uc_ptr_t)jnlpool_ctl \ + jnlpool_ctl->srclcl_array_off)); \ assert(jnlpool.gtmsource_local_array == (gtmsource_local_ptr_t)((sm_uc_ptr_t)jnlpool_ctl \ + jnlpool_ctl->sourcelocal_array_off)); \ } /* Explanation for why we need the following macro. * * Normally a cdb_sc_blkmod check is done using the "bt". This is done in t_end and tp_tend. * But that is possible only if we hold crit. There are a few routines (TP only) that need * to do this check outside of crit (e.g. tp_hist, gvcst_search). For those, the following macro * is defined. This macro compares transaction numbers directly from the buffer instead of * going through the bt or blk queues. This is done to speed up processing. One consequence * is that we might encounter a situation where the buffer's contents hasn't been modified, * but the block might actually have been changed i.e. in VMS a twin buffer might have been * created or the "blk" field in the cache-record corresponding to this buffer might have * been made CR_BLKEMPTY etc. In these cases, we rely on the fact that the cycle for the * buffer would have been incremented thereby saving us in the cdb_sc_lostcr check which will * always FOLLOW (never PRECEDE) this check. * * Note that in case of BG, it is possible that the buffer could be in the process of being updated * (phase2 outside of crit). In this case we have to restart as otherwise we could incorrectly * validate an inconsistent state of the database as okay. For example, say our search path * contains a level-1 root-block and a level-0 data block. If both of these blocks were * concurrently being updated in phase2 (outside of crit) by another process, it is possible * (because of the order in which blocks are committed) that the data block contents get * modified first but the index block is still unchanged. If we traversed down the tree at * this instant, we are looking at a search path that contains a mix of pre-update and post-update * blocks and should never validate this traversal as okay. In this case, the cache record * corresponding to the index block would have its "in_tend" flag non-zero indicating update is pending. * * The order of the check should be cr->in_tend BEFORE the buffaddr->tn check. Doing it otherwise * would mean it is posible for the buffaddr->tn check to succeed and before the cr->in_tend * check is done the buffer gets rebuilt (from start to finish in phase2). This would result * in us falsely validating this transaction as okay when in fact we should have restarted. * * Because we rely on the fact that cr->in_tend is reset to 0 AFTER t1->buffaddr->tn is updated, and * since these could be updated concurrently, and since this macro is used outside of crit, we need to * ensure a read memory barrier is done. Currently, the only two places which use this macro are tp_hist.c * and gvcst_search.c. Out of this, the latter uses this only as a performance measure and not for correctness. * But the former uses this for correctness. In fact tp_tend.c relies on tp_hist.c doing a proper validation. * Therefore the read memory barrier is essential in tp_hist.c and not needed in gvcst_search.c. See tp_hist.c * for use of the read memory barrier and a comment describing why it is ok to do it only once per function * invocation (instead of using it once per block that gets validated). * * There are two variants of this macro. * TP_IS_CDB_SC_BLKMOD : That calculates the blktn by doing t1->buffaddr->tn explicitly. * TP_IS_CDB_SC_BLKMOD3 : This is provided the blktn as input so can avoid the explicit calculation. */ #define TP_IS_CDB_SC_BLKMOD(cr, t1) (((NULL != (cr)) && (cr)->in_tend) || ((t1)->tn <= ((blk_hdr_ptr_t)(t1)->buffaddr)->tn)) #define TP_IS_CDB_SC_BLKMOD3(cr, t1, blktn) (((NULL != (cr)) && (cr)->in_tend) || ((t1)->tn <= blktn)) #define MM_ADDR(SGD) ((sm_uc_ptr_t)(((sgmnt_data_ptr_t)SGD) + 1)) #ifdef VMS #define MASTER_MAP_BLOCKS_DFLT 64 /* 64 gives 128M possible blocks */ #else #define MASTER_MAP_BLOCKS_DFLT 496 /* 496 gives 992M possible blocks */ #define MASTER_MAP_BLOCKS_V5 112 /* 112 gives 224M possible blocks */ #endif #define MASTER_MAP_BLOCKS_V4 32 /* 32 gives 64M possible blocks */ #define MASTER_MAP_BLOCKS_MAX MASTER_MAP_BLOCKS_DFLT /* 496 gives 992M possible blocks */ #define MASTER_MAP_BLOCKS_V5_OLD 64 /* V5 database previous master map block size */ #define MASTER_MAP_SIZE_V5_OLD (MASTER_MAP_BLOCKS_V5_OLD * DISK_BLOCK_SIZE) #define MASTER_MAP_SIZE_V4 (MASTER_MAP_BLOCKS_V4 * DISK_BLOCK_SIZE) /* MUST be a multiple of DISK_BLOCK_SIZE */ #define MASTER_MAP_SIZE_MAX (MASTER_MAP_BLOCKS_MAX * DISK_BLOCK_SIZE) /* MUST be a multiple of DISK_BLOCK_SIZE */ #define MASTER_MAP_SIZE_DFLT (MASTER_MAP_BLOCKS_DFLT * DISK_BLOCK_SIZE) /* MUST be a multiple of DISK_BLOCK_SIZE */ #define MASTER_MAP_SIZE_V5 (MASTER_MAP_BLOCKS_V5 * DISK_BLOCK_SIZE) /* MUST be a multiple of DISK_BLOCK_SIZE */ #define MASTER_MAP_SIZE(SGD) (((sgmnt_data_ptr_t)SGD)->master_map_len) #define SGMNT_HDR_LEN SIZEOF(sgmnt_data) #define SIZEOF_FILE_HDR(SGD) (SGMNT_HDR_LEN + MASTER_MAP_SIZE(SGD)) #define SIZEOF_FILE_HDR_DFLT (SGMNT_HDR_LEN + MASTER_MAP_SIZE_DFLT) #define SIZEOF_FILE_HDR_V5 (SGMNT_HDR_LEN + MASTER_MAP_SIZE_V5) #define SIZEOF_FILE_HDR_MIN (SGMNT_HDR_LEN + MASTER_MAP_SIZE_V4) #define SIZEOF_FILE_HDR_MAX (SGMNT_HDR_LEN + MASTER_MAP_SIZE_MAX) #define MM_BLOCK (SGMNT_HDR_LEN / DISK_BLOCK_SIZE + 1) /* gt.m numbers blocks from 1 */ #define TH_BLOCK 1 #define JNL_NAME_SIZE 256 /* possibly expanded when opened */ #define JNL_NAME_EXP_SIZE 1024 /* MAXPATHLEN, before jnl_buffer in shared memory */ #define BLKS_PER_LMAP 512 #define MAXTOTALBLKS_V4 (MASTER_MAP_SIZE_V4 * 8 * BLKS_PER_LMAP) #define MAXTOTALBLKS_V5 (MASTER_MAP_SIZE_MAX * 8 * BLKS_PER_LMAP) #define MAXTOTALBLKS_V6 (MASTER_MAP_SIZE_MAX * 8 * BLKS_PER_LMAP) #define MAXTOTALBLKS_MAX (MASTER_MAP_SIZE_MAX * 8 * BLKS_PER_LMAP) #define MAXTOTALBLKS(SGD) (MASTER_MAP_SIZE(SGD) * 8 * BLKS_PER_LMAP) #define IS_BITMAP_BLK(blk) (ROUND_DOWN2(blk, BLKS_PER_LMAP) == blk) /* TRUE if blk is a bitmap */ /* UNIX - * V6 - 8K fileheader (= 16 blocks) + 248K mastermap (= 496 blocks) + 1 * V5 - 8K fileheader (= 16 blocks) + 56K mastermap (= 112 blocks) + 1 * V4 - 8K fileheader (= 16 blocks) + 16K mastermap (= 32 blocks) + 1 * VMS - 8K fileheader (= 16 blocks) + 32K mastermap (= 64 blocks) + 24K padding (= 48 blocks) + 1 */ #define START_VBN_V6 513 #define START_VBN_V5 129 #define START_VBN_V4 49 #define START_VBN_CURRENT START_VBN_V6 #define STEP_FACTOR 64 /* the factor by which flush_trigger is incremented/decremented */ #define MIN_FLUSH_TRIGGER(n_bts) ((n_bts)/4) /* the minimum flush_trigger as a function of n_bts */ #define MAX_FLUSH_TRIGGER(n_bts) ((n_bts)*15/16) /* the maximum flush_trigger as a function of n_bts */ #define MIN_FILLFACTOR 30 #define MAX_FILLFACTOR 100 #ifdef DEBUG_DYNGRD # define DEBUG_DYNGRD_ONLY(X) X #else # define DEBUG_DYNGRD_ONLY(X) #endif #ifdef VMS /* RET is a dummy that is not really used on VMS */ #define DCLAST_WCS_WTSTART(reg, num_bufs, RET) \ { \ unsigned int status; \ \ if (SS$_NORMAL != (status = sys$dclast(wcs_wtstart, reg, 0))) \ { \ assert(FALSE); \ status = DISABLE_AST; \ wcs_wtstart(reg); \ if (SS$_WASSET == status) \ ENABLE_AST; \ } \ } #elif defined(UNIX) #define DCLAST_WCS_WTSTART(reg, num_bufs, RET) RET = wcs_wtstart(reg, num_bufs); #else #error UNSUPPORTED PLATFORM #endif #define SAVE_WTSTART_PID(cnl, pid, index) \ { \ for (index = 0; index < MAX_WTSTART_PID_SLOTS; index++) \ if (0 == cnl->wtstart_pid[index]) \ break; \ if (MAX_WTSTART_PID_SLOTS > index) \ cnl->wtstart_pid[index] = pid; \ } #define CLEAR_WTSTART_PID(cnl, index) \ { \ if (MAX_WTSTART_PID_SLOTS > index) \ cnl->wtstart_pid[index] = 0; \ } #define WRITERS_ACTIVE(cnl) ((0 < cnl->intent_wtstart) || (0 < cnl->in_wtstart)) #define SIGNAL_WRITERS_TO_STOP(cnl) \ { \ SET_TRACEABLE_VAR((cnl)->wc_blocked, TRUE); /* to stop all active writers */ \ /* memory barrier needed to broadcast this information to other processors */ \ SHM_WRITE_MEMORY_BARRIER; \ } #define WAIT_FOR_WRITERS_TO_STOP(cnl, lcnt, maxiters) \ { /* We need to ensure that an uptodate value of cnl->intent_wtstart is read in the \ * WRITERS_ACTIVE macro every iteration of the loop hence the read memory barrier. \ */ \ SHM_READ_MEMORY_BARRIER; \ for (lcnt=1; WRITERS_ACTIVE(cnl) && (lcnt <= maxiters); lcnt++) \ { /* wait for any processes INSIDE or at ENTRY of wcs_wtstart to finish */ \ wcs_sleep(lcnt); \ SHM_READ_MEMORY_BARRIER; \ } \ } #define SIGNAL_WRITERS_TO_RESUME(cnl) \ { \ SET_TRACEABLE_VAR((cnl)->wc_blocked, FALSE); /* to let active writers resume */ \ /* memory barrier needed to broadcast this information to other processors */ \ SHM_WRITE_MEMORY_BARRIER; \ } #define INCR_INTENT_WTSTART(cnl) \ { \ INCR_CNT(&cnl->intent_wtstart, &cnl->wc_var_lock); /* signal intent to enter wcs_wtstart */ \ if (0 >= cnl->intent_wtstart) \ { /* possible if wcs_verify had reset this flag */ \ INCR_CNT(&cnl->intent_wtstart, &cnl->wc_var_lock); \ /* wcs_verify cannot possibly have reset this flag again because it does this only \ * after wcs_recover waits for a maximum of 1 minute (for this flag to become zero) \ * before giving up. Therefore for that to happen, we should have been context \ * switched out for 1 minute after the second INCR_CNT but before the below assert) \ * We believe that is an extremely unlikely condition so dont do anything about it. \ * In the worst case this will get reset to 0 by the next wcs_verify or INCR_CNT \ * (may need multiple INCR_CNTs depending on how negative a value this is) whichever \ * happens sooner. \ */ \ assert(0 < cnl->intent_wtstart); \ } \ } #define DECR_INTENT_WTSTART(cnl) \ { \ if (0 < cnl->intent_wtstart) \ DECR_CNT(&cnl->intent_wtstart, &cnl->wc_var_lock); \ /* else possible if wcs_verify had reset this flag */ \ } #define ENSURE_JNL_OPEN(csa, reg) \ { \ boolean_t was_crit; \ jnl_private_control *jpc; \ sgmnt_data_ptr_t csd; \ uint4 jnl_status; \ \ assert(cs_addrs == csa); \ assert(gv_cur_region == reg); \ assert(FALSE == reg->read_only); \ csd = csa->hdr; \ if (JNL_ENABLED(csd)) \ { \ was_crit = csa->now_crit; \ if (!was_crit) \ grab_crit(reg); \ jnl_status = JNL_ENABLED(csd) ? jnl_ensure_open() : 0; \ if (!was_crit) \ rel_crit(reg); \ if (0 != jnl_status) \ { \ jpc = csa->jnl; \ assert(NULL != jpc); \ if (SS_NORMAL != jpc->status) \ rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), \ DB_LEN_STR(gv_cur_region), jpc->status); \ else \ rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), \ DB_LEN_STR(gv_cur_region)); \ } \ } \ } /* the RET is meaningful only on UNIX */ #define JNL_ENSURE_OPEN_WCS_WTSTART(csa, reg, num_bufs, RET) \ { \ ENSURE_JNL_OPEN(csa, reg); \ DCLAST_WCS_WTSTART(reg, num_bufs, RET); \ } /* Macros to effect changes in the blks_to_upgrd field of the file-header. * We should hold crit on the region in all cases except for one when we are in MUPIP CREATE (but we are still standalone here). * Therefore we need not use any interlocks to update this field. This is asserted below. * Although we can derive "csd" from "csa", we pass them as two separate arguments for performance reasons. * Use local variables to record shared memory information doe debugging purposes in case of an assert failure. */ #define INCR_BLKS_TO_UPGRD(csa, csd, delta) \ { \ int4 new_blks_to_upgrd; \ int4 cur_blks_to_upgrd; \ int4 cur_delta; \ \ assert((csd)->createinprogress || (csa)->now_crit); \ cur_delta = (delta); \ assert((csa)->hdr == (csd)); \ assert(0 != cur_delta); \ cur_blks_to_upgrd = (csd)->blks_to_upgrd; \ assert(0 <= (csd)->blks_to_upgrd); \ new_blks_to_upgrd = cur_delta + cur_blks_to_upgrd; \ assert(0 <= new_blks_to_upgrd); \ (csd)->blks_to_upgrd = new_blks_to_upgrd; \ if (0 >= new_blks_to_upgrd) \ { \ if (0 == new_blks_to_upgrd) \ (csd)->tn_upgrd_blks_0 = (csd)->trans_hist.curr_tn; \ else \ { /* blks_to_upgrd counter in the fileheader should never hold a \ * negative value. Note down the negative value in a separate \ * field for debugging and set the counter to 0. \ */ \ (csd)->blks_to_upgrd = 0; \ (csd)->blks_to_upgrd_subzero_error -= (new_blks_to_upgrd); \ } \ } else \ (csd)->fully_upgraded = FALSE; \ } #define DECR_BLKS_TO_UPGRD(csa, csd, delta) INCR_BLKS_TO_UPGRD((csa), (csd), -(delta)) /* Interlocked queue instruction constants ... */ #define QI_STARVATION 3 #define EMPTY_QUEUE 0L #define QUEUE_WAS_EMPTY 1 #define INTERLOCK_FAIL -1L #define QUEUE_INSERT_SUCCESS 1 typedef trans_num bg_trc_rec_tn; typedef int4 bg_trc_rec_cntr; typedef struct { int4 curr_count; /* count for this invocation of shared memory */ int4 cumul_count; /* count from the creation of database (not including this invocation) */ } db_csh_acct_rec; #define TAB_DB_CSH_ACCT_REC(A,B,C) A, enum db_csh_acct_rec_type { #include "tab_db_csh_acct_rec.h" n_db_csh_acct_rec_types }; #undef TAB_DB_CSH_ACCT_REC #include "gvstats_rec.h" #define GVSTATS_SET_CSA_STATISTIC(csa, counter, value) \ { \ csa->gvstats_rec.counter = value; \ } #define INCR_GVSTATS_COUNTER(csa, cnl, counter, increment) \ { \ csa->gvstats_rec.counter += increment; \ cnl->gvstats_rec.counter += increment; \ } #if defined(DEBUG) || defined(DEBUG_DB_CSH_COUNTER) # define INCR_DB_CSH_COUNTER(csa, counter, increment) \ if (csa->read_write || dba_bg == csa->hdr->acc_meth) \ csa->hdr->counter.curr_count += increment; #else # define INCR_DB_CSH_COUNTER(csa, counter, increment) #endif enum tp_blkmod_type /* used for accounting in cs_data->tp_cdb_sc_blkmod[] */ { tp_blkmod_nomod = 0, tp_blkmod_gvcst_srch, tp_blkmod_t_qread, tp_blkmod_tp_tend, tp_blkmod_tp_hist, n_tp_blkmod_types }; /* Below is a list of macro bitmasks used to set the global variable "donot_commit". This variable should normally be 0. * But in rare cases, we could end up in situations where we know it is a restartable situation but decide not to * restart right away (because of interface issues that the function where this is detected cannot signal a restart * or because we dont want to take a performance hit to check this restartable situation in highly frequented code if * the restart will anyway be detected before commit. In this cases, this variable will take on non-zero values. * The commit logic will assert that this variable is indeed zero after validation but before proceeding with commit. */ #define DONOTCOMMIT_TPHIST_BLKTARGET_MISMATCH (1 << 0) /* Restartable situation encountered in tp_hist */ #define DONOTCOMMIT_GVCST_DELETE_BLK_CSE_TLEVEL (1 << 1) /* Restartable situation encountered in gvcst_delete_blk */ #define DONOTCOMMIT_JNLGETCHECKSUM_NULL_CR (1 << 2) /* Restartable situation encountered in jnl_get_checksum.h */ #define DONOTCOMMIT_GVCST_KILL_ZERO_TRIGGERS (1 << 3) /* Restartable situation encountered in gvcst_kill */ #define DONOTCOMMIT_GVCST_BLK_BUILD_TPCHAIN (1 << 4) /* Restartable situation encountered in gvcst_blk_build */ #define DONOTCOMMIT_T_QREAD_BAD_PVT_BUILD (1 << 5) /* Restartable situation due to bad private build in t_qread */ #define DONOTCOMMIT_GVCST_SEARCH_LEAF_BUFFADR_NOTSYNC (1 << 6) /* Restartable situation encountered in gvcst_search */ #define DONOTCOMMIT_GVCST_SEARCH_BLKTARGET_MISMATCH (1 << 7) /* Restartable situation encountered in gvcst_search */ #define TAB_BG_TRC_REC(A,B) B, enum bg_trc_rec_type { #include "tab_bg_trc_rec.h" n_bg_trc_rec_types }; #undef TAB_BG_TRC_REC #define UPGRD_WARN_INTERVAL (60 * 60 * 24) /* Once every 24 hrs */ /* The following structure is used to determine the endianess of a database header. */ typedef union { struct { unsigned short little_endian; unsigned short big_endian; } shorts; uint4 word32; } endian32_struct; #ifdef BIGENDIAN # define ENDIANCHECKTHIS big_endian #else # define ENDIANCHECKTHIS little_endian #endif #define CHECK_DB_ENDIAN(CSD,FNLEN,FNNAME) \ { \ endian32_struct check_endian; \ check_endian.word32 = (CSD)->minor_dbver; \ if (!check_endian.shorts.ENDIANCHECKTHIS) \ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_DBENDIAN, 4, FNLEN, FNNAME, ENDIANOTHER, \ ENDIANTHIS); \ } /* This is the structure describing a segment. It is used as a database file header (for MM or BG access methods). * The overloaded fields for MM and BG are n_bts, bt_buckets. */ /* ***NOTE*** If the field minor_dbver is updated, please also update gdsdbver.h and db_auto_upgrade.c appropriately (see db_auto_upgrade for reasons and description). SE 5/2006 */ typedef struct sgmnt_data_struct { /************* MOSTLY STATIC DATABASE STATE FIELDS **************************/ unsigned char label[GDS_LABEL_SZ]; int4 blk_size; /* Block size for the file. Static data defined at db creation time */ int4 master_map_len; /* Length of master map */ int4 bplmap; /* Blocks per local map (bitmap). static data defined at db creation time */ int4 start_vbn; /* starting virtual block number. */ enum db_acc_method acc_meth; /* Access method (BG or MM) */ uint4 max_bts; /* Maximum number of bt records allowed in file */ int4 n_bts; /* number of cache record/blocks */ int4 bt_buckets; /* Number of buckets in bt table */ int4 reserved_bytes; /* Database blocks will always leave this many bytes unused */ int4 max_rec_size; /* maximum record size allowed for this file */ int4 max_key_size; /* maximum key size allowed for this file */ uint4 lock_space_size; /* Number of bytes to be used for locks (in database for bg) */ uint4 extension_size; /* Number of gds data blocks to extend by */ uint4 def_coll; /* Default collation type for new globals */ uint4 def_coll_ver; /* Default collation type version */ boolean_t std_null_coll; /* 0 -> GT.M null collation,i,e, null subs collate between numeric and string * 1-> standard null collation i.e. null subs collate before numeric and string */ boolean_t null_subs; uint4 free_space; /* Space in file header not being used */ mutex_spin_parms_struct mutex_spin_parms; int4 max_update_array_size; /* maximum size of update array needed for one non-TP set/kill */ int4 max_non_bm_update_array_size;/* maximum size of update array excepting bitmaps */ boolean_t file_corrupt; /* If set, it shuts the file down. No process (except DSE) can * successfully map this section after the flag is set to TRUE. Processes * that already have it mapped should produce an error the next time that * they use the file. The flag can only be reset by the DSE utility. */ enum mdb_ver minor_dbver; /* Minor DB version field that is incremented when minor changes to this * file-header or API changes occur. See note at top of sgmnt_data. */ uint4 jnl_checksum; uint4 wcs_phase2_commit_wait_spincnt; /* # of spin iterations before sleeping while waiting for phase2 commits */ enum mdb_ver last_mdb_ver; /* Minor DB version of the GT.M version that last accessed this database. * Maintained only by GT.M versions V5.3-003 and greater. */ /* The structure is 128-bytes in size at this point */ /************* FIELDS SET AT CREATION TIME ********************************/ char filler_created[52]; /* Now unused .. was "file_info created" */ boolean_t createinprogress; /* TRUE only if MUPIP CREATE is in progress. FALSE otherwise */ int4 creation_time4; /* Lower order 4-bytes of time when the database file was created */ int4 creation_filler_8byte; /************* FIELDS USED BY TN WARN PROCESSING *************************/ trans_num max_tn; /* Hardstop TN for this database */ trans_num max_tn_warn; /* TN for next TN_RESET warning for this database */ /************* FIELDS SET BY MUPIP BACKUP/REORG *************************/ trans_num last_inc_backup; trans_num last_com_backup; trans_num last_rec_backup; block_id last_inc_bkup_last_blk; /* Last block in the database at time of last incremental backup */ block_id last_com_bkup_last_blk; /* Last block in the database at time of last comprehensive backup */ block_id last_rec_bkup_last_blk; /* Last block in the database at time of last record-ed backup */ block_id reorg_restart_block; char filler_256[8]; /************* FIELDS SET WHEN DB IS OPEN ********************************/ char now_running[MAX_REL_NAME];/* for active version stamp */ # ifdef VMS uint4 owner_node; /* Node on cluster that "owns" the file -- applies to VMS only */ # else uint4 filler_owner_node; /* 4-byte filler - since owner_node is maintained on VMS only */ # endif uint4 image_count; /* for db freezing. Set to "process_id" on Unix and "image_count" on VMS */ uint4 freeze; /* for db freezing. Set to "getuid" on Unix and "process_id" on VMS */ int4 kill_in_prog; /* counter for multi-crit kills that are not done yet */ int4 abandoned_kills; char filler_320[8]; /************* FIELDS USED IN V4 <==> V5 COMPATIBILITY MODE ****************/ trans_num tn_upgrd_blks_0; /* TN when blks_to_upgrd becomes 0. * Never set = 0 => we have not achieved this yet, * Always set = 1 => database was created as V5 (or current version) */ trans_num desired_db_format_tn; /* Database tn when last db format change occurred */ trans_num reorg_db_fmt_start_tn; /* Copy of desired_db_format_tn when MUPIP REORG UPGRADE/DOWNGRADE started */ block_id reorg_upgrd_dwngrd_restart_block; /* Block numbers lesser than this were last upgraded/downgraded by * MUPIP REORG UPGRADE|DOWNGRADE before being interrupted */ int4 blks_to_upgrd; /* Blocks not at current block version level */ int4 blks_to_upgrd_subzero_error; /* number of times "blks_to_upgrd" potentially became negative */ enum db_ver desired_db_format; /* Output version for database blocks (normally current version) */ boolean_t fully_upgraded; /* Set to TRUE by MUPIP REORG UPGRADE when ALL blocks (including RECYCLED blocks) * have been examined and upgraded (if necessary) and blks_to_upgrd is set to 0; * If set to TRUE, this guarantees all blocks in the database are upgraded. * "blks_to_upgrd" being 0 does not necessarily guarantee the same since the * counter might have become incorrect (due to presently unknown reasons). * set to FALSE whenever desired_db_format changes or the database is * updated with V4 format blocks (by MUPIP JOURNAL). */ boolean_t db_got_to_v5_once; /* Set to TRUE by the FIRST MUPIP REORG UPGRADE (since MUPIP UPGRADE was run * to upgrade the file header to V5 format) when it completes successfully. * The FIRST reorg upgrade marks all RECYCLED blocks as FREE. Successive reorg * upgrades keep RECYCLED blocks as they are while still trying to upgrade them. * This is because ONLY the FIRST reorg upgrade could see RECYCLED blocks in V4 * format that are too full (lack the additional space needed by the V5 block * header) to be upgraded to V5 format. Once these are marked FREE, all future * block updates happen in V5 format in the database buffers so even if they * are written in V4 format to disk, they are guaranteed to be upgradeable. * This field marks that transition in the db and is never updated thereafter. */ boolean_t opened_by_gtmv53; /* Set to TRUE the first time this database is opened by GT.M V5.3-000 and higher */ char filler_384[12]; /************* FIELDS RELATED TO DB TRANSACTION HISTORY *****************************/ th_index trans_hist; /* transaction history - if moved from 1st filehdr block, change TH_BLOCK */ char filler_trans_hist[8]; /************* FIELDS RELATED TO WRITE CACHE FLUSHING *******************************/ int4 flush_time[2]; int4 flush_trigger; int4 n_wrt_per_flu; /* Number of writes per flush call. Overloaded for BG and MM */ int4 wait_disk_space; /* seconds to wait for diskspace before giving up on a db block write */ int4 defer_time; /* defer write * 0 => immediate, * -1 => infinite defer, * >0 => defer_time * flush_time[0] is actual defer time * default value = 1 => a write-timer every csd->flush_time[0] seconds */ volatile boolean_t filler_wc_blocked; /* Now moved to node_local */ boolean_t mumps_can_bypass; /* Allow mumps processes to bypass flushing, access control, and ftok semaphore * in gds_rundown(). This was done to improve shutdown performance. */ char filler_512[16]; /************* FIELDS Used for update process performance improvement. Some may go away in later releases ********/ uint4 reserved_for_upd; /* Percentage (%) of blocks reserved for update process disk read */ uint4 avg_blks_per_100gbl; /* Number of blocks read on average for 100 global key read */ uint4 pre_read_trigger_factor;/* Percentage (%) of blocks reserved for prereader disk read */ uint4 writer_trigger_factor; /* For update process writers flush trigger */ /************* FIELDS USED ONLY BY UNIX ********************************/ int4 semid; /* Since int may not be of fixed size, int4 is used */ int4 shmid; /* Since int may not be of fixed size, int4 is used */ gtm_time8 gt_sem_ctime; /* time of creation of semaphore */ gtm_time8 gt_shm_ctime; /* time of creation of shared memory */ char filler_unixonly[40]; /* to ensure this section has 64-byte multiple size */ /************* ACCOUNTING INFORMATION ********************************/ int4 filler_n_retries[CDB_MAX_TRIES];/* Now moved to TAB_GVSTATS_REC section */ int4 filler_n_puts; /* Now moved to TAB_GVSTATS_REC section */ int4 filler_n_kills; /* Now moved to TAB_GVSTATS_REC section */ int4 filler_n_queries; /* Now moved to TAB_GVSTATS_REC section */ int4 filler_n_gets; /* Now moved to TAB_GVSTATS_REC section */ int4 filler_n_order; /* Now moved to TAB_GVSTATS_REC section */ int4 filler_n_zprevs; /* Now moved to TAB_GVSTATS_REC section */ int4 filler_n_data; /* Now moved to TAB_GVSTATS_REC section */ uint4 filler_n_puts_duplicate; /* Now moved to TAB_GVSTATS_REC section */ uint4 filler_n_tp_updates; /* Now moved to TAB_GVSTATS_REC section */ uint4 filler_n_tp_updates_duplicate; /* Now moved to TAB_GVSTATS_REC section */ char filler_accounting_64_align[4]; /* to ensure this section has 64-byte multiple size */ /************* CCP/RC RELATED FIELDS (CCP STUFF IS NOT USED CURRENTLY BY GT.M) *************/ int4 staleness[2]; /* timer value */ int4 ccp_tick_interval[2]; /* quantum to release write mode if no write occurs and others are queued * These three values are all set at creation by mupip_create */ int4 ccp_quantum_interval[2];/* delta timer for ccp quantum */ int4 ccp_response_interval[2];/* delta timer for ccp mailbox response */ boolean_t ccp_jnl_before; /* used for clustered to pass if jnl file has before images */ boolean_t clustered; /* FALSE (clustering is currently unsupported) */ boolean_t unbacked_cache; /* FALSE for clustering. TRUE otherwise */ int4 rc_srv_cnt; /* Count of RC servers accessing database */ int4 dsid; /* DSID value, non-zero when being accessed by RC */ int4 rc_node; char filler_ccp_rc[8]; /* to ensure this section has 64-byte multiple size */ /************* REPLICATION RELATED FIELDS ****************/ /* VMS does not yet have multi-site replication functionality. Hence the two sets of fields in this section. */ #ifdef VMS seq_num reg_seqno; /* the jnl seqno of the last update to this region -- 8-byte aligned */ seq_num resync_seqno; /* the resync-seqno to be sent to the secondary */ trans_num resync_tn; /* db tn corresponding to resync_seqno - used in losttrans handling */ seq_num old_resync_seqno; /* to find out if transactions were sent from primary to secondary */ int4 repl_state; /* state of replication whether open/closed/was_open */ char filler_repl[28]; /* to ensure this section has 64-byte multiple size */ #else seq_num reg_seqno; /* the jnl seqno of the last update to this region -- 8-byte aligned */ seq_num pre_multisite_resync_seqno; /* previous resync-seqno field now moved to the replication instance file */ trans_num zqgblmod_tn; /* db tn corresponding to zqgblmod_seqno - used in losttrans handling */ seq_num zqgblmod_seqno; /* minimum resync seqno of ALL -fetchresync rollbacks that happened on a secondary * (that was formerly a root primary) AFTER the most recent * MUPIP REPLIC -LOSTTNCOMPLETE command */ int4 repl_state; /* state of replication whether open/closed/was_open */ boolean_t multi_site_open; /* Set to TRUE the first time a process opens the database using * a GT.M version that supports multi-site replication. FALSE until then */ seq_num filler_seqno; /* formerly dualsite_resync_seqno but removed once dual-site support was dropped */ char filler_repl[16]; /* to ensure this section has 64-byte multiple size */ #endif /************* TP RELATED FIELDS ********************/ int4 filler_n_tp_retries[12]; /* Now moved to TAB_GVSTATS_REC section */ int4 filler_n_tp_retries_conflicts[12]; /* Now moved to TAB_GVSTATS_REC section */ int4 tp_cdb_sc_blkmod[8]; /* Notes down the number of times each place got a cdb_sc_blkmod in tp. * Only first 4 array entries are updated now, but space is allocated * for 4 more if needed in the future. */ /************* JOURNALLING RELATED FIELDS ****************/ uint4 jnl_alq; uint4 jnl_deq; int4 jnl_buffer_size; /* in 512-byte pages */ boolean_t jnl_before_image; int4 jnl_state; /* journaling state: same as enum jnl_state_codes in jnl.h */ uint4 jnl_file_len; /* journal file name length */ uint4 autoswitchlimit; /* limit in disk blocks (max 4GB) when jnl should be auto switched */ int4 epoch_interval; /* Time between successive epochs in epoch-seconds */ uint4 alignsize; /* alignment size for JRT_ALIGN */ int4 jnl_sync_io; /* drives sync I/O ('direct' if applicable) for journals, if set (UNIX) */ /* writers open NOCACHING to bypass XFC cache, if set (VMS) */ int4 yield_lmt; /* maximum number of times a process yields to get optimal jnl writes */ boolean_t turn_around_point; trans_num jnl_eovtn; /* last tn for a closed jnl; otherwise epoch tn from the epoch before last */ char filler_jnl[8]; /* to ensure this section has 64-byte multiple size */ /************* INTERRUPTED RECOVERY RELATED FIELDS ****************/ seq_num intrpt_recov_resync_seqno;/* resync/fetchresync jnl_seqno of interrupted rollback */ jnl_tm_t intrpt_recov_tp_resolve_time;/* since-time for the interrupted recover */ boolean_t recov_interrupted; /* whether a MUPIP JOURNAL RECOVER/ROLLBACK on this db got interrupted */ int4 intrpt_recov_jnl_state; /* journaling state at start of interrupted recover/rollback */ int4 intrpt_recov_repl_state;/* replication state at start of interrupted recover/rollback */ /************* TRUNCATE RELATED FIELDS ****************/ uint4 before_trunc_total_blks; /* Used in recover_truncate to detect interrupted truncate */ uint4 after_trunc_total_blks; /* All these fields are used to repair interrupted truncates */ uint4 before_trunc_free_blocks; uint4 filler_trunc; /* Previously before_trunc_file_size, which is no longer used */ char filler_1k[24]; /************* HUGE CHARACTER ARRAYS **************/ unsigned char jnl_file_name[JNL_NAME_SIZE]; /* journal file name */ unsigned char reorg_restart_key[OLD_MAX_KEY_SZ + 1]; /* 1st key of a leaf block where reorg was done last time. * Note: In mu_reorg we don't save keys longer than OLD_MAX_KEY_SZ */ char machine_name[MAX_MCNAMELEN]; char encryption_hash[GTMCRYPT_RESERVED_HASH_LEN]; /* char filler_2k[256] was here before adding the encryption_hash. Since the GTMCRYPT_RESERVED_HASH_LEN * consumes 256 bytes, filler_2k has been removed. */ /************* BG_TRC_REC RELATED FIELDS ***********/ # define TAB_BG_TRC_REC(A,B) bg_trc_rec_tn B##_tn; # include "tab_bg_trc_rec.h" # undef TAB_BG_TRC_REC char bg_trc_rec_tn_filler [1200 - (SIZEOF(bg_trc_rec_tn) * n_bg_trc_rec_types)]; # define TAB_BG_TRC_REC(A,B) bg_trc_rec_cntr B##_cntr; # include "tab_bg_trc_rec.h" # undef TAB_BG_TRC_REC char bg_trc_rec_cntr_filler[600 - (SIZEOF(bg_trc_rec_cntr) * n_bg_trc_rec_types)]; /************* DB_CSH_ACCT_REC RELATED FIELDS ***********/ # define TAB_DB_CSH_ACCT_REC(A,B,C) db_csh_acct_rec A; # include "tab_db_csh_acct_rec.h" # undef TAB_DB_CSH_ACCT_REC char db_csh_acct_rec_filler_4k[248 - (SIZEOF(db_csh_acct_rec) * n_db_csh_acct_rec_types)]; /************* GVSTATS_REC RELATED FIELDS ***********/ gvstats_rec_t gvstats_rec; char gvstats_rec_filler_4k_plus_512[512 - SIZEOF(gvstats_rec_t)]; char filler_4k_plus_512[368]; /* Note: this filler array should START at offset 4K+512. So any additions * of new fields should happen at the END of this filler array and * the filler array size correspondingly adjusted. */ /************* INTERRUPTED RECOVERY RELATED FIELDS continued ****************/ seq_num intrpt_recov_resync_strm_seqno[MAX_SUPPL_STRMS];/* resync/fetchresync jnl_seqno of interrupted rollback * corresponding to each non-supplementary stream. */ /************* DB CREATION AND UPGRADE CERTIFICATION FIELDS ***********/ enum db_ver creation_db_ver; /* Major DB version at time of creation */ enum mdb_ver creation_mdb_ver; /* Minor DB version at time of creation */ enum db_ver certified_for_upgrade_to; /* Version the database is certified for upgrade to */ int4 filler_5k; /************* SECSHR_DB_CLNUP RELATED FIELDS (now moved to node_local) ***********/ int4 secshr_ops_index_filler; int4 secshr_ops_array_filler[255]; /* taking up 1k */ /********************************************************/ compswap_time_field next_upgrd_warn; /* Time when we can send the next upgrade warning to the operator log */ boolean_t is_encrypted; uint4 db_trigger_cycle; /* incremented every MUPIP TRIGGER command that changes ^#t global contents */ /************* SUPPLEMENTARY REPLICATION INSTANCE RELATED FIELDS ****************/ seq_num strm_reg_seqno[MAX_SUPPL_STRMS]; /* the jnl seqno of the last update to this region for a given * supplementary stream -- 8-byte aligned */ seq_num save_strm_reg_seqno[MAX_SUPPL_STRMS]; /* a copy of strm_reg_seqno[] before it gets changed in * "mur_process_intrpt_recov". Used only by journal recovery. * See comment in "mur_get_max_strm_reg_seqno" function for * purpose of this field. Must also be 8-byte aligned. */ boolean_t freeze_on_fail; /* Freeze instance if failure of this database observed */ boolean_t span_node_absent; /* Database does not contain the spanning node */ boolean_t maxkeysz_assured; /* All the keys in the database are less than MAX_KEY_SIZE */ char filler_7k[724]; char filler_8k[1024]; /********************************************************/ /* Master bitmap immediately follows. Tells whether the local bitmaps have any free blocks or not. */ } sgmnt_data; #ifdef DB64 # ifdef __osf__ # pragma pointer_size(save) # pragma pointer_size(long) # else # error UNSUPPORTED PLATFORM # endif #endif typedef sgmnt_data *sgmnt_data_ptr_t; #ifdef DB64 # ifdef __osf__ # pragma pointer_size(restore) # endif #endif typedef struct { FILL8DCL(cache_que_heads_ptr_t, cache_state, 1); /* pointer to beginnings of state queues */ } sgbg_addrs; typedef struct { # ifdef VMS FILL8DCL(sm_uc_ptr_t, base_addr, 1); # else int filler; # endif } sgmm_addrs; #define MAX_NM_LEN MAX_MIDENT_LEN #define MIN_RN_LEN 1 #define MAX_RN_LEN MAX_MIDENT_LEN #define V4_MAX_RN_LEN 31 /* required for dbcertify.h */ #define MIN_SN_LEN 1 #define MAX_SN_LEN MAX_MIDENT_LEN #define STR_SUB_PREFIX 0x0FF #define SUBSCRIPT_STDCOL_NULL 0x01 #define STR_SUB_ESCAPE 0X01 #define SPANGLOB_SUB_ESCAPE 0X02 #define STR_SUB_MAXVAL 0xFF #define SUBSCRIPT_ZERO 0x080 #define SUBSCRIPT_BIAS 0x0BE #define NEG_MNTSSA_END 0x0FF #define KEY_DELIMITER 0X00 #define MIN_DB_BLOCKS 10 /* this should be maintained in conjunction with the mimimum allocation in GDEINIT.M */ /* definition for NULL_SUBSCRIPTS */ #define NEVER 0 #define ALWAYS 1 #define ALLOWEXISTING 2 #define OFFSET(x,y) ((uchar_ptr_t)x - (uchar_ptr_t)y) #define FC_READ 0 #define FC_WRITE 1 #define FC_OPEN 2 #define FC_CLOSE 3 #define DO_BADDBVER_CHK(REG, TSD) \ { \ if (MEMCMP_LIT(TSD->label, GDS_LABEL)) \ { \ if (memcmp(TSD->label, GDS_LABEL, GDS_LABEL_SZ - 3)) \ rts_error_csa(CSA_ARG(REG2CSA(REG)) VARLSTCNT(4) ERR_DBNOTGDS, 2, \ DB_LEN_STR(REG)); \ else \ rts_error_csa(CSA_ARG(REG2CSA(REG)) VARLSTCNT(4) ERR_BADDBVER, 2, \ DB_LEN_STR(REG)); \ } \ } #define DO_DB_HDR_CHECK(REG, TSD) \ { \ GBLREF boolean_t mupip_jnl_recover; \ uint4 gtm_errcode = 0; \ \ if (TSD->createinprogress) \ gtm_errcode = ERR_DBCREINCOMP; \ if (TSD->file_corrupt && !mupip_jnl_recover) \ gtm_errcode = ERR_DBFLCORRP; \ if ((dba_mm == TSD->acc_meth) && TSD->blks_to_upgrd) \ gtm_errcode = ERR_MMNODYNUPGRD; \ if (0 != gtm_errcode) \ { \ if (IS_DSE_IMAGE) \ { \ gtm_errcode = MAKE_MSG_WARNING(gtm_errcode); \ gtm_putmsg_csa(CSA_ARG(REG2CSA(REG)) VARLSTCNT(4) gtm_errcode, 2, \ DB_LEN_STR(REG)); \ } else \ rts_error_csa(CSA_ARG(REG2CSA(REG)) VARLSTCNT(4) gtm_errcode, 2, \ DB_LEN_STR(REG)); \ } \ } #define REG2CSA(REG) (((REG) && (REG)->dyn.addr && (REG)->dyn.addr->file_cntl) ? (&FILE_INFO(REG)->s_addrs) : NULL) #define JCTL2CSA(JCTL) (((JCTL) && (JCTL->reg_ctl)) ? (JCTL->reg_ctl->csa) : NULL) typedef struct file_control_struct { sm_uc_ptr_t op_buff; UNIX_ONLY(gtm_int64_t) VMS_ONLY(int4) op_pos; int op_len; void *file_info; /* Pointer for OS specific struct */ char file_type; char op; } file_control; typedef struct header_struct_struct { char label[12]; unsigned filesize; /* size of file excluding GDE info */ /* removed unused file_log struct */ } header_struct; typedef struct gdr_name_struct { mstr name; mstr exp_name; struct gdr_name_struct *link; struct gd_addr_struct *gd_ptr; } gdr_name; typedef struct gd_addr_struct { struct gd_region_struct *local_locks; int4 max_rec_size; short n_maps; short n_regions; short n_segments; short filler; struct gd_binding_struct *maps; struct gd_region_struct *regions; struct gd_segment_struct *segments; struct gd_addr_struct *link; struct hash_table_mname_struct *tab_ptr; gd_id *id; UINTPTR_T end; } gd_addr; typedef gd_addr *(*gd_addr_fn_ptr)(); typedef struct gd_segment_struct { unsigned short sname_len; unsigned char sname[MAX_SN_LEN + 1]; unsigned short fname_len; unsigned char fname[MAX_FN_LEN + 1]; unsigned short blk_size; unsigned short ext_blk_count; uint4 allocation; struct CLB *cm_blk; unsigned char defext[4]; char defer_time; /* Was passed in cs_addrs */ unsigned char file_type; unsigned char buckets; /* Was passed in FAB */ unsigned char windows; /* Was passed in FAB */ uint4 lock_space; uint4 global_buffers; /* Was passed in FAB */ uint4 reserved_bytes; /* number of bytes to be left in every database block */ enum db_acc_method acc_meth; file_control *file_cntl; struct gd_region_struct *repl_list; UNIX_ONLY(boolean_t is_encrypted;) } gd_segment; typedef union { int4 offset; /* relative offset to segment */ gd_segment *addr; /* absolute address of segment */ } gd_seg_addr; typedef struct gd_region_struct { unsigned short rname_len; unsigned char rname[MAX_RN_LEN + 1]; unsigned short max_key_size; uint4 max_rec_size; gd_seg_addr dyn; gd_seg_addr stat; bool open; bool lock_write; /* Field is not currently used by GT.M */ char null_subs; /* 0 ->NEVER(previous NO), 1->ALWAYS(previous YES), 2->ALLOWEXISTING * i.e. will allow read null subs but prohibit set */ unsigned char jnl_state; /* deleted gbl_lk_root and lcl_lk_root, obsolete fields */ uint4 jnl_alq; #ifdef UNIX uint4 jnl_deq; uint4 jnl_autoswitchlimit; uint4 jnl_alignsize; /* not used, reserved */ int4 jnl_epoch_interval; /* not used, reserved */ int4 jnl_sync_io; /* not used, reserved */ int4 jnl_yield_lmt; /* not used, reserved */ #else unsigned short jnl_deq; #endif unsigned short jnl_buffer_size; bool jnl_before_image; bool opening; bool read_only; bool was_open; unsigned char cmx_regnum; unsigned char def_coll; bool std_null_coll; /* 0 -> GT.M null collation,i,e, null subs collate between numeric and string * 1-> standard null collation i.e. null subs collate before numeric and string */ #ifdef UNIX bool freeze_on_fail; bool mumps_can_bypass; /* Allow mumps processes to bypass flushing, access control, and ftok semaphore * in gds_rundown(). This was done to improve shutdown performance. */ #endif unsigned char jnl_file_len; unsigned char jnl_file_name[JNL_NAME_SIZE]; /* VMS file id struct goes to OS specific struct */ /* VMS lock structure for reference goes to OS specific struct */ int4 node; int4 sec_size; } gd_region; typedef struct sgmnt_addrs_struct { sgmnt_data_ptr_t hdr; sm_uc_ptr_t bmm; sm_uc_ptr_t wc; bt_rec_ptr_t bt_header; bt_rec_ptr_t bt_base; th_rec_ptr_t th_base; th_index_ptr_t ti; node_local_ptr_t nl; mutex_struct_ptr_t critical; struct shmpool_buff_hdr_struct *shmpool_buffer; /* 1MB chunk of shared memory that we micro manage */ sm_uc_ptr_t db_addrs[2]; sm_uc_ptr_t lock_addrs[2]; struct gv_namehead_struct *dir_tree; # ifdef GTM_TRIGGER struct gv_namehead_struct *hasht_tree; # endif struct sgmnt_addrs_struct *next_fenced; /* NULL if db has journaling turned off (or disabled) * Otherwise (db has journaling turned on), it is * NULL if this db was not updated in this TP/ZTP * non-NULL if this db was updated in this TP/ZTP * The non-NULL value points to the next csa that * has a non-NULL next_fenced value i.e. a linked list * of csas. The end of the list is JNL_FENCE_LIST_END * (cannot use NULL due to special meaning described * above and hence using a macro which evaluates to -1). */ struct jnl_private_control_struct *jnl; struct sgm_info_struct *sgm_info_ptr; gd_region *region; /* the region corresponding to this csa */ struct hash_table_mname_struct *gvt_hashtab; /* NON-NULL only if regcnt > 1; * Maintains all gv_targets mapped to this db file */ struct reg_ctl_list_struct *rctl; /* pointer to rctl for this region (used only if jgbl.forw_phase_recovery) */ struct sgmnt_addrs_struct *next_csa; /* points to csa of NEXT database that has been opened by this process */ # ifdef GTM_CRYPT char *encrypted_blk_contents; gtmcrypt_key_t encr_key_handle; # endif # ifdef GTM_SNAPSHOT struct snapshot_context_struct *ss_ctx; # endif union { sgmm_addrs mm; sgbg_addrs bg; /* May add new pointers here for other methods or change to void ptr */ } acc_meth; gvstats_rec_t gvstats_rec; trans_num dbsync_timer_tn;/* copy of csa->ti->curr_tn when csa->dbsync_timer became TRUE. * used to check if any updates happened in between when we flushed all * dirty buffers to disk and when the idle flush timer (5 seconds) popped. */ /* 8-byte aligned at this point on all platforms (32-bit, 64-bit or Tru64 which is a mix of 32-bit and 64-bit pointers) */ size_t fullblockwrite_len; /* Length of a full block write */ uint4 total_blks; /* Last we knew, file was this big. Used to signal MM processing file was * extended and needs to be remapped. In V55000 was used with BG to detect * file truncates. It is no longer used for that purpose: it was not necessary * in the first place because bitmap block validations in t_end/tp_tend prevent * updates from trying to commit past the end of the file. * See mu_truncate.c for more details. */ uint4 prev_free_blks; /* The following uint4's are treated as bools but must be 4 bytes to avoid interaction between bools in interrupted routines and possibly lost data */ volatile uint4 timer; /* This process has a timer for this region */ volatile uint4 in_wtstart; /* flag we are busy writing */ volatile uint4 now_crit; /* This process has the critical write lock */ volatile uint4 wbuf_dqd; /* A write buffer has been dequeued - signals that extra cleanup required if die while on */ uint4 stale_defer; /* Stale processing deferred this region */ boolean_t freeze; volatile boolean_t dbsync_timer; /* whether a timer to sync the filehdr (and write epoch) is active */ block_id reorg_last_dest; /* last destinition block used for swap */ boolean_t jnl_before_image; boolean_t read_write; boolean_t persistent_freeze; /* if true secshr_db_clnup() won't unfreeze this region */ /* The following 3 fields are in cs_addrs instead of in the file-header since they are a function * of the journal-record sizes that can change with journal-version-numbers (for the same database). */ int4 pblk_align_jrecsize; /* maximum size of a PBLK record with corresponding ALIGN record */ int4 min_total_tpjnl_rec_size; /* minimum journal space requirement for a TP transaction */ int4 min_total_nontpjnl_rec_size; /* minimum journal space requirement for a non-TP transaction */ int4 jnl_state; /* journaling state: it can be 0, 1 or 2 (same as enum jnl_state_codes in jnl.h) */ int4 repl_state; /* state of replication whether open/closed/was_open */ uint4 crit_check_cycle; /* Used to mark which regions in a transaction legiticamtely have crit */ int4 backup_in_prog; /* true if online backup in progress for this region (used in op_tcommit/tp_tend) */ boolean_t snapshot_in_prog; /* true if snapshots are in progress for this region */ int4 ref_cnt; /* count of number of times csa->nl->ref_cnt was incremented by this process */ int4 fid_index; /* index for region ordering based on unique_id */ boolean_t do_fullblockwrites; /* This region enabled for full block writes */ int4 regnum; /* Region number (region open counter) used by journaling so all tokens have a unique prefix per region (and all regions have same prefix) */ int4 n_pre_read_trigger; /* For update process to keep track of progress and when to trigger pre-read */ uint4 jnlpool_validate_check; /* See the comment above VALIDATE_INITIALIZED_JNLPOOL for details on this field */ int4 regcnt; /* # of regions that have this as their csa */ boolean_t t_commit_crit; /* set to FALSE by default. set to TRUE if in the middle of database commit. * if access method is BG, this assumes a multi-state value. * FALSE -> T_COMMIT_CRIT_PHASE1 -> T_COMMIT_CRIT_PHASE2 -> FALSE * (bg_update_phase1) (bg_update_phase2) (finish commit) */ boolean_t wcs_pidcnt_incremented; /* set to TRUE if we incremented cnl->wcs_phase2_commit_pidcnt. * used by secshr_db_clnup to decrement the shared counter. */ boolean_t incr_db_trigger_cycle; /* set to FALSE by default. set to TRUE if trigger state change (in ^#t) occurs for * any global in this database which means an increment to csa->db_trigger_cycle and * csd->db_trigger_cycle. Currently used by MUPIP TRIGGER/$ZTRIGGER(), MUPIP RECOVER * and UPDATE PROCESS */ uint4 db_trigger_cycle; /* mirror of csd->db_trigger_cycle; used to detect concurrent ^#t global changes */ uint4 db_dztrigger_cycle; /* incremented on every $ZTRIGGER() operation. Due to the presence of $ZTRIGGER() * and ZTRIGGER command the 'd' prefix for ztrigger in db_dztrigger_cycle is used * to denote the '$' in $ZTRIGGER() */ boolean_t hold_onto_crit; /* TRUE currently for dse if a CRIT -SEIZE has been done on this region. * Set to FALSE by a DSE CRIT -RELEASE done on this region. Will also be TRUE in * case of ONLINE ROLLBACK. Any code that can be invoked by both DSE and ROLLBACK * should use csa->hold_onto_crit. */ boolean_t dse_crit_seize_done; /* TRUE if DSE does a CRIT -SEIZE for this region. Set to FALSE when CRIT -RELEASE * or CRIT -REMOVE is done. Other than the -SEIZE and -RELEASE window, if any other * DSE module sets csa->hold_onto_crit to TRUE (like dse_b_dmp) but encounters a * runtime error before getting a chance to do a rel_crit, preemptive_db_clnup * should know to release crit even if hold_onto_crit is set to TRUE and so will * rely on this variable */ # ifdef UNIX uint4 root_search_cycle; /* local copy of cnl->root_search_cycle */ uint4 onln_rlbk_cycle; /* local copy of cnl->onln_rlbk_cycle */ uint4 db_onln_rlbkd_cycle; /* local copy of cnl->db_onln_rlbkd_cycle */ boolean_t dbinit_shm_created; /* TRUE if shared memory for this region was created by this process */ # endif } sgmnt_addrs; typedef struct gd_binding_struct { unsigned char name[MAX_NM_LEN + 1]; union { gd_region *addr; int4 offset; } reg; } gd_binding; typedef struct { unsigned short offset; unsigned short match; } srch_rec_status; typedef struct srch_blk_status_struct { cache_rec_ptr_t cr; sm_uc_ptr_t buffaddr; block_id blk_num; trans_num tn; srch_rec_status prev_rec, curr_rec; int4 cycle; int4 level; struct cw_set_element_struct *cse; struct srch_blk_status_struct *first_tp_srch_status; /* In TP, this points to an entry in the si->first_tp_hist array * that contains the srch_blk_status structure of this block the * first time it was referenced in this TP transaction. So basically * gvt->hist contains pointers to the first_tp_hist array. At * tp_clean_up time, the first_tp_hist array is cleared but all * pointers to it are not cleaned up then. That instead happens * when the gvt->clue gets used first in the next TP transaction, * at which point we are guaranteed local_tn is much higher than * gvt->read_local_tn which is an indication to complete this * deferred cleanup. * In non-TP, this field is maintained but not used. */ struct gv_namehead_struct *blk_target; } srch_blk_status; /* Defines for "cycle" member in srch_blk_status. * For histories pointing to shared-memory buffers, * "cycle" will be CYCLE_SHRD_COPY in MM and some positive number in BG. * For histories pointing to privately-built blocks, * "cycle" will be CYCLE_PVT_COPY for both BG and MM. */ #define CYCLE_PVT_COPY -1 #define CYCLE_SHRD_COPY -2 typedef struct { int4 depth; int4 filler; srch_blk_status h[MAX_BT_DEPTH + 1]; } srch_hist; #define SUPER_HIST_SIZE 2 * MAX_BT_DEPTH + 2 /* can be increased in the future to accommodate more than 2 histories */ /* Currently used only by MUPIP REORG in order to pass 3 search histories to t_end. */ typedef struct { int4 depth; /* t_end's validations don't depend on this field */ int4 filler; srch_blk_status h[SUPER_HIST_SIZE]; } super_srch_hist; #define MERGE_SUPER_HIST(SUPER_HIST, HIST1, HIST2) \ { /* Possible enhancement: do memcpy instead of loop */ \ srch_hist *hist; \ srch_blk_status *t0, *t1; \ \ (SUPER_HIST)->depth = 1 + (HIST1)->depth + (HIST2)->depth; \ assert(SUPER_HIST_SIZE > (SUPER_HIST)->depth); \ t0 = (SUPER_HIST)->h; \ for (hist = (HIST1); (NULL != hist); hist = (hist == (HIST1)) ? (HIST2) : NULL) \ { \ for (t1 = hist->h; t1->blk_num; t1++) \ { \ *t0 = *t1; \ t0++; \ } \ } \ t0->blk_num = 0; \ } typedef struct gv_key_struct { unsigned short top; /* Offset to top of buffer allocated for the key */ unsigned short end; /* End of the current key. Offset to the second null */ unsigned short prev; /* Offset to the start of the previous subscript. * This is used for global nakeds. */ unsigned char base[1]; /* Base of the key */ } gv_key; /* The direction that the newly added record went after a block split at a given level */ enum split_dir { NEWREC_DIR_FORCED, /* direction forced due to one of the sides being too-full i.e. no choice */ NEWREC_DIR_LEFT, /* new record went into the end of the left block after the split */ NEWREC_DIR_RIGHT, /* new record went into the beginning of the right block after the split */ }; /* Any change to this structure should also have a corresponding [re]initialization in mupip_recover.c * in the code where we play the records in the forward phase i.e. go through each of the jnl_files * and within if (mur_options.update), initialize necessary fields of gv_target before proceeding with mur_forward(). */ typedef struct gv_namehead_struct { gv_key *first_rec, *last_rec; /* Boundary recs of clue's data block */ struct gv_namehead_struct *next_gvnh; /* Used to chain gv_target's together */ struct gv_namehead_struct *prev_gvnh; /* Used to chain gv_target's together */ struct gv_namehead_struct *next_tp_gvnh; /* Used to chain gv_targets participating in THIS TP transaction */ sgmnt_addrs *gd_csa; /* Pointer to Segment corresponding to this key */ srch_hist *alt_hist; /* alternate history. initialized once per gv_target */ struct collseq_struct *collseq; /* pointer to a linked list of user supplied routine addresses for internationalization */ trans_num read_local_tn; /* local_tn of last reference for this global */ GTMTRIG_ONLY(trans_num trig_local_tn;) /* local_tn of last trigger driven for this global */ GTMTRIG_ONLY(trans_num trig_read_tn;) /* local_tn when triggers for this global (^#t records) were read from db */ boolean_t noisolation; /* whether isolation is turned on or off for this global */ block_id root; /* Root of global variable tree */ mname_entry gvname; /* the name of the global */ NON_GTM64_ONLY(uint4 filler_8byte_align0;) /* for 8-byte alignment of "hist" member */ srch_hist hist; /* block history array */ int4 regcnt; /* number of global directories whose hash-tables point to this gv_target. * 1 by default. > 1 if the same name in TWO DIFFERENT global directories * maps to the same physical file (i.e. two regions in different global * directories have the same physical file). */ unsigned char nct; /* numerical collation type for internalization */ unsigned char act; /* alternative collation type for internalization */ unsigned char ver; bool split_cleanup_needed; char last_split_direction[MAX_BT_DEPTH - 1]; /* maintain last split direction for each level in the GVT */ char filler_8byte_align1[2]; block_id last_split_blk_num[MAX_BT_DEPTH - 1]; # ifdef GTM_TRIGGER struct gvt_trigger_struct *gvt_trigger; /* pointer to trigger info for this global * (is non-NULL only if db_trigger_cycle is non-zero) */ uint4 db_trigger_cycle; /* copy of csd->db_trigger_cycle when triggers for this global were * last read/initialized from ^#t global (in gvtr_init) */ uint4 db_dztrigger_cycle; /* copy of csa->db_dztrigger_cycle when triggers for this global were * last read/initialized from ^#t global (in gvtr_init) */ boolean_t trig_mismatch_test_done; /* whether update process has checked once if there is a mismatch * in trigger definitions between originating and replicating instance */ GTM64_ONLY(uint4 filler_8byte_align2;) /* for 8-byte alignment of "clue" member. (targ_alloc relies on this) */ # endif gv_key clue; /* Clue key, must be last in namehead struct because of hung buffer. */ } gv_namehead; typedef struct gvnh_reg_struct { gv_namehead *gvt; gd_region *gd_reg; /* Region of key */ } gvnh_reg_t; #define INVALID_GV_TARGET (gv_namehead *)-1L typedef struct gvsavtarg_struct { gd_addr *gd_targ_addr; gd_binding *gd_map; gd_region *gv_cur_region; gv_namehead *gv_target; bool gv_last_subsc_null; bool gv_some_subsc_null; short prev; short end; short filler_8byte_align; } gvsavtarg_t; #define GVSAVTARG_ALIGN_BNDRY 8 #define GVSAVTARG_FIXED_SIZE (SIZEOF(gvsavtarg_t)) /* Following three macros define the mechanism to restore gv_target under normal and error conditions. * RESET_GV_TARGET should be used to restore gv_target from the global, reset_gv_target, only when we * are sure that this function is the first one in the call stack to have saved gv_target. * If the module that needs the restoration mechanism is not the first one to save gv_target in the call * stack, then one of the last two macros should be used. * RESET_GV_TARGET_LCL is used to restore gv_target from the local variable used to save gv_target. * RESET_GV_TARGET_LCL_AND_CLR_GBL is used at the end of the module, when there are no more gv_target * restorations needed. This resets gv_target and invalidates reset_gv_target. * * This mechanism ensures that, when there are multiple functions in a given call stack that save and * restore gv_target, only the bottom most function gets to store its value in the global, reset_gv_target. * In case of rts errors, if the error is not SUCCESS or INFO, then gv_target gets restored to reset_gv_target * (in preemptive_db_clnup()). For SUCCESS or INFO, no restoration is necessary because CONTINUE from the condition * handlers would take us through the normal path for gv_target restoration. */ #define SKIP_GVT_GVKEY_CHECK 0 #define DO_GVT_GVKEY_CHECK 1 #define DO_GVT_GVKEY_CHECK_RESTART 2 /* do GVT_GVKEY check but skip gvt/csa check since we are in a TP transaction * and about to restart, gv_target and cs_addrs will anyways get back in sync * as part of the tp_restart process. This flag should be used only in TP * as non-TP restart does not do this reset/sync. */ #define RESET_GV_TARGET(GVT_GVKEY_CHECK) \ { \ assert(INVALID_GV_TARGET != reset_gv_target); \ gv_target = reset_gv_target; \ reset_gv_target = INVALID_GV_TARGET; \ DEBUG_ONLY( \ if (GVT_GVKEY_CHECK) \ DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); \ ) \ } #define RESET_GV_TARGET_LCL(SAVE_TARG) gv_target = SAVE_TARG; #define RESET_GV_TARGET_LCL_AND_CLR_GBL(SAVE_TARG, GVT_GVKEY_CHECK) \ { \ GBLREF uint4 dollar_tlevel; \ \ gv_target = SAVE_TARG; \ if (!gbl_target_was_set) \ { \ assert(SAVE_TARG == reset_gv_target || INVALID_GV_TARGET == reset_gv_target); \ DEBUG_ONLY( \ if (DO_GVT_GVKEY_CHECK == (GVT_GVKEY_CHECK)) \ { \ DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); \ } else \ { \ assert((SKIP_GVT_GVKEY_CHECK == (GVT_GVKEY_CHECK)) \ || (dollar_tlevel && (DO_GVT_GVKEY_CHECK_RESTART == (GVT_GVKEY_CHECK)))); \ DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_FALSE); \ } \ ) \ reset_gv_target = INVALID_GV_TARGET; \ } \ } /* No point doing the gvtarget-gvcurrkey in-sync check or the gvtarget-csaddrs in-sync check if we are anyways going to exit. * There is no way op_gvname (which is where these design assumptions get actually used) is going to be called from now onwards. */ GBLREF int process_exiting; GBLREF trans_num local_tn; GBLREF gv_namehead *gvt_tp_list; #define RESET_FIRST_TP_SRCH_STATUS_FALSE FALSE #define RESET_FIRST_TP_SRCH_STATUS_TRUE TRUE #define GVT_CLEAR_FIRST_TP_SRCH_STATUS(GVT) \ { \ srch_blk_status *srch_status; \ \ assert(GVT->clue.end); /* or else first_tp_srch_status will be reset as part of traversal */ \ assert(GVT->read_local_tn != local_tn); \ for (srch_status = &(GVT)->hist.h[0]; HIST_TERMINATOR != srch_status->blk_num; srch_status++) \ srch_status->first_tp_srch_status = NULL; \ } #define ADD_TO_GVT_TP_LIST(GVT, RESET_FIRST_TP_SRCH_STATUS) \ { \ if (GVT->read_local_tn != local_tn) \ { /* Set read_local_tn to local_tn; Also add GVT to list of gvtargets referenced in this TP transaction. */ \ if (GVT->clue.end && RESET_FIRST_TP_SRCH_STATUS) \ GVT_CLEAR_FIRST_TP_SRCH_STATUS(GVT); \ GVT->read_local_tn = local_tn; \ GVT->next_tp_gvnh = gvt_tp_list; \ gvt_tp_list = GVT; \ } else \ { /* Check that GVT is already part of the list of gvtargets referenced in this TP transaction */ \ DBG_CHECK_IN_GVT_TP_LIST(GVT, TRUE); /* TRUE => we check that GVT IS present in the gvt_tp_list */ \ } \ } /* Although the below macros are used only in DBG code, they are passed as parameters so need to be defined for pro code too */ #define CHECK_CSA_FALSE FALSE #define CHECK_CSA_TRUE TRUE #ifdef DEBUG #define DBG_CHECK_IN_GVT_TP_LIST(gvt, present) \ { \ gv_namehead *gvtarg; \ \ GBLREF gv_namehead *gvt_tp_list; \ GBLREF uint4 dollar_tlevel; \ \ for (gvtarg = gvt_tp_list; NULL != gvtarg; gvtarg = gvtarg->next_tp_gvnh) \ { \ if (gvtarg == gvt) \ break; \ } \ assert(!present || (NULL != gvtarg)); \ assert(present || (NULL == gvtarg) || (process_exiting && !dollar_tlevel)); \ } #define DBG_CHECK_GVT_IN_GVTARGETLIST(gvt) \ { \ gv_namehead *gvtarg; \ \ GBLREF gd_region *gv_cur_region; \ GBLREF gv_namehead *gv_target_list; \ \ for (gvtarg = gv_target_list; NULL != gvtarg; gvtarg = gvtarg->next_gvnh) \ { \ if (gvtarg == gvt) \ break; \ } \ /* For dba_cm or dba_usr type of regions, gv_target_list is not maintained so \ * if gv_target is not part of gv_target_list, assert region is not BG or MM. \ * The only exception is if the region was dba_cm but later closed due to an error on \ * the server side (in which case access method gets reset back to BG. (e.g. gvcmz_error.c) \ */ \ assert((NULL != gvtarg) || (dba_cm == gv_cur_region->dyn.addr->acc_meth) \ || (dba_usr == gv_cur_region->dyn.addr->acc_meth) \ || ((FALSE == gv_cur_region->open) && (dba_bg == gv_cur_region->dyn.addr->acc_meth))); \ } /* If CHECK_CSADDRS input parameter is CHECK_CSA_TRUE, then check that GV_CURRKEY, GV_TARGET and CS_ADDRS are all in sync. * If CHECK_CSADDRS input parameter is CHECK_CSA_FALSE, then only check GV_CURRKEY and GV_TARGET are in sync (skip CS_ADDRS check). * The hope is that most callers of this macro use CHECK_CSA_TRUE (i.e. a stricter check). * * The DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSADDRS) macro is used at various points in the database code to check that * gv_currkey, gv_target and cs_addrs are in sync. This is because op_gvname relies on this in order to avoid a gv_bind_name * function call (if incoming key matches gv_currkey from previous call, it uses gv_target and cs_addrs right * away instead of recomputing them). The only exception is if we were interrupted in the middle of TP transaction by an * external signal which resulted in us terminating right away. In this case, we are guaranteed not to make a call to op_gvname * again (because we are exiting) so it is ok not to do this check if process_exiting is TRUE. */ #define DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSADDRS) \ { \ mname_entry *gvent; \ mstr *varname; \ int varlen; \ unsigned short keyend; \ unsigned char *keybase; \ \ GBLREF int4 gv_keysize; \ \ GBLREF gv_key *gv_currkey; \ GBLREF gv_namehead *reset_gv_target; \ \ assert((NULL != gv_currkey) || (NULL == gv_target)); \ /* make sure gv_currkey->top always reflects the maximum keysize across all dbs that we opened until now */ \ assert((NULL == gv_currkey) || (gv_currkey->top == gv_keysize)); \ if (!process_exiting) \ { \ keybase = &gv_currkey->base[0]; \ if ((NULL != gv_currkey) && (0 != keybase[0]) && (INVALID_GV_TARGET == reset_gv_target)) \ { \ assert(NULL != gv_target); \ gvent = &gv_target->gvname; \ varname = &gvent->var_name; \ varlen = varname->len; \ assert(varlen); \ assert((0 != keybase[varlen]) || !memcmp(keybase, varname->addr, varlen)); \ keyend = gv_currkey->end; \ assert(!keyend || (KEY_DELIMITER == keybase[keyend])); \ assert(!keyend || (KEY_DELIMITER == keybase[keyend - 1])); \ /* Check that gv_target is part of the gv_target_list */ \ DBG_CHECK_GVT_IN_GVTARGETLIST(gv_target); \ if (CHECK_CSADDRS) \ DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC; \ } \ /* Do gv_target sanity check too; Do not do this if it is NULL or if it is GT.CM GNP client (gd_csa is NULL) */ \ if ((NULL != gv_target) && (NULL != gv_target->gd_csa)) \ DBG_CHECK_GVTARGET_INTEGRITY(gv_target); \ } \ } /* Do checks on the integrity of various fields in gv_target. targ_alloc initializes these and they are supposed to * stay that way. The following code is very similar to that in targ_alloc so needs to be maintained in sync. This * macro expects that gv_target->gd_csa is non-NULL (could be NULL for GT.CM GNP client) so any callers of this macro * should ensure they do not invoke it in case of NULL gd_csa. */ #define DBG_CHECK_GVTARGET_INTEGRITY(GVT) \ { \ int keysize, partial_size; \ GBLREF boolean_t dse_running; \ \ keysize = GVT->gd_csa->hdr->max_key_size; \ keysize = DBKEYSIZE(keysize); \ partial_size = SIZEOF(gv_namehead) + 2 * SIZEOF(gv_key) + 3 * keysize; \ /* DSE could change the max_key_size dynamically so account for it in the below assert */ \ if (!dse_running) \ { \ assert(GVT->gvname.var_name.addr == (char *)GVT + partial_size); \ assert((char *)GVT->first_rec == ((char *)&GVT->clue + SIZEOF(gv_key) + keysize)); \ assert((char *)GVT->last_rec == ((char *)GVT->first_rec + SIZEOF(gv_key) + keysize)); \ assert(GVT->clue.top == keysize); \ } \ assert(GVT->clue.top == GVT->first_rec->top); \ assert(GVT->clue.top == GVT->last_rec->top); \ } #else # define DBG_CHECK_IN_GVT_TP_LIST(gvt, present) # define DBG_CHECK_GVT_IN_GVTARGETLIST(gvt) # define DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSADDRS) # define DBG_CHECK_GVTARGET_INTEGRITY(GVT) #endif /* The below GBLREFs are for the following macro */ GBLREF gv_namehead *gv_target; GBLREF sgmnt_addrs *cs_addrs; #define DBG_CHECK_GVTARGET_CSADDRS_IN_SYNC assert(process_exiting || (NULL == gv_target) || (gv_target->gd_csa == cs_addrs)) /* Indicate incompleteness of (potentially subscripted) global name by adding a "*" (without closing ")") at the end */ #define GV_SET_LAST_SUBSCRIPT_INCOMPLETE(BUFF, END) \ { \ if (NULL == (char *)(END)) \ { /* The buffer passed to format_targ_key was not enough \ * for the transformation. We don't expect this. Handle \ * it nevertheless by adding ",*" at end. \ */ \ assert(FALSE); \ END = ((unsigned char *)ARRAYTOP(BUFF)) - 1; \ assert((char *)(END) > (char *)(BUFF)); \ *(END)++ = '*'; \ } else \ { /* Overflow occurred while adding the global name OR \ * after adding the last subscript OR in the middle of \ * adding a subscript (not necessarily last). In all \ * cases, add a '*' at end to indicate incompleteness. \ */ \ if (')' == END[-1]) \ (END)--; \ /* ensure we have space to write 1 byte */ \ assert((char *)(END) + 1 <= ((char *)ARRAYTOP(BUFF))); \ *(END)++ = '*'; \ } \ } #define ISSUE_GVSUBOFLOW_ERROR(GVKEY) \ { \ unsigned char *endBuff, fmtBuff[MAX_ZWR_KEY_SZ]; \ \ /* Assert that input key to format_targ_key is double null terminated */ \ assert(KEY_DELIMITER == GVKEY->base[GVKEY->end]); \ endBuff = format_targ_key(fmtBuff, ARRAYSIZE(fmtBuff), GVKEY, TRUE); \ GV_SET_LAST_SUBSCRIPT_INCOMPLETE(fmtBuff, endBuff); /* Note: might update "endBuff" */ \ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GVSUBOFLOW, 0, ERR_GVIS, 2, \ endBuff - fmtBuff, fmtBuff); \ } #define COPY_SUBS_TO_GVCURRKEY(mvarg, max_key, gv_currkey, was_null, is_null) \ { \ GBLREF mv_stent *mv_chain; \ GBLREF unsigned char *msp, *stackwarn, *stacktop; \ mval temp; \ unsigned char buff[MAX_ZWR_KEY_SZ], *end; \ int len; \ \ was_null |= is_null; \ if (mvarg->mvtype & MV_SUBLIT) \ { \ is_null = ((STR_SUB_PREFIX == *(unsigned char *)mvarg->str.addr) \ && (KEY_DELIMITER == *(mvarg->str.addr + 1))); \ if (gv_target->collseq || gv_target->nct) \ { \ /* collation transformation should be done at the server's end for CM regions */ \ assert(dba_cm != gv_cur_region->dyn.addr->acc_meth); \ TREF(transform) = FALSE; \ end = gvsub2str((uchar_ptr_t)mvarg->str.addr, buff, FALSE); \ TREF(transform) = TRUE; \ temp.mvtype = MV_STR; \ temp.str.addr = (char *)buff; \ temp.str.len = (mstr_len_t)(end - buff); \ mval2subsc(&temp, gv_currkey); \ } else \ { \ len = mvarg->str.len; \ if (gv_currkey->end + len - 1 >= max_key) \ ISSUE_GVSUBOFLOW_ERROR(gv_currkey); \ memcpy((gv_currkey->base + gv_currkey->end), mvarg->str.addr, len); \ if (is_null && 0 != gv_cur_region->std_null_coll) \ gv_currkey->base[gv_currkey->end] = SUBSCRIPT_STDCOL_NULL; \ gv_currkey->prev = gv_currkey->end; \ gv_currkey->end += len - 1; \ } \ } else \ { \ MV_FORCE_DEFINED(mvarg); \ mval2subsc(mvarg, gv_currkey); \ if (gv_currkey->end >= max_key) \ ISSUE_GVSUBOFLOW_ERROR(gv_currkey); \ is_null = (MV_IS_STRING(mvarg) && (0 == mvarg->str.len)); \ } \ } /* Copy GVKEY to GVT->CLUE. Take care NOT to copy cluekey->top to GVKEY->top as they correspond * to the allocation sizes of two different memory locations and should stay untouched. */ #define COPY_CURRKEY_TO_GVTARGET_CLUE(GVT, GVKEY) \ { \ gv_key *cluekey; \ \ if (GVT->clue.top <= GVKEY->end) \ GTMASSERT; \ assert(KEY_DELIMITER == GVKEY->base[GVKEY->end]); \ assert(KEY_DELIMITER == GVKEY->base[GVKEY->end - 1]); \ cluekey = &GVT->clue; \ memcpy(cluekey->base, GVKEY->base, GVKEY->end + 1); \ cluekey->end = GVKEY->end; \ cluekey->prev = GVKEY->prev; \ DBG_CHECK_GVTARGET_INTEGRITY(GVT); \ } /* If SRC_KEY->end == 0, make sure to copy the first byte of SRC_KEY->base */ #define MEMCPY_KEY(TARG_KEY, SRC_KEY) \ { \ memcpy((TARG_KEY), (SRC_KEY), OFFSETOF(gv_key, base[0]) + (SRC_KEY)->end + 1); \ } #define COPY_KEY(TARG_KEY, SRC_KEY) \ { \ assert(TARG_KEY->top >= SRC_KEY->end); \ /* ensure proper alignment before dereferencing SRC_KEY->end */ \ assert(0 == (((UINTPTR_T)(SRC_KEY)) % SIZEOF(SRC_KEY->end))); \ /* WARNING: depends on the first two bytes of gv_key structure being key top field */ \ assert((2 == SIZEOF(TARG_KEY->top)) && ((sm_uc_ptr_t)(TARG_KEY) == (sm_uc_ptr_t)(&TARG_KEY->top))); \ memcpy(((sm_uc_ptr_t)(TARG_KEY) + 2), ((sm_uc_ptr_t)(SRC_KEY) + 2), OFFSETOF(gv_key, base[0]) + (SRC_KEY)->end - 1); \ } /* Macro to denote special value of first_rec when it is no longer reliable */ #define GVT_CLUE_FIRST_REC_UNRELIABLE (short)0xffff /* Macro to denote special value of last_rec when it is the absolute maximum (in case of *-keys all the way down) */ #define GVT_CLUE_LAST_REC_MAXKEY (short)0xffff /* Macro to reset first_rec to a special value to indicate it is no longer reliable * (i.e. the keyrange [first_rec, clue] should not be used by gvcst_search. * Note that [clue, last_rec] is still a valid keyrange and can be used by gvcst_search. */ #define GVT_CLUE_INVALIDATE_FIRST_REC(GVT) \ { \ assert(GVT->clue.end); \ *((short *)GVT->first_rec->base) = GVT_CLUE_FIRST_REC_UNRELIABLE; \ } #ifdef DEBUG /* Macro to check that the clue is valid. Basically check that first_rec <= clue <= last_rec. Also check that * all of them start with the same global name in case of a GVT. A clue that does not satisfy these validity * checks implies the possibility of DBKEYORD errors (e.g. C9905-001119 in VMS). */ #define DEBUG_GVT_CLUE_VALIDATE(GVT) \ { \ mname_entry *gvent; \ unsigned short klen; \ gv_namehead *gvt; \ \ /* Verify that clue->first_rec <= clue.base <= clue->last_rec. \ * The only exception is if first_rec has been reset to an unreliable value. \ */ \ gvt = GVT; /* copy into local variable to avoid evaluating input multiple times */ \ klen = MIN(gvt->clue.end, gvt->first_rec->end); \ assert(klen); \ assert((0 <= memcmp(gvt->clue.base, gvt->first_rec->base, klen)) \ || (GVT_CLUE_FIRST_REC_UNRELIABLE == *((short *)gvt->first_rec->base))); \ klen = MIN(gvt->clue.end, gvt->last_rec->end); \ assert(klen); \ assert(0 <= memcmp(gvt->last_rec->base, gvt->clue.base, klen)); \ if (DIR_ROOT != gvt->root) \ { /* Not a directory tree => a GVT tree, check that first_rec/last_rec have at least gvname in it */ \ gvent = &gvt->gvname; \ if (GVT_CLUE_FIRST_REC_UNRELIABLE != *((short *)gvt->first_rec->base)) \ { \ assert((0 == memcmp(gvent->var_name.addr, gvt->first_rec->base, gvent->var_name.len)) \ && (KEY_DELIMITER == gvt->first_rec->base[gvent->var_name.len])); \ } \ if (GVT_CLUE_LAST_REC_MAXKEY != *((short *)gvt->last_rec->base)) \ { \ assert((0 == memcmp(gvent->var_name.addr, gvt->last_rec->base, gvent->var_name.len)) \ && (KEY_DELIMITER == gvt->last_rec->base[gvent->var_name.len])); \ } \ } \ } #else #define DEBUG_GVT_CLUE_VALIDATE(GVT) #endif /* Macro used by $ZPREVIOUS to replace a NULL subscript at the end with the maximum possible subscript * that could exist in the database for this global name. */ #define GVZPREVIOUS_APPEND_MAX_SUBS_KEY(GVKEY, GVT) \ { \ int lastsubslen, keysize; \ unsigned char *ptr; \ \ assert(GVT->clue.top || (NULL == GVT->gd_csa)); \ assert(!GVT->clue.top || (NULL != GVT->gd_csa) && (GVT->gd_csa == cs_addrs)); \ /* keysize can be obtained from GVT->clue.top in case of GT.M. \ * But for GT.CM client, clue will be uninitialized. So we would need to \ * compute keysize from gv_cur_region->max_key_size. Since this is true for \ * GT.M as well, we use the same approach for both to avoid an if check and a \ * break in the pipeline. \ */ \ keysize = DBKEYSIZE(gv_cur_region->max_key_size); \ assert(!GVT->clue.top || (keysize == GVT->clue.top)); \ lastsubslen = keysize - GVKEY->prev - 2; \ if ((0 < lastsubslen) && (GVKEY->top >= keysize) && (GVKEY->end > GVKEY->prev)) \ { \ ptr = &GVKEY->base[GVKEY->prev]; \ memset(ptr, STR_SUB_MAXVAL, lastsubslen); \ ptr += lastsubslen; \ *ptr++ = KEY_DELIMITER; /* terminator for last subscript */ \ *ptr = KEY_DELIMITER; /* terminator for entire key */ \ GVKEY->end = GVKEY->prev + lastsubslen + 1; \ assert(GVKEY->end == (ptr - &GVKEY->base[0])); \ } else \ GTMASSERT; \ if (NULL != gv_target->gd_csa) \ DBG_CHECK_GVTARGET_INTEGRITY(GVT); \ } /* Bit masks for the update_trans & si->update_trans variables */ #define UPDTRNS_DB_UPDATED_MASK (1 << 0) /* 1 if this region was updated by this non-TP/TP transaction */ #define UPDTRNS_JNL_LOGICAL_MASK (1 << 1) /* 1 if logical jnl record was written in this region's * journal file by this TP transaction. Maintained only for TP. */ #define UPDTRNS_JNL_REPLICATED_MASK (1 << 2) /* 1 if there is at least one logical jnl record written in this * region's journal file by this TP transaction that needs to be * replicated across. 0 if all updates done to this region was * inside of a trigger. Maintained only for TP. */ #define UPDTRNS_TCOMMIT_STARTED_MASK (1 << 3) /* 1 if non-TP or TP transaction is beyond the point of rolling * back by "t_commit_cleanup" and can only be rolled forward by * "secshr_db_clnup". */ #define UPDTRNS_ZTRIGGER_MASK (1 << 4) /* 1 if ZTRIGGER command was done in this transaction. This allows * the transaction to be committed even if it had no updates. * Maintained only for TP. */ #define UPDTRNS_VALID_MASK (UPDTRNS_DB_UPDATED_MASK | UPDTRNS_JNL_LOGICAL_MASK \ | UPDTRNS_JNL_REPLICATED_MASK | UPDTRNS_TCOMMIT_STARTED_MASK \ | UPDTRNS_ZTRIGGER_MASK) /* The enum codes below correspond to code-paths that can increment the database curr_tn * without having a logical update. Journaling currently needs to know all such code-paths */ typedef enum { inctn_invalid_op = 0, /* 0 : */ /* the following opcodes do NOT populate the global variable "inctn_detail" */ inctn_gvcstput_extra_blk_split, /* 1 : */ inctn_mu_reorg, /* 2 : */ inctn_wcs_recover, /* 3 : */ /* the following opcodes populate "inctn_detail.blks2upgrd_struct" */ inctn_gdsfilext_gtm, /* 4 : */ inctn_gdsfilext_mu_reorg, /* 5 : */ inctn_db_format_change, /* 6 : written when cs_data->desired_db_format changes */ /* the following opcodes populate "inctn_detail.blknum_struct" */ inctn_bmp_mark_free_gtm, /* 7 : */ inctn_bmp_mark_free_mu_reorg, /* 8 : */ inctn_blkmarkfree, /* 9 : a RECYCLED block being marked free by MUPIP REORG UPGRADE/DOWNGRADE */ inctn_blkupgrd, /* 10 : written whenever a GDS block is upgraded by MUPIP REORG UPGRADE if * a) SAFEJNL is specified OR * b) NOSAFEJNL is specified and the block is not undergoing a fmt change */ inctn_blkupgrd_fmtchng, /* 11 : written whenever a GDS block is upgraded by MUPIP REORG UPGRADE -NOSAFEJNL * and if that block is undergoing a fmt change i.e. (V4 -> V5) OR (V5 -> V4). * This differentiation (inctn_blkupgrd vs inctn_blkupgrd_fmtch) is necessary * because in the latter case we will not be writing a PBLK record and hence * have no record otherwise of a block fmt change if it occurs (note that a * PBLK journal record's "ondsk_blkver" field normally helps recovery * determine if a fmt change occurred or not). */ inctn_blkdwngrd, /* 12 : similar to inctn_blkupgrd except that this is for DOWNGRADE */ inctn_blkdwngrd_fmtchng, /* 13 : similar to inctn_blkupgrd_fmtchng except that this is for DOWNGRADE */ /* the following opcodes do NOT populate the global variable "inctn_detail" */ inctn_opcode_total /* 15 : MAX. All additions of inctn opcodes should be done BEFORE this line */ } inctn_opcode_t; /* macros to check curr_tn */ #define MAX_TN_V4 ((trans_num)(MAXUINT4 - TN_HEADROOM_V4)) #define MAX_TN_V6 (MAXUINT8 - TN_HEADROOM_V6) #define TN_HEADROOM_V4 (2 * MAXTOTALBLKS_V4) #define TN_HEADROOM_V6 (2 * MAXTOTALBLKS_V6) #define HEADROOM_FACTOR 4 /* the following macro checks that curr_tn < max_tn_warn <= max_tn. * if not, it adjusts max_tn_warn accordingly to ensure the above. * if not possible, it issues TNTOOLARGE error. */ #define CHECK_TN(CSA, CSD, TN) \ { \ assert((CSA)->hdr == (CSD)); \ assert((TN) <= (CSD)->max_tn_warn); \ assert((CSD)->max_tn_warn <= (CSD)->max_tn); \ assert((CSA)->now_crit); /* Must be crit to mess with stuff */ \ if ((TN) >= (CSD)->max_tn_warn) \ { \ trans_num trans_left; \ \ if ((CSA)->hdr->max_tn <= (TN)) \ { \ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(5) ERR_TNTOOLARGE, 3, DB_LEN_STR((CSA)->region), \ &(CSA)->hdr->max_tn); \ assert(FALSE); /* should not come here */ \ } \ assert((CSD)->max_tn > (TN)); \ trans_left = (CSD)->max_tn - (TN); \ send_msg_csa(CSA_ARG(CSA) VARLSTCNT(6) ERR_TNWARN, 4, DB_LEN_STR((CSA)->region), &trans_left, \ &(CSD)->max_tn); \ (CSD)->max_tn_warn = (TN) + 1 + ((trans_left - 1) >> 1); \ assert((TN) < (CSD)->max_tn_warn); \ assert((CSD)->max_tn_warn <= (CSD)->max_tn); \ } \ } #define INCREMENT_CURR_TN(CSD) \ { \ assert((CSD)->trans_hist.curr_tn < (CSD)->max_tn_warn); \ assert((CSD)->max_tn_warn <= (CSD)->max_tn); \ (CSD)->trans_hist.curr_tn++; \ assert((CSD)->trans_hist.curr_tn == (CSD)->trans_hist.early_tn); \ } #define SET_TN_WARN(CSD, ret_warn_tn) \ { \ trans_num headroom; \ \ headroom = (gtm_uint64_t)(GDSV4 == (CSD)->desired_db_format ? TN_HEADROOM_V4 : TN_HEADROOM_V6); \ headroom *= HEADROOM_FACTOR; \ (ret_warn_tn) = (CSD)->trans_hist.curr_tn; \ if ((headroom < (CSD)->max_tn) && ((ret_warn_tn) < ((CSD)->max_tn - headroom))) \ (ret_warn_tn) = (CSD)->max_tn - headroom; \ assert((CSD)->trans_hist.curr_tn <= (ret_warn_tn)); \ assert((ret_warn_tn) <= (CSD)->max_tn); \ } #define HIST_TERMINATOR 0 #define HIST_SIZE(h) ( (SIZEOF(int4) * 2) + (SIZEOF(srch_blk_status) * ((h).depth + 1)) ) /* Start of lock space in a bg file, therefore also doubles as overhead size for header, bt and wc queues F = # of wc blocks */ #define LOCK_BLOCK(X) (DIVIDE_ROUND_UP(SIZEOF_FILE_HDR(X) + BT_SIZE(X), DISK_BLOCK_SIZE)) #define LOCK_BLOCK_SIZE(X) (DIVIDE_ROUND_UP(SIZEOF_FILE_HDR(X) + BT_SIZE(X), OS_PAGE_SIZE)) #define LOCK_SPACE_SIZE(X) (ROUND_UP2(((sgmnt_data_ptr_t)X)->lock_space_size, OS_PAGE_SIZE)) /* In case of an encrypted database, we maintain both encrypted and decrypted versions of the block in shared memory * in parallel arrays of global buffers hence the doubling calculation below. Although this doubles the shared memory * size requirements for encrypted databases (when compared to the same unencrypted database), it helps in other ways. * By ensuring that this encrypted global buffer array contents are identical to the encrypted on-disk block contents * of database blocks at all times, we can avoid allocating process private memory to store encrypted before-images * (to write to a journal file). Instead processes can use the encrypted global buffer directly for this purpose. * In user environments where process-private memory is very costly compared to database shared memory (e.g. where * 1000s of GT.M processes run against the same database) the above approach is expected to use lesser total memory. */ #define CACHE_CONTROL_SIZE(X) \ (ROUND_UP((ROUND_UP((X->bt_buckets + X->n_bts) * SIZEOF(cache_rec) + SIZEOF(cache_que_heads), OS_PAGE_SIZE) \ + ((gtm_uint64_t)X->n_bts * X->blk_size * (X->is_encrypted ? 2 : 1))), OS_PAGE_SIZE)) OS_PAGE_SIZE_DECLARE #ifdef VMS #define MAX_NAME_LEN 31 /* Size of a repl resource name on vvms */ #endif /* structure to identify a given system wide shared section to be ours (replic section) */ typedef struct { unsigned char label[GDS_LABEL_SZ]; char pool_type; char now_running[MAX_REL_NAME]; #ifdef VMS char repl_pool_key[MAX_NAME_LEN + 1]; /* resource name for the section */ char filler[7]; /* makes sure the size of the structure is a multiple of 8 */ char gtmgbldir[MAX_FN_LEN + 1]; /* Identify which instance of this shared pool corresponds to */ #else int4 repl_pool_key_filler; /* makes sure the size of the structure is a multiple of 8 */ char instfilename[MAX_FN_LEN + 1]; /* Identify which instance file this shared pool corresponds to */ #endif } replpool_identifier; #if defined(__osf__) && defined(__alpha) # pragma pointer_size(save) # pragma pointer_size(long) #endif typedef replpool_identifier *replpool_id_ptr_t; #if defined(__osf__) && defined(__alpha) # pragma pointer_size(restore) #endif /* Macro to increment the count of processes that are doing two phase commit. * This is invoked just BEFORE starting phase1 of the commit. */ #define INCR_WCS_PHASE2_COMMIT_PIDCNT(csa, cnl) \ { \ assert(!csa->wcs_pidcnt_incremented); \ INCR_CNT(&cnl->wcs_phase2_commit_pidcnt, &cnl->wc_var_lock); \ csa->wcs_pidcnt_incremented = TRUE; \ } /* Macro to decrement the count of processes that are doing two phase commit. * This is invoked just AFTER finishing phase2 of the commit. */ #define DECR_WCS_PHASE2_COMMIT_PIDCNT(csa, cnl) \ { \ assert(csa->wcs_pidcnt_incremented); \ csa->wcs_pidcnt_incremented = FALSE; \ DECR_CNT(&cnl->wcs_phase2_commit_pidcnt, &cnl->wc_var_lock); \ } /* The CAREFUL_DECR_WCS_PHASE2_COMMIT_PIDCNT macro is the same as the DECR_WCS_PHASE2_COMMIT_PIDCNT macro * except that it uses CAREFUL_DECR_CNT instead of DECR_CNT. This does alignment checks and is needed by * secshr_db_clnup as it runs in kernel mode in VMS. The two macros should be maintained in parallel. */ #define CAREFUL_DECR_WCS_PHASE2_COMMIT_PIDCNT(csa, cnl) \ { \ assert(csa->wcs_pidcnt_incremented); \ csa->wcs_pidcnt_incremented = FALSE; \ CAREFUL_DECR_CNT(&cnl->wcs_phase2_commit_pidcnt, &cnl->wc_var_lock); \ } #ifdef UNIX /* Insert the process_id into the list of process ids actively doing a kill */ #define INSERT_KIP_PID(local_csa) \ { \ int idx; \ uint4 pid; \ pid_t *kip_pid_arr_ptr; \ GBLREF uint4 process_id; \ \ kip_pid_arr_ptr = local_csa->nl->kip_pid_array; \ assert(local_csa->now_crit); \ for (idx = 0; idx < MAX_KIP_PID_SLOTS; idx++) \ { \ pid = kip_pid_arr_ptr[idx]; \ if ((0 == pid) || (process_id == pid)) \ { \ kip_pid_arr_ptr[idx] = process_id; \ break; \ } \ } \ } /* Remove the process_id from the list of process ids actively doing a kill */ #define REMOVE_KIP_PID(local_csa) \ { \ int idx; \ pid_t *kip_pid_arr_ptr; \ GBLREF uint4 process_id; \ \ kip_pid_arr_ptr = local_csa->nl->kip_pid_array; \ for (idx = 0; idx < MAX_KIP_PID_SLOTS; idx++) \ { \ if (process_id == kip_pid_arr_ptr[idx]) \ { \ kip_pid_arr_ptr[idx] = 0; \ break; \ } \ } \ } #else #define INSERT_KIP_PID(local_csa) #define REMOVE_KIP_PID(local_csa) #endif #define DECR_KIP(CSD, CSA, KIP_CSA) \ { \ sgmnt_data_ptr_t local_csd; \ sgmnt_addrs *local_csa; \ \ /* Instead of using CSA and CSD directly in DECR_CNT, assign it to \ * local variables as the caller can potentially pass the global \ * kip_csa as the second argument(which also happens to be the \ * the third argument which will be reset to NULL below) thereby \ * leading to SEG faults in the calls to DECR_CNT. Similar \ * modifications are in INCR_KIP and their CAREFUL counterparts */ \ local_csd = CSD; \ local_csa = CSA; \ assert(NULL != KIP_CSA); \ KIP_CSA = NULL; \ DECR_CNT(&local_csd->kill_in_prog, &local_csa->nl->wc_var_lock); \ REMOVE_KIP_PID(local_csa); \ } /* Note that the INCR_KIP and CAREFUL_INCR_KIP macros should be maintained in parallel */ #define INCR_KIP(CSD, CSA, KIP_CSA) \ { \ sgmnt_data_ptr_t local_csd; \ sgmnt_addrs *local_csa; \ \ local_csd = CSD; \ local_csa = CSA; \ assert(NULL == KIP_CSA); \ INCR_CNT(&local_csd->kill_in_prog, &local_csa->nl->wc_var_lock); \ INSERT_KIP_PID(local_csa); \ KIP_CSA = CSA; \ } /* The CAREFUL_INCR_KIP macro is the same as the INCR_KIP macro except that it uses CAREFUL_INCR_CNT instead of INCR_CNT. * This does alignment checks and is needed by secshr_db_clnup as it runs in kernel mode in VMS. * The INCR_KIP and CAREFUL_INCR_KIP macros should be maintained in parallel. */ #define CAREFUL_INCR_KIP(CSD, CSA, KIP_CSA) \ { \ sgmnt_data_ptr_t local_csd; \ sgmnt_addrs *local_csa; \ \ local_csd = CSD; \ local_csa = CSA; \ assert(NULL == KIP_CSA); \ CAREFUL_INCR_CNT(&local_csd->kill_in_prog, &local_csa->nl->wc_var_lock); \ INSERT_KIP_PID(local_csa); \ KIP_CSA = CSA; \ } #define CAREFUL_DECR_KIP(CSD, CSA, KIP_CSA) \ { \ sgmnt_data_ptr_t local_csd; \ sgmnt_addrs *local_csa; \ \ local_csd = CSD; \ local_csa = CSA; \ assert(NULL != KIP_CSA); \ KIP_CSA = NULL; \ CAREFUL_DECR_CNT(&local_csd->kill_in_prog, &local_csa->nl->wc_var_lock); \ REMOVE_KIP_PID(local_csa); \ } /* Since abandoned_kills counter is only incremented in secshr_db_clnup it does not have its equivalent DECR_ABANDONED_KILLS */ #define CAREFUL_INCR_ABANDONED_KILLS(CSD, CSA) \ { \ CAREFUL_INCR_CNT(&CSD->abandoned_kills, &CSA->nl->wc_var_lock); \ } #define INCR_INHIBIT_KILLS(CNL) \ { \ INCR_CNT(&CNL->inhibit_kills, &CNL->wc_var_lock); \ } #define DECR_INHIBIT_KILLS(CNL) \ { \ if (0 < CNL->inhibit_kills) \ DECR_CNT(&CNL->inhibit_kills, &CNL->wc_var_lock); \ } /* Commands like MUPIP BACKUP, MUPIP INTEG -REG or MUPIP FREEZE wait for kills-in-prog flag to become zero. * While these process wait for ongoing block-freeing KILLs (or reorg actions that free up blocks) to complete, * new block-freeing KILLs (or reorg actions that free up blocks) are deferred using inhibit_kills counter. * New block-freeing KILLs/REORG will wait for a maximum period of 1 minute until inhibit_kills counter is 0. * In case of timeout, they will proceed after resetting the inhibit_kills to 0. The reset is done in case * the inhibit_kills was orphaned (i.e. the process that set it got killed before it got a chance to reset). */ #define WAIT_ON_INHIBIT_KILLS(CNL, MAXKILLINHIBITWAIT) \ { \ int4 sleep_counter; \ \ GBLREF boolean_t need_kip_incr; \ GBLREF uint4 dollar_tlevel; \ \ assert(dollar_tlevel || need_kip_incr); \ for (sleep_counter = 1; (0 < CNL->inhibit_kills); ++sleep_counter) \ { \ if (MAXKILLINHIBITWAIT <= sleep_counter) \ { \ CNL->inhibit_kills = 0; \ SHM_WRITE_MEMORY_BARRIER; \ break; \ } \ wcs_sleep(sleep_counter); \ } \ } /* Wait for a region freeze to be turned off. Note that we dont hold CRIT at this point. Ideally we would have * READ memory barriers between each iterations of sleep to try and get the latest value of the "freeze" field from * the concurrently updated database shared memory. But since region-freeze is a perceivably rare event, we choose * not to do the memory barriers. The consequence of this decision is that it might take more iterations for us to * see updates to the "freeze" field than it would have if we did the memory barrier each iteration. But since we * dont hold crit at this point AND since freeze is a rare event, we dont mind the extra wait. */ #define MAXHARDCRITS 31 #define WAIT_FOR_REGION_TO_UNFREEZE(CSA, CSD) \ { \ int lcnt1; \ \ assert(CSA->hdr == CSD); \ assert(!CSA->now_crit); \ for (lcnt1 = 1; ; lcnt1++) \ { \ if (!CSD->freeze) \ break; \ if (MAXHARDCRITS < lcnt1) \ wcs_backoff(lcnt1); \ } \ } #define GRAB_UNFROZEN_CRIT(reg, csa, csd) \ { \ int lcnt; \ \ assert(&FILE_INFO(reg)->s_addrs == csa && csa->hdr == csd); \ assert(csa->now_crit); \ for (lcnt = 0; ; lcnt++) \ { \ if (!csd->freeze) \ break; \ rel_crit(reg); \ WAIT_FOR_REGION_TO_UNFREEZE(csa, csd); \ grab_crit(reg); \ } \ assert(!csd->freeze && csa->now_crit); \ } /* remove "csa" from list of open regions (cs_addrs_list) */ #define REMOVE_CSA_FROM_CSADDRSLIST(CSA) \ { \ GBLREF sgmnt_addrs *cs_addrs_list; \ \ sgmnt_addrs *tmpcsa, *prevcsa; \ \ assert(NULL != CSA); \ assert(NULL == CSA->nl); \ prevcsa = NULL; \ for (tmpcsa = cs_addrs_list; NULL != tmpcsa; tmpcsa = tmpcsa->next_csa) \ { \ if (CSA == tmpcsa) \ break; \ prevcsa = tmpcsa; \ } \ /* tmpcsa could not be equal to CSA in case CSA was never added to this list \ * (possible in case of errors during gvcst_init). In dbg, the only case we \ * know of this is if an external signal causes exit processing before db_init \ * completes. Assert accordingly. \ */ \ assert((tmpcsa == CSA) || process_exiting); \ if (tmpcsa == CSA) \ { \ if (NULL != prevcsa) \ prevcsa->next_csa = CSA->next_csa; \ else \ cs_addrs_list = CSA->next_csa; \ } \ } #define INVALID_SEMID -1 #define INVALID_SHMID -1L #ifdef VMS #define NEW_DBINIT_SHM_IPC_MASK (1 << 0) /* 1 if db_init created a new shared memory (no pre-existing one) */ #define NEW_DBINIT_SEM_IPC_MASK (1 << 1) /* 1 if db_init created a new access control semaphore */ #endif #define RESET_SHMID_CTIME(X) \ { \ (X)->shmid = INVALID_SHMID; \ (X)->gt_shm_ctime.ctime = 0; \ } #define RESET_SEMID_CTIME(X) \ { \ (X)->semid = INVALID_SEMID; \ (X)->gt_sem_ctime.ctime = 0; \ } #define RESET_IPC_FIELDS(X) \ { \ RESET_SHMID_CTIME(X); \ RESET_SEMID_CTIME(X); \ } #if defined(UNIX) #define DB_FSYNC(reg, udi, csa, db_fsync_in_prog, save_errno) \ { \ int rc; \ \ BG_TRACE_PRO_ANY(csa, n_db_fsyncs); \ if (csa->now_crit) \ BG_TRACE_PRO_ANY(csa, n_db_fsyncs_in_crit); \ db_fsync_in_prog++; \ save_errno = 0; \ GTM_DB_FSYNC(csa, udi->fd, rc); \ if (-1 == rc) \ save_errno = errno; \ db_fsync_in_prog--; \ assert(0 <= db_fsync_in_prog); \ } #define STANDALONE(x) mu_rndwn_file(x, TRUE) #define DBFILOP_FAIL_MSG(status, msg) gtm_putmsg_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(5) msg, 2, \ DB_LEN_STR(gv_cur_region), status); #elif defined(VMS) #define STANDALONE(x) mu_rndwn_file(TRUE) /* gv_cur_region needs to be equal to "x" */ #define DBFILOP_FAIL_MSG(status, msg) gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) msg, 2, DB_LEN_STR(gv_cur_region), status, \ FILE_INFO(gv_cur_region)->fab->fab$l_stv); #else #error unsupported platform #endif #define CR_NOT_ALIGNED(cr, cr_base) (!IS_PTR_ALIGNED((cr), (cr_base), SIZEOF(cache_rec))) #define CR_NOT_IN_RANGE(cr, cr_lo, cr_hi) (!IS_PTR_IN_RANGE((cr), (cr_lo), (cr_hi))) /* Examine that cr->buffaddr is indeed what it should be. If not, this macro fixes its value by * recomputing from the cache_array. * NOTE: We rely on bt_buckets, n_bts and blk_size fields of file header being correct/not corrupt */ #define CR_BUFFER_CHECK(reg, csa, csd, cr) \ { \ cache_rec_ptr_t cr_lo, cr_hi; \ \ cr_lo = (cache_rec_ptr_t)csa->acc_meth.bg.cache_state->cache_array + csd->bt_buckets; \ cr_hi = cr_lo + csd->n_bts; \ CR_BUFFER_CHECK1(reg, csa, csd, cr, cr_lo, cr_hi); \ } /* A more efficient macro than CR_BUFFER_CHECK when we have cr_lo and cr_hi already available */ #define CR_BUFFER_CHECK1(reg, csa, csd, cr, cr_lo, cr_hi) \ { \ INTPTR_T bp, bp_lo, bp_top, cr_top; \ \ cr_top = GDS_ANY_ABS2REL(csa, cr_hi); \ bp_lo = ROUND_UP(cr_top, OS_PAGE_SIZE); \ bp = bp_lo + ((cr) - (cr_lo)) * csd->blk_size; \ if (bp != cr->buffaddr) \ { \ send_msg_csa(CSA_ARG(csa) VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), \ cr, cr->blk, RTS_ERROR_TEXT("cr->buffaddr"), \ cr->buffaddr, bp, CALLFROM); \ cr->buffaddr = bp; \ } \ DEBUG_ONLY(bp_top = bp_lo + (gtm_uint64_t)csd->n_bts * csd->blk_size;) \ assert(IS_PTR_IN_RANGE(bp, bp_lo, bp_top) && IS_PTR_ALIGNED(bp, bp_lo, csd->blk_size)); \ } #define DB_INFO UNIX_ONLY(unix_db_info)VMS_ONLY(vms_gds_info) #define FILE_CNTL_INIT_IF_NULL(SEG) \ { \ file_control *lcl_fc; \ \ lcl_fc = SEG->file_cntl; \ if (NULL == lcl_fc) \ { \ MALLOC_INIT(lcl_fc, SIZEOF(file_control)); \ SEG->file_cntl = lcl_fc; \ } \ if (NULL == lcl_fc->file_info) \ { \ MALLOC_INIT(lcl_fc->file_info, SIZEOF(DB_INFO)); \ SEG->file_cntl->file_info = lcl_fc->file_info; \ } \ } #define FILE_CNTL_INIT(SEG) \ { \ file_control *lcl_fc; \ \ MALLOC_INIT(lcl_fc, SIZEOF(file_control)); \ MALLOC_INIT(lcl_fc->file_info, SIZEOF(DB_INFO)); \ SEG->file_cntl = lcl_fc; \ } #define IS_DOLLAR_INCREMENT ((is_dollar_incr) && (ERR_GVPUTFAIL == t_err)) #define AVG_BLKS_PER_100_GBL 200 #define PRE_READ_TRIGGER_FACTOR 50 #define UPD_RESERVED_AREA 50 #define UPD_WRITER_TRIGGER_FACTOR 33 #define ONLY_SS_BEFORE_IMAGES(CSA) (CSA->snapshot_in_prog && !CSA->backup_in_prog && !(JNL_ENABLED(CSA) && CSA->jnl_before_image)) #define SET_SNAPSHOTS_IN_PROG(X) ((X)->snapshot_in_prog = TRUE) #define CLEAR_SNAPSHOTS_IN_PROG(X) ((X)->snapshot_in_prog = FALSE) #ifdef GTM_SNAPSHOT # define SNAPSHOTS_IN_PROG(X) ((X)->snapshot_in_prog) /* Creates a new snapshot context. Called by GT.M (or utilities like update process, MUPIP LOAD which uses * GT.M runtime. As a side effect sets csa->snapshot_in_prog to TRUE if the context creation went fine. */ # define SS_INIT_IF_NEEDED(CSA, CNL) \ { \ int ss_shmcycle; \ boolean_t status; \ snapshot_context_ptr_t lcl_ss_ctx; \ \ lcl_ss_ctx = SS_CTX_CAST(CSA->ss_ctx); \ assert(NULL != lcl_ss_ctx); \ CNL->fastinteg_in_prog ? SET_FAST_INTEG(lcl_ss_ctx) : SET_NORM_INTEG(lcl_ss_ctx); \ ss_shmcycle = CNL->ss_shmcycle; \ SET_SNAPSHOTS_IN_PROG(CSA); \ assert(lcl_ss_ctx->ss_shmcycle <= ss_shmcycle); \ if (lcl_ss_ctx->ss_shmcycle != ss_shmcycle) \ { /* Process' view of snapshot is stale. Create/Update snapshot context */ \ status = ss_create_context(lcl_ss_ctx, ss_shmcycle); \ if (!status) \ { /* snapshot context creation failed. Reset private copy of snapshot_in_prog so that we don't \ * read the before images in t_end or op_tcommit */ \ CLEAR_SNAPSHOTS_IN_PROG(CSA); \ } \ assert(!status || (SNAPSHOT_INIT_DONE == lcl_ss_ctx->cur_state)); \ assert(status || (SHADOW_FIL_OPEN_FAIL == lcl_ss_ctx->cur_state) \ || (SNAPSHOT_SHM_ATTACH_FAIL == lcl_ss_ctx->cur_state) \ || (SNAPSHOT_NOT_INITED == lcl_ss_ctx->cur_state)); \ } else if ((SHADOW_FIL_OPEN_FAIL == lcl_ss_ctx->cur_state) \ || (SNAPSHOT_SHM_ATTACH_FAIL == lcl_ss_ctx->cur_state)) \ { /* Previous attempt at snapshot context creation failed (say, snapshot file open failed) and the error \ * has been reported in the shared memory. However, the snapshot is not yet complete. So, set \ * snapshot_in_prog to FALSE since the ongoing snapshot is not valid (as indicated by us in the prior \ * transaction/retry inside crit) \ * Note that we will be doing this 'if' check unconditionally until MUPIP INTEG detects the error in \ * shared memory which can be avoided by making GT.M itself set CNL->snapshot_in_prog to FALSE when it \ * detects inside crit that snapshot initialization failed for this process and hence the ongoing \ * snapshot is no longer valid. This way we don't wait for MUPIP INTEG to detect and terminate the \ * snapshots \ */ \ CLEAR_SNAPSHOTS_IN_PROG(CSA); \ } \ } #ifdef DEBUG # define DBG_ENSURE_SNAPSHOT_GOOD_TO_GO(LCL_SS_CTX, CNL) \ { \ shm_snapshot_ptr_t ss_shm_ptr; \ \ assert(SNAPSHOTS_IN_PROG(CNL)); \ assert(NULL != LCL_SS_CTX); \ ss_shm_ptr = LCL_SS_CTX->ss_shm_ptr; \ assert(NULL != ss_shm_ptr); \ assert(SNAPSHOT_INIT_DONE == LCL_SS_CTX->cur_state); \ assert(0 == LCL_SS_CTX->failure_errno); \ assert((-1 != CNL->ss_shmid) && \ (LCL_SS_CTX->attach_shmid == CNL->ss_shmid)); \ assert(NULL != LCL_SS_CTX->start_shmaddr); \ assert(0 == STRCMP(LCL_SS_CTX->shadow_file, ss_shm_ptr->ss_info.shadow_file)); \ assert(-1 != LCL_SS_CTX->shdw_fd); \ } #else # define DBG_ENSURE_SNAPSHOT_GOOD_TO_GO(LCL_SS_CTX, CNL) #endif /* Destroy an existing snapshot. Called by GT.M (or utilities like update process, MUPIP LOAD which uses * GT.M runtime. Assumes that csa->snapshot_in_prog is TRUE and as a side effect sets csa->snapshot_in_prog * to FALSE if the context is destroyed */ # define SS_RELEASE_IF_NEEDED(CSA, CNL) \ { \ int ss_shmcycle; \ snapshot_context_ptr_t lcl_ss_ctx; \ \ lcl_ss_ctx = SS_CTX_CAST(CSA->ss_ctx); \ assert(SNAPSHOTS_IN_PROG(CSA) && (NULL != lcl_ss_ctx)); \ ss_shmcycle = CNL->ss_shmcycle; \ if (!SNAPSHOTS_IN_PROG(cnl) || (lcl_ss_ctx->ss_shmcycle != ss_shmcycle)) \ { \ ss_destroy_context(lcl_ss_ctx); \ CLEAR_SNAPSHOTS_IN_PROG(CSA); \ } \ } /* No need to write before-image in case the block is FREE. In case the database had never been fully upgraded from V4 to V5 format * (after the MUPIP UPGRADE), all RECYCLED blocks can basically be considered FREE (i.e. no need to write before-images since * backward journal recovery will never be expected to take the database to a point BEFORE the mupip upgrade). * Logic to check if before image of a given block has to be read or not are slightly complicated if snapshots are present * For snapshots, we might want to read the before images of FREE blocks. Also, if the block that we are reading * is already before imaged by some other GT.M process then we do not needed to read the before image of such a block. But, such * a condition is applicable ONLY if snapshots alone are in progress as we might want the same block for BACKUP if it is in * progress. * Note: The below condition, to before image FREE blocks, is needed only if INTEG is the snapshot initiator. When we add * bitmasks or some alternate mechanism to optionalize the before image'ing of FREE blocks, this condition must be tweaked * accordingly. For now, INTEG is the only snapshot initiator. */ # define BEFORE_IMAGE_NEEDED(read_before_image, CS, csa, csd, blk_no, retval) \ { \ retval = (read_before_image && csd->db_got_to_v5_once); \ retval = retval && (!WAS_FREE(CS->blk_prior_state) || SNAPSHOTS_IN_PROG(csa)); \ retval = retval && (!ONLY_SS_BEFORE_IMAGES(csa) || !ss_chk_shdw_bitmap(csa, SS_CTX_CAST(csa->ss_ctx), blk_no));\ } # define CHK_AND_UPDATE_SNAPSHOT_STATE_IF_NEEDED(CSA, CNL, SS_NEED_TO_RESTART) \ { \ GBLREF uint4 process_id; \ \ uint4 lcl_failure_errno; \ ss_proc_status cur_state; \ shm_snapshot_ptr_t ss_shm_ptr; \ snapshot_context_ptr_t lcl_ss_ctx; \ boolean_t csa_snapshot_in_prog, cnl_snapshot_in_prog; \ \ assert(CSA->now_crit); \ csa_snapshot_in_prog = SNAPSHOTS_IN_PROG(CSA); \ cnl_snapshot_in_prog = SNAPSHOTS_IN_PROG(CNL); \ if (csa_snapshot_in_prog || cnl_snapshot_in_prog) \ { \ lcl_ss_ctx = SS_CTX_CAST(CSA->ss_ctx); \ ss_shm_ptr = (shm_snapshot_ptr_t)(SS_GETSTARTPTR(CSA)); \ assert(lcl_ss_ctx->ss_shmcycle <= CNL->ss_shmcycle); \ if (!cnl_snapshot_in_prog || ss_shm_ptr->failure_errno) \ { /* No on going snapshots or on going snapshot is invalid. Even if we encountered error during snapshot \ * context creation outside crit, we ignore it as the snapshot is no more active/valid. \ */ \ CLEAR_SNAPSHOTS_IN_PROG(CSA); \ } else if (lcl_ss_ctx->ss_shmcycle == CNL->ss_shmcycle) \ { /* Neither new snapshots started nor existing ones completed. However, it's possible that we might have \ * encountered error during snapshot context creation outside crit. If the values noted outside crit \ * matches with the global values, then the error is genuine. If not, then we might have done operations\ * (shm attach and file open) when things in the shared memory were in flux in which case we need to \ * restart \ */ \ lcl_failure_errno = lcl_ss_ctx->failure_errno; \ assert(!ss_shm_ptr->failure_errno); \ SS_NEED_TO_RESTART = FALSE; \ cur_state = lcl_ss_ctx->cur_state; \ switch(cur_state) \ { \ case SNAPSHOT_INIT_DONE: \ /* Most common case. Ensure the local values of snapshot context matches with the \ * values stored in shared memory */ \ assert(csa_snapshot_in_prog); \ DBG_ENSURE_SNAPSHOT_GOOD_TO_GO(lcl_ss_ctx, CNL); \ break; \ case SNAPSHOT_SHM_ATTACH_FAIL: \ assert(0 != lcl_failure_errno); \ assert(FALSE == SNAPSHOTS_IN_PROG(CSA)); \ if (lcl_ss_ctx->nl_shmid == CNL->ss_shmid) \ { /* Error encountered outside crit is genuine. Indicate MUPIP INTEG that the \ * snapshot is no more valid \ */ \ send_msg_csa(CSA_ARG(CSA) VARLSTCNT(4) ERR_SSATTACHSHM, 1, \ lcl_ss_ctx->nl_shmid, lcl_failure_errno); \ ss_shm_ptr->failure_errno = lcl_failure_errno; \ ss_shm_ptr->failed_pid = process_id; \ } else /* snapshot context creation done while things were in flux */ \ SS_NEED_TO_RESTART = TRUE; \ break; \ case SHADOW_FIL_OPEN_FAIL: \ assert(0 != lcl_failure_errno); \ assert(FALSE == SNAPSHOTS_IN_PROG(CSA)); \ if (0 == STRCMP(lcl_ss_ctx->shadow_file, ss_shm_ptr->ss_info.shadow_file)) \ { /* Error encountered outside crit is genuine. Indicate MUPIP INTEG that the \ * snapshot is no more valid \ */ \ send_msg_csa(CSA_ARG(CSA) VARLSTCNT(7) ERR_SSFILOPERR, 4, LEN_AND_LIT("open"), \ LEN_AND_STR(lcl_ss_ctx->shadow_file), lcl_failure_errno); \ ss_shm_ptr->failure_errno = lcl_failure_errno; \ ss_shm_ptr->failed_pid = process_id; \ } else /* snapshot context creation done while things were in flux */ \ SS_NEED_TO_RESTART = TRUE; \ break; \ default: \ assert(FALSE); \ } \ } else /* A new snapshot has started after we grabbed crit in t_end. Need to restart */ \ SS_NEED_TO_RESTART = TRUE; \ } \ } # define WRITE_SNAPSHOT_BLOCK(csa, cr, mm_blk_ptr, blkid, lcl_ss_ctx) \ { \ assert(NULL != lcl_ss_ctx); \ /* write this block to the snapshot shadow file only if this was not already \ * before imaged. If error happens while writing to the snapshot file, then \ * ss_write_block will mark the appropriate error in the shared memory \ * which INTEG will later query and report accordingly. So, just continue \ * as if nothing happened. \ */ \ if (!ss_chk_shdw_bitmap(csa, lcl_ss_ctx, blkid)) \ if (!ss_write_block(csa, blkid, cr, mm_blk_ptr, lcl_ss_ctx)) \ assert(FALSE); \ } #else /* GTM_SNAPSHOT is not defined */ # define SNAPSHOTS_IN_PROG(X) (FALSE) # define WRITE_SNAPSHOT_BLOCK(csa, cr, mm_blk_ptr, blkid, lcl_ss_ctx) # define SS_INIT_IF_NEEDED(CSA, CNL) # define SS_RELEASE_IF_NEEDED(CSA, CNL) /* No need to write before-image in case the block is FREE. In case the database had never been fully upgraded from V4 to V5 format * (after the MUPIP UPGRADE), all RECYCLED blocks can basically be considered FREE (i.e. no need to write before-images since * backward journal recovery will never be expected to take the database to a point BEFORE the mupip upgrade). */ # define BEFORE_IMAGE_NEEDED(read_before_image, CS, csa, csd, blk_no, retval) \ retval = (read_before_image && csd->db_got_to_v5_once && !WAS_FREE(CS->blk_prior_state)); #endif /* Determine if the state of 'backup in progress' has changed since we grabbed crit in t_end.c/tp_tend.c */ #define CHK_AND_UPDATE_BKUP_STATE_IF_NEEDED(CNL, CSA, NEW_BKUP_STARTED) \ { \ if (CSA->backup_in_prog != (BACKUP_NOT_IN_PROGRESS != CNL->nbb)) \ { \ if (!CSA->backup_in_prog) \ NEW_BKUP_STARTED = TRUE; \ CSA->backup_in_prog = !CSA->backup_in_prog; \ } \ } #define BLK_HDR_EMPTY(bp) ((0 == (bp)->bsiz) && (0 == (bp)->tn)) #ifdef GTM_TRUNCATE /* Reduction in free blocks after truncating from a to b total blocks: a = old_total (larger), b = new_total */ # define DELTA_FREE_BLOCKS(a, b) ((a - b) - (DIVIDE_ROUND_UP(a, BLKS_PER_LMAP) - DIVIDE_ROUND_UP(b, BLKS_PER_LMAP))) # define WRITE_EOF_BLOCK(reg, csd, new_total, status) \ { \ off_t new_eof; \ char buff[DISK_BLOCK_SIZE]; \ sgmnt_addrs *csa; \ unix_db_info *udi; \ \ new_eof = ((off_t)(csd->start_vbn - 1) * DISK_BLOCK_SIZE) + ((off_t)new_total * csd->blk_size); \ memset(buff, 0, DISK_BLOCK_SIZE); \ udi = FILE_INFO(reg); \ csa = &udi->s_addrs; \ DB_LSEEKWRITE(csa, udi->fn, udi->fd, new_eof, buff, DISK_BLOCK_SIZE, status); \ } #endif typedef enum { REG_FREEZE_SUCCESS, REG_ALREADY_FROZEN, REG_HAS_KIP } freeze_status; #ifdef UNIX /* This structure holds state captured on entry into gvcst_redo_root_search which it restores on error or exit */ typedef struct redo_root_search_context_struct { unsigned char t_fail_hist[CDB_MAX_TRIES]; unsigned int t_tries; unsigned int prev_t_tries; inctn_opcode_t inctn_opcode; trans_num start_tn; uint4 update_trans; uint4 t_err; boolean_t hold_onto_crit; char currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)]; gv_key *gv_currkey; # ifdef DEBUG unsigned char t_fail_hist_dbg[T_FAIL_HIST_DBG_SIZE]; unsigned int t_tries_dbg; # endif } redo_root_search_context; #endif #define SET_GV_CURRKEY_FROM_REORG_GV_TARGET \ { /* see mupip reorg.c for comment */ \ GBLREF gv_key *gv_currkey; \ GBLREF gv_namehead *reorg_gv_target; /* for global name */ \ GBLREF boolean_t mu_reorg_process; \ \ mname_entry *gvent; \ int end; \ \ assert(mu_reorg_process); \ gvent = &reorg_gv_target->gvname; \ memcpy(gv_currkey->base, gvent->var_name.addr, gvent->var_name.len); \ end = gvent->var_name.len + 1; \ gv_currkey->end = end; \ gv_currkey->base[end - 1] = 0; \ gv_currkey->base[end] = 0; \ } #define SET_WANT_ROOT_SEARCH(CDB_STATUS, WANT_ROOT_SEARCH) \ { \ GBLREF uint4 t_tries; \ GBLREF gv_namehead *gv_target; \ \ if (cdb_sc_normal == cdb_status) \ cdb_status = LAST_RESTART_CODE; \ /* Below IF check is a special case where t_retry/tp_restart detects mismatched root cycles in 2nd to 3rd retry \ * transition. In this case, the CDB_STATUS can be anything but we still need to redo the root search \ */ \ if ((CDB_STAGNATE == t_tries) && !gv_target->root) \ WANT_ROOT_SEARCH = TRUE; \ switch(CDB_STATUS) \ { \ case cdb_sc_onln_rlbk1: \ case cdb_sc_gvtrootmod: \ case cdb_sc_gvtrootmod2: \ WANT_ROOT_SEARCH = TRUE; \ break; \ case cdb_sc_onln_rlbk2: \ /* Database was taken back to a different logical state and we are an implicit TP \ * transaction. Issue DBROLLEDBACK error that the application programmer can catch and do \ * the necessary stuff. \ */ \ assert(gtm_trigger_depth == tstart_trigger_depth); \ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DBROLLEDBACK); \ default: \ break; \ } \ } #define REDO_ROOT_SEARCH_IF_NEEDED(WANT_ROOT_SEARCH, CDB_STATUS) \ { \ DEBUG_ONLY(GBLREF tp_frame *tp_pointer;) \ GBLREF uint4 t_err; \ GBLREF uint4 update_trans; \ uint4 save_update_trans, save_t_err; \ \ CDB_STATUS = cdb_sc_normal; \ if (WANT_ROOT_SEARCH) \ { /* We are implicit transaction and one of two things has happened: \ * 1. Online rollback updated the database but did NOT take us to a different logical state in which \ * case we've already done the restart, but the root is now reset to zero. \ * 2. mu_swap_root concurrently moved root blocks. We've restarted and reset root to zero. \ * In either case, do root search to establish the new root. \ */ \ NON_GTMTRIG_ONLY(assert(FALSE)); \ assert(tp_pointer->implicit_tstart); \ assert(NULL != gv_target); \ save_t_err = t_err; \ save_update_trans = update_trans; \ GVCST_ROOT_SEARCH_DONOT_RESTART(CDB_STATUS); \ t_err = save_t_err; \ update_trans = save_update_trans; \ if (cdb_sc_normal == CDB_STATUS) \ WANT_ROOT_SEARCH = FALSE; \ } \ } #define ASSERT_BEGIN_OF_FRESH_TP_TRANS \ { \ GBLREF sgm_info *first_sgm_info; \ GBLREF sgm_info *sgm_info_ptr; \ \ assert((NULL == first_sgm_info) || ((sgm_info_ptr == first_sgm_info) && (NULL == first_sgm_info->next_sgm_info))); \ assert((NULL == first_sgm_info) || (0 == sgm_info_ptr->num_of_blks)); \ } #define GVCST_ROOT_SEARCH \ { /* gvcst_root_search is invoked to establish the root block of a given global (pointed to by gv_target). We always \ * expect the root block of the directory tree to be 1 and so must never come here with gv_target pointing to directory \ * tree. Assert that. \ */ \ assert((NULL != gv_target) && (DIR_ROOT != gv_target->root)); \ if (!gv_target->root) \ gvcst_root_search(FALSE); \ } /* Same as GVCST_ROOT_SEARCH, but tells gvcst_root_search NOT to restart but to return the status code back to the caller */ #define GVCST_ROOT_SEARCH_DONOT_RESTART(STATUS) \ { \ assert((NULL != gv_target) && (DIR_ROOT != gv_target->root)); \ STATUS = cdb_sc_normal; \ if (!gv_target->root) \ STATUS = gvcst_root_search(TRUE); \ } #define GVCST_ROOT_SEARCH_AND_PREP(est_first_pass) \ { /* Before beginning a spanning node try in a gvcst routine, make sure the root is established. If we've restarted \ * issue DBROLLEDBACK appropriately. \ */ \ GBLREF unsigned char t_fail_hist[CDB_MAX_TRIES]; /* for LAST_RESTART_CODE */ \ GBLREF stack_frame *frame_pointer; \ \ DCL_THREADGBL_ACCESS; \ \ SETUP_THREADGBL_ACCESS; \ assert(dollar_tlevel); \ ASSERT_BEGIN_OF_FRESH_TP_TRANS; \ frame_pointer->flags |= SFF_IMPLTSTART_CALLD; \ if (est_first_pass && (cdb_sc_onln_rlbk2 == LAST_RESTART_CODE)) \ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DBROLLEDBACK); \ tp_set_sgm(); \ GVCST_ROOT_SEARCH; \ } #define GV_BIND_NAME_ONLY(ADDR, TARG) gv_bind_name(ADDR, TARG) #define GV_BIND_NAME_AND_ROOT_SEARCH(ADDR, TARG) \ { \ enum db_acc_method acc_meth; \ GBLREF gd_region *gv_cur_region; \ GBLREF gv_namehead *gv_target; \ \ GV_BIND_NAME_ONLY(ADDR, TARG); \ acc_meth = gv_cur_region->dyn.addr->acc_meth; \ if ((dba_bg == acc_meth) || (dba_mm == acc_meth)) \ GVCST_ROOT_SEARCH; \ } /* When invoking grab_lock or grab_gtmsource_srv_latch, use one of the following parameters. * GRAB_LOCK_ONLY : use when code expects an online rollback, but handles it separately (like updproc.c) * GRAB_GTMSOURCE_SRV_LATCH_ONLY : Same as above (just that this is used for grab_gtmsource_srv_latch instead of grab_lock) * ASSERT_NO_ONLINE_ROLLBACK : use when holding some other lock (like crit) that prevents online rollback * HANDLE_CONCUR_ONLINE_ROLLBACK : use when not blocking online rollback, but handling with this macro (only source server) */ #define GRAB_LOCK_ONLY 0x01 #define GRAB_GTMSOURCE_SRV_LATCH_ONLY 0x01 #define ASSERT_NO_ONLINE_ROLLBACK 0x02 #define HANDLE_CONCUR_ONLINE_ROLLBACK 0x03 #ifdef UNIX /* caller should have THREADGBL_ACCESS and gbl access to t_tries and t_fail_hist */ # define LAST_RESTART_CODE ( (0 < t_tries) ? t_fail_hist[TREF(prev_t_tries)] : (enum cdb_sc)cdb_sc_normal ) # define SYNC_ONLN_RLBK_CYCLES \ { \ GBLREF sgmnt_addrs *cs_addrs_list; \ GBLREF jnlpool_addrs jnlpool; \ GBLREF boolean_t mu_reorg_process; \ \ sgmnt_addrs *lcl_csa; \ DCL_THREADGBL_ACCESS; \ \ SETUP_THREADGBL_ACCESS; \ if (!TREF(in_gvcst_bmp_mark_free) || mu_reorg_process) \ { \ for (lcl_csa = cs_addrs_list; NULL != lcl_csa; lcl_csa = lcl_csa->next_csa) \ { \ lcl_csa->onln_rlbk_cycle = lcl_csa->nl->onln_rlbk_cycle; \ lcl_csa->db_onln_rlbkd_cycle = lcl_csa->nl->db_onln_rlbkd_cycle; \ lcl_csa->db_trigger_cycle = lcl_csa->hdr->db_trigger_cycle; \ } \ if (NULL != jnlpool.jnlpool_ctl) \ { \ lcl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; \ lcl_csa->onln_rlbk_cycle = jnlpool.jnlpool_ctl->onln_rlbk_cycle; \ } \ } \ } # define SYNC_ROOT_CYCLES(CSA) \ { /* NULL CSA acts as a flag to do all regions */ \ GBLREF sgmnt_addrs *cs_addrs_list; \ GBLREF boolean_t mu_reorg_process; \ \ sgmnt_addrs *lcl_csa; \ DCL_THREADGBL_ACCESS; \ \ SETUP_THREADGBL_ACCESS; \ for (lcl_csa = cs_addrs_list; NULL != lcl_csa; lcl_csa = lcl_csa->next_csa) \ if (NULL == (CSA) || (CSA) == lcl_csa) \ lcl_csa->root_search_cycle = lcl_csa->nl->root_search_cycle; \ } # define MISMATCH_ROOT_CYCLES(CSA, CNL) ((CSA)->root_search_cycle != (CNL)->root_search_cycle) # define MISMATCH_ONLN_RLBK_CYCLES(CSA, CNL) ((CSA)->onln_rlbk_cycle != (CNL)->onln_rlbk_cycle) # define ONLN_RLBK_STATUS(CSA, CNL) \ (((CSA)->db_onln_rlbkd_cycle != (CNL)->db_onln_rlbkd_cycle) ? cdb_sc_onln_rlbk2 : cdb_sc_onln_rlbk1) # define ABORT_TRANS_IF_GBL_EXIST_NOMORE(LCL_T_TRIES, TN_ABORTED) \ { \ DEBUG_ONLY(GBLREF unsigned int t_tries;) \ DEBUG_ONLY(GBLREF unsigned char t_fail_hist[CDB_MAX_TRIES];) \ GBLREF gd_region *gv_cur_region; \ GBLREF sgmnt_addrs *cs_addrs; \ GBLREF gv_namehead *gv_target; \ \ DEBUG_ONLY(enum cdb_sc failure;) \ DCL_THREADGBL_ACCESS; \ \ SETUP_THREADGBL_ACCESS; \ assert(0 < t_tries); \ assert((CDB_STAGNATE == t_tries) || (lcl_t_tries == t_tries - 1)); \ DEBUG_ONLY(failure = LAST_RESTART_CODE); \ assert(NULL != gv_target); \ TN_ABORTED = FALSE; \ if (!gv_target->root) \ { /* online rollback took us back to a prior logical state where the global that existed when we came into \ * mu_reorg or mu_extr_getblk, no longer exists. Consider this as the end of the tree and return to the \ * caller with the appropriate code. The caller knows to continue with the next global \ */ \ assert(cdb_sc_onln_rlbk2 == failure || TREF(rlbk_during_redo_root)); \ /* abort the current transaction */ \ t_abort(gv_cur_region, cs_addrs); \ TN_ABORTED = TRUE; \ } \ } #else # define ABORT_TRANS_IF_GBL_EXIST_NOMORE(LCL_T_TRIES, TN_ABORTED) #endif #define SET_GV_ALTKEY_TO_GBLNAME_FROM_GV_CURRKEY \ { \ uchar_ptr_t dst_ptr, src_ptr; \ \ GBLREF gv_key *gv_currkey, *gv_altkey; \ GBLREF int4 gv_keysize; \ \ assert(gv_altkey->top == gv_currkey->top); \ assert(gv_altkey->top == gv_keysize); \ assert(gv_currkey->end < gv_currkey->top); \ dst_ptr = gv_altkey->base; \ src_ptr = gv_currkey->base; \ for ( ; *src_ptr; ) \ *dst_ptr++ = *src_ptr++; \ *dst_ptr++ = 0; \ *dst_ptr = 0; \ gv_altkey->end = dst_ptr - gv_altkey->base; \ assert(gv_altkey->end < gv_altkey->top); \ } typedef struct span_subs_struct { unsigned char b_ctrl; unsigned char b_first; unsigned char b_sec; } span_subs; #define ASCII_0 '0' #define SPAN_BLKID_BASE 255 #define DECIMAL_BASE 10 /* SPAN_SUBS_LEN macro define the length of the special subscript of spanning node in terms of number of characters. * The format of special spanning node subscript is '#-X-X', where X ranges from 1 to 255. Note that X never takes the * value of '0' because '0' is used as subscript deliminiter. */ #define SPAN_SUBS_LEN 3 #define SPAN_PREFIX "#SPAN" #define SPAN_PREFIX_LEN (SIZEOF(SPAN_PREFIX) - 1) #define ASGN_SPAN_PREFIX(B) {*(B) = '#'; *(B + 1) = 'S'; *(B + 2) = 'P'; *(B + 3) = 'A'; *(B + 4) = 'N';} #define SPAN_GVSUBS2INT(A) (((A)->b_first - 1) * SPAN_BLKID_BASE + (A)->b_sec - 1) #define SPAN_INT2GVSUBS(A, B) {(A)->b_ctrl = 0x02; (A)->b_first = B / SPAN_BLKID_BASE + 1 ; (A)->b_sec = B % SPAN_BLKID_BASE + 1;} #define SPAN_DECLSUBS(A) (span_subs A) #define SPAN_INITSUBS(A, B) SPAN_INT2GVSUBS(A, B) #define SPAN_INCRSUBS(A) SPAN_INT2GVSUBS(A, SPAN_GVSUBS2INT(A) + 1) #define SPAN_INCRBYSUBS(A, B) SPAN_INT2GVSUBS(A, SPAN_GVSUBS2INT(A) + B) #define SPAN_DECRSUBS(A, B) SPAN_INT2GVSUBS(A, SPAN_GVSUBS2INT(A) - 1) #define SPAN_DECRBYSUBS(A, B) SPAN_INT2GVSUBS(A, SPAN_GVSUBS2INT(A) - B) /* The following macro assumes that the length of the special subscript for spanning node is '3'. The assert in the macro verfies * that this assumption is true. In future, if the length of the special subscript for spanning node changes, the following macro * needs to be fixed accordingly. */ #define SPAN_SUBSCOPY_SRC2DST(DST, SRC) \ { \ assert(SPAN_SUBS_LEN == 3); \ *((DST) + 0) = *((SRC) + 0); \ *((DST) + 1) = *((SRC) + 1); \ *((DST) + 2) = *((SRC) + 2); \ } /*#include "mv_stent.h"*/ typedef struct { boolean_t span_status; boolean_t enable_jnl_format; boolean_t enable_trigger_read_and_fire; boolean_t ztval_gvcst_put_redo; mval *val_forjnl; int4 blk_reserved_bytes; # ifdef GTM_TRIGGER unsigned char *save_msp; unsigned char *save_mv_chain; /* actually mv_stent ptr */ mval *ztold_mval; mval *ztval_mval; # endif } span_parms; #ifdef UNIX # define DEFINE_NSB_CONDITION_HANDLER(gvcst_xxx_ch) \ CONDITION_HANDLER(gvcst_xxx_ch) \ { \ int rc; \ \ START_CH; \ if ((int)ERR_TPRETRY == SIGNAL) \ { \ rc = tp_restart(1, !TP_RESTART_HANDLES_ERRORS); \ /*DEBUG_ONLY(printf("gvcst_xxx_ch: Unwinding due to TP Restart\n");)*/ \ UNWIND(NULL, NULL); \ } \ NEXTCH; \ } /* Check if the value of a primary node is a dummy value: $c(0). If so, it might be a spanning node */ # define IS_SN_DUMMY(len, addr) ((1 == (len)) && ('\0' == *(unsigned char *)(addr))) # define RTS_ERROR_IF_SN_DISALLOWED \ { \ GBLREF boolean_t span_nodes_disallowed; \ \ error_def(ERR_TEXT); /* BYPASSOK */ \ error_def(ERR_UNIMPLOP); /* BYPASSOK */ \ \ if (span_nodes_disallowed) \ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UNIMPLOP, 0, ERR_TEXT, 2, \ LEN_AND_LIT("GT.CM Server does not support spanning nodes")); \ } # define IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(STATEMENT) \ { /* We've encountered a spanning node dummy value. Check if spanning nodes are disallowed (e.g., GT.CM). \ * If csd->span_node_absent is TRUE we know the value really is $c(0) and we return that. Otherwise, \ * this is potentially a spanning node. We cannot do an op_tstart to check so we issue an error instead. \ */ \ GBLREF sgmnt_data_ptr_t cs_data; \ GBLREF boolean_t span_nodes_disallowed; \ \ if (span_nodes_disallowed) \ { \ if (!cs_data->span_node_absent) \ { \ RTS_ERROR_IF_SN_DISALLOWED; \ } else \ { \ STATEMENT; \ } \ } \ } #else # define DEFINE_NSB_CONDITION_HANDLER(gvcst_xxx_ch) # define IF_NSB_DUMMY_RETURN # define RTS_ERROR_IF_SN_DISALLOWED_AND_SPAN_IN_DB # define RETURN_NO_VAL_IF_SN_DISALLOWED # define RETURN_IF_SN_DISALLOWED(value) #endif #define MAX_NSBCTRL_SZ 30 /* Upper bound on size of ctrl value. 2*10 digs + 1 comma + 1 null + overhead */ /* Control node value is 6 bytes, 2 for unsigned short numsubs, 4 for uint4 gblsize. Each is little-endian. */ #ifdef BIGENDIAN # define PUT_NSBCTRL(BYTES, NUMSUBS, GBLSIZE) \ { \ unsigned short swap_numsubs; \ uint4 swap_gblsize; \ \ swap_numsubs = GTM_BYTESWAP_16(NUMSUBS); \ swap_gblsize = GTM_BYTESWAP_32(GBLSIZE); \ PUT_USHORT((unsigned char *)BYTES, swap_numsubs); \ PUT_ULONG((unsigned char *)BYTES + 2, swap_gblsize); \ } # define GET_NSBCTRL(BYTES, NUMSUBS, GBLSIZE) \ { \ unsigned short swap_numsubs; \ uint4 swap_gblsize; \ \ GET_USHORT(swap_numsubs, (unsigned char *)BYTES); \ GET_ULONG(swap_gblsize, (unsigned char *)BYTES + 2); \ NUMSUBS = GTM_BYTESWAP_16(swap_numsubs); \ GBLSIZE = GTM_BYTESWAP_32(swap_gblsize); \ } #else # define PUT_NSBCTRL(BYTES, NUMSUBS, GBLSIZE) \ { \ PUT_USHORT((unsigned char *)BYTES, NUMSUBS); \ PUT_ULONG((unsigned char *)BYTES + 2, GBLSIZE); \ } # define GET_NSBCTRL(BYTES, NUMSUBS, GBLSIZE) \ { \ GET_USHORT(NUMSUBS, (unsigned char *)BYTES); \ GET_ULONG(GBLSIZE, (unsigned char *)BYTES + 2); \ } #endif #define CHECK_HIDDEN_SUBSCRIPT_AND_RETURN(found, gv_altkey, is_hidden) \ { \ if (found) \ { \ CHECK_HIDDEN_SUBSCRIPT(gv_altkey, is_hidden); \ if (!is_hidden) \ return found; \ } else \ return found; \ } #define CHECK_HIDDEN_SUBSCRIPT_AND_BREAK(found, gv_altkey, is_hidden) \ { \ if (found) \ { \ CHECK_HIDDEN_SUBSCRIPT(gv_altkey, is_hidden); \ if (!is_hidden) \ break; \ } else \ break; \ } #define CHECK_HIDDEN_SUBSCRIPT(KEY, IS_HIDDEN) \ { \ sm_uc_ptr_t keyloc; \ \ keyloc = (KEY)->base + (KEY)->end - 5; \ if ((KEY)->end >= 5 && 0 == *keyloc && 2 == *(keyloc+1)) \ IS_HIDDEN = TRUE; \ else \ IS_HIDDEN = FALSE; \ } #define SAVE_GV_CURRKEY \ { \ assert(NULL != gv_currkey); \ assert((SIZEOF(gv_key) + gv_currkey->end) <= SIZEOF(save_currkey)); \ save_gv_currkey = (gv_key *)&save_currkey[0]; \ memcpy(save_gv_currkey, gv_currkey, SIZEOF(gv_key) + gv_currkey->end); \ } #define RESTORE_GV_CURRKEY \ { \ assert(gv_currkey->top == save_gv_currkey->top); \ memcpy(gv_currkey, save_gv_currkey, SIZEOF(gv_key) + save_gv_currkey->end); \ } #define SAVE_GV_CURRKEY_LAST_SUBSCRIPT(gv_currkey, prev, oldend) \ { \ prev = gv_currkey->prev; \ oldend = gv_currkey->end; \ assert('\0' == gv_currkey->base[oldend]); \ if (prev <= oldend) \ memcpy(save_currkey, &gv_currkey->base[prev], oldend - prev + 1); \ } #define RESTORE_GV_CURRKEY_LAST_SUBSCRIPT(gv_currkey, prev, oldend) \ { \ gv_currkey->prev = prev; \ gv_currkey->end = oldend; \ if (prev <= oldend) \ memcpy(&gv_currkey->base[prev], save_currkey, oldend - prev + 1); \ assert('\0' == gv_currkey->base[oldend]); \ } #define CAN_APPEND_HIDDEN_SUBS(KEY) (((KEY)->end + 5 <= MAX_KEY_SZ) && ((KEY)->end + 5 <= (KEY)->top)) #define APPEND_HIDDEN_SUB(KEY) \ { \ int end; \ \ assert(CAN_APPEND_HIDDEN_SUBS(KEY)); \ end = gv_currkey->end; \ gv_currkey->end += 4; \ (KEY)->base[end++] = 2; \ (KEY)->base[end++] = 1; \ (KEY)->base[end++] = 1; \ (KEY)->base[end++] = 0; \ (KEY)->base[end] = 0; \ } #define NEXT_HIDDEN_SUB(KEY, I) \ { \ int end; \ \ end = gv_currkey->end - 4; \ (KEY)->base[end++] = 2; \ (KEY)->base[end++] = 1 + ((I + 1) / 0xFF); \ (KEY)->base[end++] = 1 + ((I + 1) % 0xFF); \ (KEY)->base[end++] = 0; \ (KEY)->base[end] = 0; \ } #define RESTORE_CURRKEY(KEY, OLDEND) \ { \ (KEY)->end = OLDEND; \ (KEY)->base[OLDEND - 1] = 0; \ (KEY)->base[OLDEND] = 0; \ } #define COMPUTE_CHUNK_SIZE(KEY, BLKSZ, RESERVED) \ (BLKSZ - RESERVED - ((KEY)->end + 1) - SIZEOF(blk_hdr) - SIZEOF(rec_hdr)) void assert_jrec_member_offsets(void); bt_rec_ptr_t bt_put(gd_region *r, int4 block); void bt_que_refresh(gd_region *greg); void bt_init(sgmnt_addrs *cs); void bt_malloc(sgmnt_addrs *csa); void bt_refresh(sgmnt_addrs *csa, boolean_t init); void db_common_init(gd_region *reg, sgmnt_addrs *csa, sgmnt_data_ptr_t csd); void grab_crit(gd_region *reg); boolean_t grab_crit_immediate(gd_region *reg); boolean_t grab_lock(gd_region *reg, boolean_t is_blocking_wait, uint4 onln_rlbk_action); void gv_init_reg(gd_region *reg); void gvcst_init(gd_region *greg); enum cdb_sc gvincr_compute_post_incr(srch_blk_status *bh); enum cdb_sc gvincr_recompute_upd_array(srch_blk_status *bh, struct cw_set_element_struct *cse, cache_rec_ptr_t cr); boolean_t mupfndfil(gd_region *reg, mstr *mstr_addr); boolean_t region_init(bool cm_regions); freeze_status region_freeze(gd_region *region, boolean_t freeze, boolean_t override, boolean_t wait_for_kip); void rel_crit(gd_region *reg); void rel_lock(gd_region *reg); boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_is_wcs_recover); bool wcs_wtfini(gd_region *reg); #ifdef VMS int4 wcs_wtstart(gd_region *region); #elif defined(UNIX) int4 wcs_wtstart(gd_region *region, int4 writes); #else #error Undefined Platform #endif void bmm_init(void); int4 bmm_find_free(uint4 hint, uchar_ptr_t base_addr, uint4 total_bits); bool reg_cmcheck(gd_region *reg); void gv_bind_name(gd_addr *addr, mstr *targ); void db_csh_ini(sgmnt_addrs *cs); void db_csh_ref(sgmnt_addrs *cs_addrs, boolean_t init); cache_rec_ptr_t db_csh_get(block_id block); cache_rec_ptr_t db_csh_getn(block_id block); enum cdb_sc tp_hist(srch_hist *hist1); sm_uc_ptr_t get_lmap(block_id blk, unsigned char *bits, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr); bool ccp_userwait(struct gd_region_struct *reg, uint4 state, int4 *timadr, unsigned short cycle); void ccp_closejnl_ast(struct gd_region_struct *reg); bt_rec *ccp_bt_get(sgmnt_addrs *cs_addrs, int4 block); unsigned char *mval2subsc(mval *in_val, gv_key *out_key); int4 dsk_read(block_id blk, sm_uc_ptr_t buff, enum db_ver *ondisk_blkver, boolean_t blk_free); gtm_uint64_t gds_file_size(file_control *fc); uint4 jnl_flush(gd_region *reg); void jnl_fsync(gd_region *reg, uint4 fsync_addr); void jnl_mm_timer(sgmnt_addrs *csa, gd_region *reg); void jnl_oper_user_ast(gd_region *reg); void jnl_wait(gd_region *reg); void view_jnlfile(mval *dst, gd_region *reg); void jnl_put_jrt_pfin(sgmnt_addrs *csa); void jnl_put_jrt_pini(sgmnt_addrs *csa); void jnl_write_epoch_rec(sgmnt_addrs *csa); void jnl_write_inctn_rec(sgmnt_addrs *csa); void fileheader_sync(gd_region *reg); gd_addr *create_dummy_gbldir(void); /* These prototypes should ideally be included in gvstats_rec.h but they require "sgmnt_addrs" type * to be defined which is done in this header file, hence the prototyping is done here instead. */ void gvstats_rec_csd2cnl(sgmnt_addrs *csa); void gvstats_rec_cnl2csd(sgmnt_addrs *csa); void gvstats_rec_upgrade(sgmnt_addrs *csa); #include "gdsfheadsp.h" /* End of gdsfhead.h */ #endif fis-gtm-V6.0-003/sr_port/gdsfilext.h0000644000032200000250000000157112201176156016201 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GDSFILEXT_H__ #define __GDSFILEXT_H__ #ifdef UNIX uint4 gdsfilext(uint4 blocks, uint4 filesize, boolean_t trans_in_prog); # define GDSFILEXT(BLOCKS, FILESIZE, TRANS_IN_PROG) gdsfilext(BLOCKS, FILESIZE, TRANS_IN_PROG) #else uint4 gdsfilext(uint4 blocks, uint4 filesize); # define GDSFILEXT(BLOCKS, FILESIZE, DUMMY) gdsfilext(BLOCKS, FILESIZE) #endif #define TRANS_IN_PROG_FALSE FALSE #define TRANS_IN_PROG_TRUE TRUE #endif fis-gtm-V6.0-003/sr_port/gdskill.h0000644000032200000250000000267212201176156015644 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GDSKILL_H__ #define __GDSKILL_H__ /* Since small memory is allocated in powers of two, keep the kill_set structure size about 8 bytes under 1k mark (current size of header used by memory management system) */ #define BLKS_IN_KILL_SET 251 /* Note that currently GDS_MAX_BLK_BITS is 30. This 30 bit block field allows for a 1G GDS block database. */ typedef struct { #ifdef BIGENDIAN unsigned int flag : 1; /* Block was created by this TP transaction (not real block yet) */ unsigned int level : 1; /* Block level (zero or non-zero) */ unsigned int block : GDS_MAX_BLK_BITS; /* Block number */ #else unsigned int block : GDS_MAX_BLK_BITS; /* Block number */ unsigned int level : 1; /* Block level (zero or non-zero) */ unsigned int flag : 1; /* Block was created by this TP transaction (not real block yet) */ #endif } blk_ident; typedef struct kill_set_struct { struct kill_set_struct *next_kill_set; int4 used; blk_ident blk[BLKS_IN_KILL_SET]; } kill_set; #endif fis-gtm-V6.0-003/sr_port/gdsroot.h0000644000032200000250000001467712201176156015704 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GDSROOT_H #define GDSROOT_H #include #define DIR_ROOT 1 #define CDB_STAGNATE 3 #define CDB_MAX_TRIES (CDB_STAGNATE + 2) /* used in defining arrays, usage requires it must be at least 1 more than CSB_STAGNATE*/ #define T_FAIL_HIST_DBG_SIZE 32 #define MAX_BT_DEPTH 7 #define CSE_LEVEL_DRT_LVL0_FREE (MAX_BT_DEPTH + 2) /* used to indicate a level-0 block in GV tree will be freed */ #define GLO_NAME_MAXLEN 33 /* 1 for length, 4 for prefix, 15 for dvi, 1 for $, 12 for fid */ #define MAX_NUM_SUBSC_LEN 10 /* one for exponent, nine for the 18 significant digits */ /* Define padding in a gv_key structure to hold * 1) A number : This way we are ensured a key buffer overflow will never occur while converting a number * from mval representation to subscript representation. * 2) 16 byte of a string : This way if we are about to overflow the max-key-size, we are more likely to fit the * overflowing key in the padding space and so can give a more user-friendly GVSUBOFLOW message which * includes the overflowing subscript in most practical situations. */ #define MAX_GVKEY_PADDING_LEN (MAX_NUM_SUBSC_LEN + 16) #define EXTEND_WARNING_FACTOR 3 /* Define macro to compute the maximum key size required in the gv_key structure based on the database's maximum key size. * Align it to 4-byte boundary as this macro is mostly used by targ_alloc which allocates 3 keys one for gv_target->clue, * one for gv_target->first_rec and one for gv_target->last_rec. The alignment ensures all 3 fields start at aligned boundary. * In the following macro, we can ideally use the ROUND_UP2 macro but since this is used in a typedef (of "key_cum_value") * in gdscc.h, we cannot use that macro as it contains GTMASSERT expressions to do the 2-power check. To avoid this, * we use the ROUND_UP macro (which has no checks). It is ok to do that instead of the more-efficient ROUND_UP2 macro * as the second parameter is a constant so all this should get evaluated at compile-time itself. */ #define DBKEYSIZE(KSIZE) (ROUND_UP((KSIZE + MAX_GVKEY_PADDING_LEN), 4)) /* Possible states for TREF(in_mu_swap_root_state) (part of MUPIP REORG -TRUNCATE) */ #define MUSWP_NONE 0 /* default; not in mu_swap_root */ #define MUSWP_INCR_ROOT_CYCLE 1 /* moving a root block; need to increment root_search_cycle */ #define MUSWP_FREE_BLK 2 /* freeing a directory block; need to write leaf blocks to snapshot file */ #define MUSWP_DIRECTORY_SWAP 3 /* moving a directory block; just checked by cert_blk */ typedef gtm_uint64_t trans_num; typedef uint4 trans_num_4byte; typedef int4 block_id; /* allows for GDS block #s to have 32 bits but see GDS_MAX_BLK_BITS below */ #define GDS_MAX_BLK_BITS 30 /* see blk_ident structure in gdskill.h for why this cannot be any greater */ #define GDS_MAX_VALID_BLK (1<inode != (B)->inode) \ ? ((A)->inode > (B)->inode ? 1 : -1) \ : ((A)->device != (B)->device) \ ? ((A)->device > (B)->device ? 1 : -1) \ : ((A)->st_gen != (B)->st_gen) \ ? ((A)->st_gen > (B)->st_gen ? 1 : -1) \ : 0) #else #define gdid_cmp(A, B) \ (((A)->inode != (B)->inode) \ ? ((A)->inode > (B)->inode ? 1 : -1) \ : ((A)->device != (B)->device) \ ? ((A)->device > (B)->device ? 1 : -1) \ : 0) #endif #define is_gdid_gdid_identical(A, B) (0 == gdid_cmp(A, B) ? TRUE: FALSE) #endif #define VALFIRSTCHAR(X) (ISALPHA_ASCII(X) || ('%' == X)) #define VALFIRSTCHAR_WITH_TRIG(X) (ISALPHA_ASCII(X) || ('%' == X) GTMTRIG_ONLY(|| (HASHT_GBL_CHAR1 == X))) #define VALKEY(X) (ISALPHA_ASCII(X) || ISDIGIT_ASCII(X)) /* Prototypes below */ block_id get_dir_root(void); boolean_t get_full_path(char *orig_fn, unsigned int orig_len, char *full_fn, unsigned int *full_len, int max_len, uint4 *status); void gvinit(void); #ifdef VMS void global_name(unsigned char prefix[], gds_file_id *fil, unsigned char *buff); #endif #endif fis-gtm-V6.0-003/sr_port/ged.mpt0000644000032200000250000001346412201176156015324 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1989,2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %ged ;%ged - global editor n (%zdebug) s %("lo")="abcdefghijklmnopqrstuvwxyz" s %("up")="ABCDEFGHIJKLMNOPQRSTUVWXYZ" s %("$zso")=$zso s %("$io")=$io s $zso=$select($zv'["VMS":".",1:"[]")_"_"_$j_".ged" s %("zlbeg")=$zl beg ; n $et s $et=$s($d(%zdebug):"b",1:"s $ec="""" zg "_$zl_":beg") u 0:(ctrap=$c(3)) f r !,"Edit ^",%("global"),! q:%("global")="" d . i $e(%("global"))'="^" s %("global")="^"_%("global") . if (($e(%("global"),2)="%")&($l(%("global"))=2)) d q .. w !,"%ged will not edit: ",%("global") .. q . if ($e(%("global"),2)="?") d help q . d convert . d main . k @%("local"),@(%("a")_$e(%("global"),3,%("glbl lngth"))) . zwi %("add"),%("change"),%("kill"),%("s") . quit s $zso=%("$zso") u %("$io"):(ctrap="":exception="") q ; main ; s %("glbl lngth")=$f(%("global"),"(")-2 if %("glbl lngth")=-2 s %("glbl lngth")=$l(%("global")) s %("local")=$e(%("global"),2,%("glbl lngth")) d zwr s %=%("global") o $zso u $zso f r % q:$zeof s @(%("a")_$e(%,3,9999)) s %("s")=$g(%("s"))+1 c $zso zed $zso o $zso:(read:rewind) d stor c $zso:delete o $zso c $zso:delete w !,"node : ",%("global") w !,"selected : ",+$g(%("s")) w !,"changed : ",+$g(%("change")) w !,"added : ",+$g(%("add")) w !,"killed : ",+$g(%("kill")) q ; zwr ; n $et s $et=$s($d(%zdebug):"b",1:"s $ec="""" goto continue") o $zso:(newversion:exc="":noreadonly) u $zso zwr @%("global") continue c $zso q badzwr ; c $zso:delete u 0 w !,"invalid global description: ",%("global") q stor ; s %("storlvl")=$zl u $zso f r % quit:$zeof d istor do work q istor ; n $et s $et="do istorerr" i '$l($tr(%," ")) q i $e(%)'="^" s %="^"_% i $e(%,1,%("glbl lngth"))=$e(%("global"),1,%("glbl lngth")) do . s %=$e(%,2,99999) . s @% . quit else do . set %("cur io")=$io . u 0 w !,"%ged will not edit: ",% . use %("cur io") . quit q ; istorerr; close $zso use 0 w !,"invalid syntax: ",%,!,"return to continue: " r %:30,! zed $zso open $zso:(read:rewind) s $ec="" zg %("storlvl"):stor work ; s %=%("local") if $d(@%)'[0 d check ; Set top node f s %=$q(@%) q:%="" d check d kill q check ; if ($d(@("^"_%))[0)&($d(@(%("a")_$e(%,2,9999)))[0) d add q if ($d(@("^"_%))[0)&($d(@(%("a")_$e(%,2,9999)))'[0) d addcheck q if ($d(@("^"_%))'[0)&($d(@(%("a")_$e(%,2,9999)))[0) d conflict q if @("^"_%)=@% d withdraw q if @(%("a")_$e(%,2,9999))=@("^"_%) d change q d checkerr q ; add ; s @("^"_%)=@% s %("add")=$g(%("add"))+1 d withdraw q ; change ; s @("^"_%)=@% s %("change")=$g(%("change"))+1 d withdraw q ; withdraw; if $d(@(%("a")_$e(%,2,9999)))'[0 zwithdraw @(%("a")_$e(%,2,9999)) q ; conflict; u 0 w !,"WARNING: The original value for node ^",%," was not stored before" w !,"the edit session and may have changed while in the editor.",! s %("%local")=%("a")_$e(%,2,9999) w !,"old value : ",$s($d(@%("%local"))'[0:@%("%local"),1:"") w !,"current value : ",@("^"_%) w !,"edit value : ",@(%),!! w !,"Do you still wish to use the edit value? [n] " r %("ans"):30 s %("ans")=$tr(%("ans"),%("lo"),%("up")) if "\NO"[("\"_%("ans")) d withdraw q if "\YES"[("\"_%("ans")) d change q d withdraw q addcheck; u 0 w !,"WARNING: Node ^",%," was deleted while in the editor",! s %("%local")=%("a")_$e(%,2,9999) w !,"old value : ",$s($d(@%("%local"))'[0:@%("%local"),1:"") w !,"current value : " w !,"edit value : ",@(%),!! w !,"Do you still wish to use the edit value? [n] " r %("ans"):30 s %("ans")=$tr(%("ans"),%("lo"),%("up")) if "\NO"[("\"_%("ans")) d withdraw q if "\YES"[("\"_%("ans")) d add q d withdraw q checkerr; u 0 w !,"WARNING: Node ^",%," was modified while in editor",! s %("%local")=%("a")_$e(%,2,9999) w !,"old value : ",$s($d(@%("%local"))'[0:@%("%local"),1:"") w !,"current value : ",@("^"_%) w !,"edit value : ",@(%),!! w !,"Do you still wish to use the edit value? [n] " r %("ans"):30 s %("ans")=$tr(%("ans"),%("lo"),%("up")) if "\NO"[("\"_%("ans")) d withdraw q if "\YES"[("\"_%("ans")) d add q d withdraw q ; kill ; n $et s $et="s $ec="""" q" s %=(%("a")_$e(%("local"),2,9999)) if $d(@%)'[0 d killcheck f s %=$q(@%) q:%="" d killcheck q ; killcheck; if $d(@("^"_%("b")_$e(%,2,9999)))[0 s %("kill")=$g(%("kill"))+1 q if @("^"_%("b")_$e(%,2,9999))=@% zwi @("^"_%("b")_$e(%,2,9999)) s %("kill")=$g(%("kill"))+1 q u 0 w !,"killed node has changed: " w !,"node : ^",%("b")_$e(%,2,9999) w !,"old value : ",@(%("a")_$e(%,2,9999)) w !,"current value : ",@("^"_%("b")_$e(%,2,9999)) q ; nofile c $zso:delete u 0 w !,"No changes made",! q ; convert; s %("b")=$e(%("global"),2) s %("a")=$a(%("global"),2) s %("a")=%("a")+1 s %("a")=$s(%("a")=91:65,%("a")=123:97,%("a")=38:65,1:%("a")) s %("a")=$c(%("a")) q ; help i "dD"[$e(%("global"),3),$l(%("global"))=3 d ^%GD q w !,"VALID INPUT",!! w !,?3,"",?16,"to leave the %GED utility ",! w !,?4,"?D",?16,"to display existing globals in your directory ",! w !,"[global name]",?16,"the MUMPS name for the global e.g. ABC" w !?16,"the global name may be followed by: " w !?16,"subscript(s) in parentheses" w !?16,"a subscript is a MUMPS expression e.g. ""joe"",10,$e(a,1)," w !?16,"a ""*"" as a subscript causes all descendents to be included," w !?16,"or by a range of subscripts in parentheses" w !?16,"expressed as [expr]:[expr] e.g 1:10 ""a"":""d""" w !?16,"a MUMPS pattern to match selected subscripts: ^TEST(?1.3N)" q fis-gtm-V6.0-003/sr_port/gendash.m0000644000032200000250000000133512201176156015624 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; gendash ;generate sub-indices for dash type ttt's n (work,ttt,opcdcnt) f x=0:1:opcdcnt-1 d gd1 q gd1 i $d(work(x)) s ttt(x)=work(x) q i $o(work(x))\1'=x s ttt(x)=0 q s ttt(x)=ttt f i=x+.1:.1 d proc q:$o(work(i))\1'=x q proc i $d(work(i)) s ttt(ttt)=work(i) e s ttt(ttt)=0 s ttt=ttt+1 q fis-gtm-V6.0-003/sr_port/genout.m0000644000032200000250000000277412201176156015524 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001, 2007 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; genout ;output the results o outfile:newv u outfile n knt s knt=0 w "/****************************************************************",! w " *",$c(9),$c(9),$c(9),$c(9),$c(9),$c(9),$c(9),$c(9),"*",! w " *",$c(9),"Copyright 2001, ",$Zdate($H,"YEAR")," Fidelity Information Services, Inc",$c(9),"*",! w " *",$c(9),$c(9),$c(9),$c(9),$c(9),$c(9),$c(9),$c(9),"*",! w " *",$c(9),"This source code contains the intellectual property",$c(9),"*",! w " *",$c(9),"of its copyright holder(s), and is made available",$c(9),"*",! w " *",$c(9),"under a license. If you do not know the terms of",$c(9),"*",! w " *",$c(9),"the license, please stop and do not read further.",$c(9),"*",! w " *",$c(9),$c(9),$c(9),$c(9),$c(9),$c(9),$c(9),$c(9),"*",! w " ****************************************************************/",!! f i="mdef.h","vxi.h","vxt.h","xfer_enum.h" w "#include """,i,"""",! w "LITDEF short ttt[",ttt,"] = {",! f i=0:1:ttt-2 d prnt w ttt(ttt-1),"};",! c outfile q prnt i knt=0 w !,"/*",$j(i,5)," */",$c(9) w ttt(i),"," s knt=knt+1 i knt>7!(ttt(i)="VXT_END") s knt=0 q fis-gtm-V6.0-003/sr_port/get_cmd_qlf.c0000644000032200000250000001206712201176156016451 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "cmd_qlf.h" #include "cli.h" #define INIT_QUALIF_STR(QUALIF, CQCODE, FIELD) \ { \ if ((glb_cmd_qlf.qlf & CQCODE) && (MV_STR == glb_cmd_qlf.FIELD.mvtype) && (0 < glb_cmd_qlf.FIELD.str.len)) \ { \ QUALIF->FIELD.mvtype = MV_STR; \ QUALIF->FIELD.str.len = glb_cmd_qlf.FIELD.str.len; \ memcpy(QUALIF->FIELD.str.addr, glb_cmd_qlf.FIELD.str.addr, glb_cmd_qlf.FIELD.str.len); \ } \ } GBLDEF list_params lst_param; GBLREF command_qualifier glb_cmd_qlf; GBLREF boolean_t gtm_utf8_mode; void get_cmd_qlf(command_qualifier *qualif) { static readonly char upper[] = "UPPER"; static readonly char lower[] = "LOWER"; mstr *s; int4 temp_int; unsigned short len; unsigned char inbuf[255]; qualif->qlf = glb_cmd_qlf.qlf; qualif->object_file.mvtype = qualif->list_file.mvtype = qualif->ceprep_file.mvtype = 0; INIT_QUALIF_STR(qualif, CQ_OBJECT, object_file); INIT_QUALIF_STR(qualif, CQ_LIST, list_file); INIT_QUALIF_STR(qualif, CQ_CE_PREPROCESS, ceprep_file); if (gtm_utf8_mode) qualif->qlf |= CQ_UTF8; /* Mark as being compiled in UTF8 mode */ if (cli_present("OBJECT") == CLI_PRESENT) { qualif->qlf |= CQ_OBJECT; qualif->object_file.mvtype = MV_STR; s = &qualif->object_file.str; len = s->len; if (cli_get_str("OBJECT", s->addr, &len) == FALSE) { s->len = 0; if (glb_cmd_qlf.object_file.mvtype == MV_STR && glb_cmd_qlf.object_file.str.len > 0) { s->len = glb_cmd_qlf.object_file.str.len; memcpy(s->addr, glb_cmd_qlf.object_file.str.addr, s->len); } } else s->len = len; } else if (cli_negated("OBJECT") == TRUE) qualif->qlf &= ~CQ_OBJECT; if (cli_present("CROSS_REFERENCE") == CLI_PRESENT) qualif->qlf |= CQ_CROSS_REFERENCE; else if (cli_negated("CROSS_REFERENCE") == TRUE) qualif->qlf &= ~CQ_CROSS_REFERENCE; if (cli_negated("IGNORE") == TRUE) qualif->qlf &= ~CQ_IGNORE; else qualif->qlf |= CQ_IGNORE; if (cli_present("DEBUG") == CLI_PRESENT) qualif->qlf |= CQ_DEBUG; else if (cli_negated("DEBUG") == TRUE) qualif->qlf &= ~CQ_DEBUG; if (cli_negated("LINE_ENTRY") == TRUE) qualif->qlf &= ~CQ_LINE_ENTRY; if (cli_negated("INLINE_LITERALS") == TRUE) qualif->qlf &= ~CQ_INLINE_LITERALS; if (cli_negated("ALIGN_STRINGS") == TRUE) qualif->qlf &= ~CQ_ALIGN_STRINGS; #ifdef DEBUG if (cli_present("MACHINE_CODE") == CLI_PRESENT) qualif->qlf |= CQ_MACHINE_CODE; else if (cli_negated("MACHINE_CODE") == TRUE) qualif->qlf &= ~CQ_MACHINE_CODE; #else qualif->qlf &= ~CQ_MACHINE_CODE; #endif if (cli_negated("WARNINGS") == TRUE) qualif->qlf &= ~CQ_WARNINGS; else qualif->qlf |= CQ_WARNINGS; if (cli_negated("LIST") == TRUE) qualif->qlf &= (~CQ_LIST & ~CQ_MACHINE_CODE); else if (cli_present("LIST") == CLI_PRESENT) { qualif->qlf |= CQ_LIST; qualif->list_file.mvtype = MV_STR; s = &qualif->list_file.str; len = s->len; if (cli_get_str("LIST", s->addr, &len) == FALSE) { s->len = 0; if (glb_cmd_qlf.list_file.mvtype == MV_STR && glb_cmd_qlf.list_file.str.len > 0) { s->len = glb_cmd_qlf.list_file.str.len; memcpy(s->addr, glb_cmd_qlf.list_file.str.addr, s->len); } } else s->len = len; } else if (!(qualif->qlf & CQ_LIST)) qualif->qlf &= ~CQ_MACHINE_CODE; if (cli_get_int("LENGTH",&temp_int) == FALSE) temp_int = 66; lst_param.lines_per_page = temp_int; if (cli_get_int("SPACE",&temp_int) == FALSE || temp_int <= 0 || temp_int >= lst_param.lines_per_page) temp_int = 1; lst_param.space = temp_int; if (cli_present("LABELS") == CLI_PRESENT) { len = SIZEOF(inbuf); if (cli_get_str("LABELS", (char *)&inbuf[0], &len)) { if (len == SIZEOF(upper) - 1) { if (!memcmp(upper, &inbuf[0], len)) qualif->qlf &= ~CQ_LOWER_LABELS; else if (!memcmp(lower, &inbuf[0], len)) qualif->qlf |= CQ_LOWER_LABELS; } } } # ifdef UNIX if (CLI_PRESENT == cli_present("NAMEOFRTN")) qualif->qlf |= CQ_NAMEOFRTN; # endif if (cli_present("CE_PREPROCESS") == CLI_PRESENT) { qualif->qlf |= CQ_CE_PREPROCESS; qualif->ceprep_file.mvtype = MV_STR; s = &qualif->ceprep_file.str; len = s->len; if (cli_get_str("CE_PREPROCESS", s->addr, &len) == FALSE) { s->len = 0; if (glb_cmd_qlf.ceprep_file.mvtype == MV_STR && glb_cmd_qlf.ceprep_file.str.len > 0) { s->len = glb_cmd_qlf.ceprep_file.str.len; memcpy(s->addr, glb_cmd_qlf.ceprep_file.str.addr, s->len); } } else s->len = len; } else if (cli_negated("CE_PREPROCESS") == TRUE) qualif->qlf &= ~CQ_CE_PREPROCESS; # ifdef USHBIN_SUPPORTED if (CLI_PRESENT == cli_present("DYNAMIC_LITERALS")) qualif->qlf |= CQ_DYNAMIC_LITERALS; # endif } fis-gtm-V6.0-003/sr_port/get_command_line.h0000644000032200000250000000115312201176156017470 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GET_COMMAND_LINE_INCLUDED #define GET_COMMAND_LINE_INCLUDED void get_command_line(mval *result, boolean_t zcmd_line); #endif /* GET_COMMAND_LINE_INCLUDED */ fis-gtm-V6.0-003/sr_port/get_dir_root.c0000644000032200000250000000102312201176156016653 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" block_id get_dir_root(void) { return 1; } fis-gtm-V6.0-003/sr_port/get_dlr_device.c0000644000032200000250000000154712201176156017145 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "stringpool.h" GBLREF io_pair io_curr_device; void get_dlr_device(mval *v) { mstr x; char buff[128], *cp, *cend; x.len = SIZEOF(buff); x.addr = buff; (io_curr_device.in->disp_ptr->dlr_device)(&x); v->mvtype = MV_STR; v->str.addr = cp = x.addr; cend = cp + x.len; for ( ; cp < cend && *cp ; cp++) ; v->str.len = INTCAST(cp - v->str.addr); s2pool(&v->str); } fis-gtm-V6.0-003/sr_port/get_dlr_key.c0000644000032200000250000000154012201176156016467 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "stringpool.h" GBLREF io_pair io_curr_device; void get_dlr_key(mval *v) { mstr x; char buff[128], *cp, *cend; x.len = SIZEOF(buff); x.addr = buff; (io_curr_device.in->disp_ptr->dlr_key)(&x); v->mvtype = MV_STR; v->str.addr = cp = x.addr; cend = cp + x.len; for ( ; cp < cend && *cp ; cp++) ; v->str.len = INTCAST(cp - v->str.addr); s2pool(&v->str); } fis-gtm-V6.0-003/sr_port/get_dollar_stack_info.c0000644000032200000250000000264012201176156020515 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "stringpool.h" #include "error_trap.h" GBLREF spdesc stringpool; GBLREF dollar_stack_type dollar_stack; /* structure containing $STACK related information */ void get_dollar_stack_info(int level, stack_mode_t mode, mval *result) { assert(0 <= level); assert(level < dollar_stack.index); switch(mode) { case DOLLAR_STACK_MODE: result->str = dollar_stack.array[level].mode_str; break; case DOLLAR_STACK_MCODE: result->str = dollar_stack.array[level].mcode_str; break; case DOLLAR_STACK_PLACE: result->str = dollar_stack.array[level].place_str; break; case DOLLAR_STACK_ECODE: if (NULL != dollar_stack.array[level].ecode_ptr) result->str = dollar_stack.array[level].ecode_ptr->ecode_str; else { result->str.len = 0; return; } break; default: GTMASSERT; } s2pool(&result->str); assert(!result->str.len || ((unsigned char *)result->str.addr + result->str.len) == stringpool.free); return; } fis-gtm-V6.0-003/sr_port/get_frame_creation_info.c0000644000032200000250000000442712201176176021040 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "stack_frame.h" #include "stringpool.h" #include "error_trap.h" #define CREATEDBY_DO 0 #define CREATEDBY_XECUTE 1 #define CREATEDBY_FUNCTION 2 #define CREATEDBY_ZINTR 3 #define CREATEDBY_TRIGGER 4 GBLREF stack_frame *frame_pointer; GBLREF spdesc stringpool; #ifdef UNIX LITDEF mstr createdby_text[5] = {{0, LEN_AND_LIT("DO")}, {0, LEN_AND_LIT("XECUTE")}, {0, LEN_AND_LIT("$$")}, {0, LEN_AND_LIT("ZINTR")}, {0, LEN_AND_LIT("TRIGGER")}}; #endif #ifdef VMS LITDEF mstr createdby_text[4] = {{LEN_AND_LIT("DO")}, {LEN_AND_LIT("XECUTE")}, {LEN_AND_LIT("$$")}, {LEN_AND_LIT("ZINTR")}}; #endif void get_frame_creation_info(int level, int cur_zlevel, mval *result) { int count; stack_frame *fp; assert(0 < level); assert(level < cur_zlevel); count = cur_zlevel; for (fp = frame_pointer; ; fp = fp->old_frame_pointer) { if (NULL == fp->old_frame_pointer) { if (fp->type & SFT_TRIGR) /* Have a trigger baseframe, pick up stack continuation frame_pointer stored by base_frame() */ fp = *(stack_frame **)(fp + 1); else { /* Something wrong, just return null or assert if debug mode */ assert(FALSE); result->str.len = 0; return; } } assert(NULL != fp); if (!(fp->type & SFT_COUNT)) continue; count--; if (count == level) break; } assert(fp && (fp->type & SFT_COUNT)); if (fp && (fp->type & SFT_ZINTR)) result->str = createdby_text[CREATEDBY_ZINTR]; else if (fp && (fp->flags & SFF_INDCE)) result->str = createdby_text[CREATEDBY_XECUTE]; # ifdef GTM_TRIGGER else if (fp && (fp->old_frame_pointer->type & SFT_TRIGR)) result->str = createdby_text[CREATEDBY_TRIGGER]; # endif else if (fp && fp->ret_value) result->str = createdby_text[CREATEDBY_FUNCTION]; else result->str = createdby_text[CREATEDBY_DO]; } fis-gtm-V6.0-003/sr_port/get_frame_place_mcode.c0000644000032200000250000001201412201176176020443 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include #include "stack_frame.h" #include "stringpool.h" #include "error_trap.h" #include "objlabel.h" #include "cache.h" #include "cache_cleanup.h" #include "mu_gv_stack_init.h" #include "gtmimagename.h" #include "op.h" /* for op_fntext() prototype */ GBLREF stack_frame *frame_pointer; GBLREF stack_frame *error_frame; GBLREF spdesc stringpool; GBLREF dollar_ecode_type dollar_ecode; /* structure containing $ECODE related information */ GBLREF enum gtmImageTypes image_type; void get_frame_place_mcode(int level, stack_mode_t mode, int cur_zlevel, mval *result) { int count; stack_frame *fp; unsigned char pos_str[MAX_ENTRYREF_LEN]; mval label; mval routine; int ips; int offset; int s1, s2; boolean_t indirect_frame; ihdtyp *irtnhdr; cache_entry *indce; INTPTR_T *vp; unsigned char *fpmpc; assert(DOLLAR_STACK_PLACE == mode || DOLLAR_STACK_MCODE == mode); assert(0 <= level); assert(level < cur_zlevel); count = cur_zlevel; for (fp = frame_pointer; ; fp = fp->old_frame_pointer) { if (NULL == fp->old_frame_pointer) { if (fp->type & SFT_TRIGR) /* Have a trigger baseframe, pick up stack continuation frame_pointer stored by base_frame() */ fp = *(stack_frame **)(fp + 1); else { /* Something wrong, just return null or assert if debug mode */ assert(FALSE); result->str.len = 0; return; } } assert(NULL != fp); if (!(fp->type & SFT_COUNT)) continue; count--; if (count == level) break; } fpmpc = fp->mpc; if (ADDR_IN_CODE(fpmpc, fp->rvector)) { result->str.addr = (char *)&pos_str[0]; result->str.len = INTCAST(symb_line(fpmpc, &pos_str[0], 0, fp->rvector) - &pos_str[0]); indirect_frame = FALSE; } else { indirect_frame = TRUE; pos_str[0] = '@'; result->str.addr = (char *)&pos_str[0]; result->str.len = 1; } if (DOLLAR_STACK_PLACE == mode) { if (result->str.len) { s2pool(&result->str); assert(((unsigned char *)result->str.addr + result->str.len) == stringpool.free); } } if (DOLLAR_STACK_MCODE == mode) { if (!indirect_frame) { if (IS_GTM_IMAGE || (0 < level)) { label.mvtype = MV_STR; routine.mvtype = MV_STR; result->mvtype = MV_STR; label.str.len = result->str.len; label.str.addr = (char *)&pos_str[0]; routine.str.len = 0; for (ips = 0, s1 = s2 = -1; ips < result->str.len; ips++) { if ('+' == pos_str[ips]) { assert((-1 == s1) && (-1 == s2)); s1 = ips; } if ('^' == pos_str[ips]) { s2 = ips; break; } } if (s2 >= 0) { routine.str.addr = (char *)&pos_str[s2 + 1]; routine.str.len = result->str.len - s2 - 1; label.str.len = s2; } offset = 0; if (s1 >= 0) { label.str.len = s1; if (s2 < 0) s2 = result->str.len; for (ips = s1 + 1; ips < s2; ips++) offset = offset * 10 + pos_str[ips] - '0'; } op_fntext(&label, offset, &routine, result); } else { /* Utility base frame does not have source code */ result->str.addr = UTIL_BASE_FRAME_CODE; result->str.len = STRLEN(UTIL_BASE_FRAME_CODE); } } else { /* We think we are looking for an indirect invocation (mpc not in routine expected) but if the * indirect flag is not on, then it's something else and trying to dig out indirect information * is going to cause this process to explode. So some simple validation first and if it is not * an indirect, deal with that fact. */ if (fp->flags & SFF_INDCE) { /* This is a real indirect - dig a bit to find the cache header and the actual code. * Note, this code picked up from cache_cleanup(). any changes here might need to be * reflected there. */ vp = (INTPTR_T *)fp->ctxt; assert(NULL != vp); vp--; assertpro(((GTM_OMAGIC << 16) + OBJ_LABEL) == *vp); /* Validate backward linkage */ vp--; irtnhdr = (ihdtyp *)((char *)vp + *vp); indce = irtnhdr->indce; assert(NULL != indce); assert(0 < indce->refcnt); /* currently used in the M stack better have a non-zero refcnt */ s2pool(&indce->src.str); result->str = indce->src.str; assert(((unsigned char *)result->str.addr + result->str.len) == stringpool.free); } else { /* Not a real indirect. The mpc may have been reset by error handling to various assembler * routines or it just may be broken. Whatever the reason, the value to return is that the * code address and thus the code itself is not available so make an appropriate return. */ result->str.addr = "N/A"; result->str.len = SIZEOF("N/A") - 1; } } } return; } fis-gtm-V6.0-003/sr_port/get_fs_block_size.c0000644000032200000250000000340312201176156017652 0ustar librarygtc/**************************************************************** * * * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "have_crit.h" #include "eintr_wrappers.h" #include "get_fs_block_size.h" #ifndef VMS #include "gtm_statvfs.h" #endif uint4 get_fs_block_size(int fd) { # ifndef VMS struct statvfs bufvfs; int status; # endif uint4 gtm_fs_block_size; unsigned long sys_fs_block_size; # if defined(__vms) sys_fs_block_size = DISK_BLOCK_SIZE; # else FSTATVFS(fd, &bufvfs, status); assert(-1 != status); assert(SIZEOF(sys_fs_block_size) == SIZEOF(bufvfs.f_frsize)); /* If fstatvfs call fails, we dont know what the underlying filesystem size is. * We found some NFS implementations return bufvfs.f.frsize values that are inappropriate. * Instead of erroring out at this point, we assume a safe value (4K) and continue as much as we can. */ sys_fs_block_size = ((-1 == status) || (MAX_IO_BLOCK_SIZE < bufvfs.f_frsize) || (DISK_BLOCK_SIZE > bufvfs.f_frsize)) ? 4096 : bufvfs.f_frsize; # endif /* Fit file system block size in a 4-byte unsigned integer as that is the size in jnl_buffer. * Assert that we never get a block size > what can be held in a 4-byte unsigned integer. */ gtm_fs_block_size = (uint4)sys_fs_block_size; assert(gtm_fs_block_size == sys_fs_block_size); assert(MAX_IO_BLOCK_SIZE >= gtm_fs_block_size); assert(MAX_IO_BLOCK_SIZE % gtm_fs_block_size == 0); return gtm_fs_block_size; } fis-gtm-V6.0-003/sr_port/get_fs_block_size.h0000644000032200000250000000112012201176156017651 0ustar librarygtc/**************************************************************** * * * Copyright 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GET_FS_BLOCK_SIZE_INCLUDED #define GET_FS_BLOCK_SIZE_INCLUDED uint4 get_fs_block_size(int fd); #endif /* GET_FS_BLOCK_SIZE_INCLUDED */ fis-gtm-V6.0-003/sr_port/get_lmap.c0000644000032200000250000000333112201176156015767 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gdsbml.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" /* Include prototypes */ #include "t_qread.h" /* get_lmap.c: Reads local bit map and returns buffer address, two bit local bit-map value corresponding to the block, cycle and cr Input Parameter: blk: block id of the block whose bit map this routine is to fetch Output Parameter: bits: two bit local bit map cycle: Cycle value found in t_qread cr: Cache Record value found in t_qread Returns: buffer address of local bitmap block Null: if t_qread fails */ sm_uc_ptr_t get_lmap (block_id blk, unsigned char *bits, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr) { sm_uc_ptr_t ptr, bp; block_id index, offset; error_def(ERR_DSEBLKRDFAIL); index = ROUND_DOWN2(blk, BLKS_PER_LMAP); offset = blk - index; bp = t_qread (index, cycle, cr); if (bp) { ptr = bp + SIZEOF(blk_hdr) + (offset * BML_BITS_PER_BLK) / 8; *bits = *ptr; switch (blk % (8 / BML_BITS_PER_BLK)) { case 0: break; case 1: *bits = *bits >> BML_BITS_PER_BLK; break; case 2: *bits = *bits >> 2 * BML_BITS_PER_BLK; break; case 3: *bits = *bits >> 3 * BML_BITS_PER_BLK; break; } *bits = *bits & 3; } return bp; } fis-gtm-V6.0-003/sr_port/get_log_name.c0000644000032200000250000000347512201176156016630 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "io.h" #include "ident.h" #include "mmemory.h" GBLREF io_log_name *io_root_log_name; #define LOGNAME_LEN 255 io_log_name *get_log_name(mstr *v, bool insert) { io_log_name *l, *prev, *new; int4 stat; short index, v_len; unsigned char buf[LOGNAME_LEN]; error_def (ERR_INVSTRLEN); assert (io_root_log_name != 0); assert(io_root_log_name->len == 0); v_len = v->len; if (v_len == 0) return io_root_log_name; if (v_len > LOGNAME_LEN) rts_error(VARLSTCNT(4) ERR_INVSTRLEN, 2, v_len, LOGNAME_LEN); CONVERT_IDENT(buf, v->addr, v_len); for (prev = io_root_log_name, l = prev->next; l != 0; prev = l, l = l->next) { stat = memvcmp(l->dollar_io, l->len, buf, v_len); if (stat == 0) return l; if (stat > 0) break; } if (insert == INSERT) { assert(prev != 0); new =(io_log_name *) malloc(SIZEOF(*new) + v_len); memset(new, 0, SIZEOF(*new) - 1); new->len = v_len; memcpy(new->dollar_io, buf, v_len); new->dollar_io[v_len] = 0; prev->next = new; new->next = l; return new; } assert(insert == NO_INSERT); return 0; } fis-gtm-V6.0-003/sr_port/get_mladdr.c0000644000032200000250000000301612201176156016301 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "compiler.h" #include "cmd_qlf.h" #include "mmemory.h" #include "gtm_caseconv.h" #include "min_max.h" #include "stringpool.h" GBLREF mlabel *mlabtab; GBLREF command_qualifier cmd_qlf; mlabel *get_mladdr(mident *lab_name) { mident_fixed upper_ident; mident *lname, upper_lname; mlabel **p; int4 x; mstr lab_str; lname = lab_name; if (!(cmd_qlf.qlf & CQ_LOWER_LABELS)) { lower_to_upper((uchar_ptr_t)&upper_ident.c[0], (uchar_ptr_t)lab_name->addr, lab_name->len); upper_lname.len = lab_name->len; upper_lname.addr = &upper_ident.c[0]; lname = &upper_lname; } for (p = &mlabtab; *p; ) { MIDENT_CMP(&(*p)->mvname, lname, x); if (x < 0) p = &((*p)->rson); else if (x > 0) p = &((*p)->lson); else return *p; } lab_str.len = lname->len; lab_str.addr = lname->addr; s2pool_align(&lab_str); *p = (mlabel *) mcalloc(SIZEOF(mlabel)); (*p)->mvname.len = lab_str.len; (*p)->mvname.addr = lab_str.addr; assert(!(*p)->lson && !(*p)->rson); (*p)->formalcnt = NO_FORMALLIST; (*p)->gbl = TRUE; return *p; } fis-gtm-V6.0-003/sr_port/get_mmseg.c0000644000032200000250000000344712201176156016156 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "mmseg.h" GBLREF sm_uc_ptr_t min_mmseg; GBLREF sm_uc_ptr_t max_mmseg; GBLREF mmseg *mmseg_head; OS_PAGE_SIZE_DECLARE /* === get virtual address if available === */ caddr_t get_mmseg(size_t size) { mmseg *curr, *newone; sm_uc_ptr_t begin_hint, end_hint; #if defined(__osf__) && defined(__alpha) /* caddr_t should be 64 bits */ assert(8 == SIZEOF(caddr_t)); #endif if (!mmseg_head) { #if defined(__osf__) && defined(__alpha) /* Some simple initial value for Tru64 UNIX, these numbers * really should be from testing */ min_mmseg = (sm_uc_ptr_t)0x4000000000L; max_mmseg = (sm_uc_ptr_t)0x3E000000000L; #endif return (caddr_t)min_mmseg; } if ((mmseg_head->begin > min_mmseg) && (size < mmseg_head->begin - min_mmseg)) return (caddr_t)min_mmseg; curr = mmseg_head; while (curr) { end_hint = curr->next ? (sm_uc_ptr_t)curr->next->begin : max_mmseg; end_hint = (sm_uc_ptr_t)(ROUND_DOWN2((long)end_hint, OS_PAGE_SIZE)); begin_hint = (sm_uc_ptr_t)(ROUND_UP2((long)(curr->end), OS_PAGE_SIZE)); if (((unsigned long)begin_hint > (unsigned long)min_mmseg) && ((unsigned long)size < (unsigned long)end_hint - (unsigned long)begin_hint)) return (caddr_t)begin_hint; curr = curr->next; } /* Our managable virtual address space is used up, let system decide */ return (caddr_t)NULL; } fis-gtm-V6.0-003/sr_port/get_mumps_code.h0000644000032200000250000000076612201176156017207 0ustar librarygtc/**************************************************************** * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ void get_mumps_code(stack_frame *fp, mval *place, mval *mumpscode); fis-gtm-V6.0-003/sr_port/get_mvaddr.c0000644000032200000250000000273212201176156016317 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "compiler.h" #include "mmemory.h" #include "min_max.h" #include "stringpool.h" GBLREF mvar *mvartab; GBLREF mvax *mvaxtab, *mvaxtab_end; GBLREF int mvmax; mvar *get_mvaddr(mident *var_name) { mvar **p; mvax *px; mstr vname; int x; p = &mvartab; while (*p) { MIDENT_CMP(&(*p)->mvname, var_name, x); if (x < 0) p = &((*p)->rson); else if (x > 0) p = &((*p)->lson); else return *p; } /* variable doesn't exist - create a new mvar in mvartab */ vname.len = var_name->len; vname.addr = var_name->addr; s2pool_align(&vname); *p = (mvar *)mcalloc(SIZEOF(mvar)); (*p)->mvname.len = vname.len; (*p)->mvname.addr = vname.addr; (*p)->mvidx = mvmax++; (*p)->lson = (*p)->rson = NULL; (*p)->last_fetch = NULL; px = (mvax *)mcalloc(SIZEOF(mvax)); px->var = *p; px->last = px->next = 0; px->mvidx = (*p)->mvidx; if (mvaxtab_end) { px->last = mvaxtab_end; mvaxtab_end->next = px; mvaxtab_end = px; } else mvaxtab = mvaxtab_end = px; return *p; } fis-gtm-V6.0-003/sr_port/get_page_size.h0000644000032200000250000000107412201176156017013 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GET_PAGE_SIZE_INCLUDED #define GET_PAGE_SIZE_INCLUDED void get_page_size(void); #endif /* GET_PAGE_SIZE_INCLUDED */ fis-gtm-V6.0-003/sr_port/get_reference.c0000644000032200000250000000410412201176156016773 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" /* needed for gdsfhead.h */ #include "gtm_facility.h" /* needed for gdsfhead.h */ #include "fileinfo.h" /* needed for gdsfhead.h */ #include "gdsbt.h" /* needed for gdsfhead.h */ #include "gdsfhead.h" #include "stringpool.h" #include "format_targ_key.h" #include "get_reference.h" /* for get_reference() prototype */ GBLREF gv_key *gv_currkey; GBLREF spdesc stringpool; GBLREF mstr extnam_str; void get_reference(mval *var) { char *end, *start; char extnamdelim[] = "^|\"\"|"; char *extnamsrc, *extnamtop; int maxlen; /* you need to return a double-quote for every single-quote. assume worst case. */ maxlen = MAX_ZWR_KEY_SZ + (!extnam_str.len ? 0 : ((extnam_str.len * 2) + SIZEOF(extnamdelim))); ENSURE_STP_FREE_SPACE(maxlen); var->mvtype = MV_STR; start = var->str.addr = (char *)stringpool.free; var->str.len = 0; if (gv_currkey && gv_currkey->end) { if (extnam_str.len) { *start++ = extnamdelim[0]; *start++ = extnamdelim[1]; *start++ = extnamdelim[2]; extnamsrc = &extnam_str.addr[0]; extnamtop = extnamsrc + extnam_str.len; for ( ; extnamsrc < extnamtop; ) { *start++ = *extnamsrc; if ('"' == *extnamsrc++) /* caution : pointer increment side-effect */ *start++ = '"'; } *start++ = extnamdelim[3]; } end = (char *)format_targ_key((unsigned char *)start, MAX_ZWR_KEY_SZ, gv_currkey, TRUE); if (extnam_str.len) /* Note: the next vertical bar overwrites the caret that * was part of he original name of the global variable */ *start = extnamdelim[4]; var->str.len = INTCAST(end - var->str.addr); stringpool.free += var->str.len; } } fis-gtm-V6.0-003/sr_port/get_reference.h0000644000032200000250000000110712201176156017000 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GET_REFERENCE_H_INCLUDED #define GET_REFERENCE_H_INCLUDED void get_reference(mval *var); #endif /* GET_REFERENCE_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/get_ret_targ.c0000644000032200000250000000220212201176176016643 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "stack_frame.h" #include "get_ret_targ.h" GBLREF stack_frame *frame_pointer; GBLREF unsigned char *msp, *stackbase, *stacktop; /* return the target of the return for this frame; return NULL if not called as extrinsic */ mval *get_ret_targ(stack_frame **retsf) { stack_frame *sf; assert((stackbase >= msp) && (stacktop < msp)); assert(((stack_frame *)stackbase >= frame_pointer) && ((stack_frame *)stacktop < frame_pointer)); for (sf = frame_pointer; NULL != sf; sf = sf->old_frame_pointer) if (SFT_COUNT & sf->type) /* a counted frame; look no further */ { if (NULL != retsf) *retsf = sf; return sf->ret_value; } return NULL; } fis-gtm-V6.0-003/sr_port/get_ret_targ.h0000644000032200000250000000105512201176156016653 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GET_RET_TARG_H__ #define __GET_RET_TARG_H__ mval *get_ret_targ(stack_frame **retsf); #endif fis-gtm-V6.0-003/sr_port/get_root.h0000644000032200000250000000101112201176156016017 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GET_ROOT_H__ #define __GET_ROOT_H__ int get_root(void); #endif fis-gtm-V6.0-003/sr_port/get_spec.c0000644000032200000250000000234412201176156015773 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "spec_type.h" #include "get_spec.h" GBLREF gv_key *gv_altkey; GBLREF gv_namehead *gv_target; static readonly int spec_len[LAST_TYPE_DEFINED]={4,4}; uchar_ptr_t get_spec(uchar_ptr_t spec_rec_addr, int spec_rec_len, unsigned char spec_type) { uchar_ptr_t ptr, top; error_def(ERR_GVIS); error_def(ERR_INVSPECREC); for (ptr = spec_rec_addr, top = ptr + spec_rec_len; ptr < top; ptr += spec_len[*ptr]) { if (*ptr == spec_type) return ptr; else if (*ptr > LAST_TYPE_DEFINED) { gv_target->root = 0; rts_error(VARLSTCNT(6) ERR_INVSPECREC, 0, ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base); } } return (uchar_ptr_t)0; } fis-gtm-V6.0-003/sr_port/get_spec.h0000644000032200000250000000115712201176156016001 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GET_SPEC_INCLUDED #define GET_SPEC_INCLUDED uchar_ptr_t get_spec(uchar_ptr_t spec_rec_addr, int spec_rec_len, unsigned char spec_type); #endif /* GET_SPEC_INCLUDED */ fis-gtm-V6.0-003/sr_port/get_symb_line.c0000644000032200000250000000326612201176176017030 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include #include "stack_frame.h" #include "error_trap.h" /* for error_ret()/error_ret_vms() declaration */ GBLREF stack_frame *frame_pointer; GBLREF stack_frame *error_frame; GBLREF dollar_ecode_type dollar_ecode; /* structure containing $ECODE related information */ unsigned char *get_symb_line(unsigned char *out, unsigned char **b_line, unsigned char **ctxt) { boolean_t line_reset; stack_frame *fp; unsigned char *addr, *out_addr; unsigned char *fpmpc, *fpctxt; line_reset = FALSE; for (fp = frame_pointer; fp; fp = fp->old_frame_pointer) { # ifdef GTM_TRIGGER if (NULL == fp->old_frame_pointer && (fp->type & SFT_TRIGR)) /* Have a trigger baseframe, pick up stack continuation frame_pointer stored by base_frame() */ fp = *(stack_frame **)(fp + 1); # endif fpmpc = fp->mpc; fpctxt = fp->ctxt; if (ADDR_IN_CODE(fpmpc, fp->rvector)) { if (ctxt != 0) *ctxt = fpctxt; if (line_reset) addr = fpmpc + 1; else addr = fpmpc; out_addr = symb_line(addr, out, b_line, fp->rvector); assert (out < out_addr); return out_addr; } else { if (fp->type & SFT_ZTRAP || fp->type & SFT_DEV_ACT) line_reset = TRUE; } } GTMASSERT; return NULL; } fis-gtm-V6.0-003/sr_port/getjobname.c0000644000032200000250000000165112201176156016315 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "stringpool.h" #include "mvalconv.h" #include "getjobnum.h" #include "getjobname.h" GBLREF uint4 process_id; GBLDEF mval dollar_job; static char djbuff[10]; /* storage for dollar job's string form */ void getjobname(void) { getjobnum(); i2usmval(&dollar_job, process_id); n2s(&dollar_job); assert(dollar_job.str.len <= SIZEOF(djbuff)); memcpy(djbuff,dollar_job.str.addr,dollar_job.str.len); dollar_job.str.addr = djbuff; } fis-gtm-V6.0-003/sr_port/getjobname.h0000644000032200000250000000102012201176156016310 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GETJOBNAME_H__ #define __GETJOBNAME_H__ void getjobname(void); #endif fis-gtm-V6.0-003/sr_port/getjobnum.h0000644000032200000250000000101512201176156016173 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GETJOBNUM_H__ #define __GETJOBNUM_H__ void getjobnum(void); #endif fis-gtm-V6.0-003/sr_port/getprime.c0000644000032200000250000000124212201176156016012 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" int4 getprime (int4 n) /* Returns first prime # >= n */ { int m, p; for (m = n | 1 ; ; m += 2) { for (p = 3 ; ; p += 2) { if (p * p > m) return m; if (((m / p) * p) == m) break; } } } fis-gtm-V6.0-003/sr_port/getstorage.h0000644000032200000250000000106712201176156016354 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GETSTORAGE_INCLUDED #define GETSTORAGE_INCLUDED int4 getstorage(void); #endif /* GETSTORAGE_INCLUDED */ fis-gtm-V6.0-003/sr_port/getzdir.c0000644000032200000250000000160612201176156015652 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_unistd.h" #include "gtm_string.h" #include "getzdir.h" #include "setzdir.h" GBLREF mval dollar_zdir; void getzdir(void) { mval cwd; setzdir(NULL, &cwd); if (cwd.str.len > dollar_zdir.str.len) { if (NULL != dollar_zdir.str.addr) free(dollar_zdir.str.addr); dollar_zdir.str.addr = malloc(cwd.str.len); } dollar_zdir.str.len = cwd.str.len; memcpy(dollar_zdir.str.addr, cwd.str.addr, cwd.str.len); return; } fis-gtm-V6.0-003/sr_port/getzdir.h0000644000032200000250000000104412201176156015653 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GETZDIR_INCLUDED #define GETZDIR_INCLUDED void getzdir(void); #endif /* GETZDIR_INCLUDED */ fis-gtm-V6.0-003/sr_port/getzmode.h0000644000032200000250000000105012201176156016016 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GETZMODE_INCLUDED #define GETZMODE_INCLUDED void getzmode(void); #endif /* GETZMODE_INCLUDED */ fis-gtm-V6.0-003/sr_port/getzposition.c0000644000032200000250000000153412201176176016742 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "stringpool.h" #include #include "stack_frame.h" #include "getzposition.h" GBLREF spdesc stringpool; void getzposition (mval *v) { ENSURE_STP_FREE_SPACE(MAX_ENTRYREF_LEN); v->mvtype = MV_STR; v->str.addr = (char *) stringpool.free; stringpool.free = get_symb_line (stringpool.free, 0, 0); v->str.len = INTCAST((char *)stringpool.free - v->str.addr); return; } fis-gtm-V6.0-003/sr_port/getzposition.h0000644000032200000250000000107312201176156016743 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GETZPOSITION_INCLUDED #define GETZPOSITION_INCLUDED void getzposition(mval *v); #endif /* GETZPOSITION_INCLUDED */ fis-gtm-V6.0-003/sr_port/getzprocess.h0000644000032200000250000000106412201176156016555 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GETZPROCESS_INCLUDED #define GETZPROCESS_INCLUDED void getzprocess(void); #endif /* GETZPROCESS_INCLUDED */ fis-gtm-V6.0-003/sr_port/gi.mpt0000644000032200000250000000437612201176156015166 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1991, 2006 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %GI ;service@greystone.com %GO;19920722 21:35;global input ;Load globals into database ;Possible enhancements: ;selection and/or exclusion by key list, range and/or wildcard ;optional confirmation by global name ;callable entry point ; w !,"Global Input Utility",! i '$d(%zdebug) n $et s $et="zg "_$zl_":ERR^%GI" u $p:(ctrap=$c(3):exc="zg "_$zl_":EXIT^%GI") n d,g,n,sav,x,y,%ZD,fmt,ctls s ctls="" f d=1:1:31,127 s ctls=ctls_$c(d) f d q:$l(%ZD) . r !,"Input device: : ",%ZD,! . i '$l(%ZD) s %ZD=$p q . i %ZD="^" q . i %ZD="?" d q . . w !!,"Select the device you want for input" . . w !,"If you wish to exit enter a caret (^)",! . . s %ZD="" . i $zparse(%ZD)="" w " no such device" s %ZD="" q . o %ZD:(readonly:block=2048:record=2044:exception="g noopen"):0 . i '$t w !,%ZD," is not available" s %ZD="" q . q noopen . w !,$p($ZS,",",2,999),! c %ZD s %ZD="" q:%ZD="^" w !! s sav="",(g,n)=0 u %ZD:exception="g eof" r x,y u $p w !,x,!,y,!! u $p r !,"OK ? ",x,!! i $l(x),$e("NO",1,$l(x))=$tr(x,"no","NO") c:%ZD'=$p %ZD u $p:(ctrap="":exc="") q s fmt=y["ZWR" i (fmt) f u %ZD r x q:x="" d . s @x,n=n+1,x=$p($p(x,"="),"(") i x'=sav,x'="^" d . . s g=g+1,sav=x . . u $p w:$x>70 ! w x,?$x\10+1*10 i ('fmt) f u %ZD r x,y i "*"'[$e(x) d . i $tr(x,ctls,"")'=x d ;convert control chars to $C(x) exprs . . n c,cp,nx s nx="" . . f cp=1:1:$l(x) d . . . s c=$e(x,cp),nx=nx_$s(ctls[c:"""_$c("_$a(c)_")_""",1:c) . . s x=nx ;use fixed 'x' . s @x=y . s n=n+1,x=$p(x,"(") . i x'=sav,x'="^" d . . s g=g+1,sav=x . . u $p w:$x>70 ! w x,?$x\10+1*10 eof u $p w !!,"Restored ",n," node",$s(n=1:"",1:"s") w " in ",g," global",$s(g=1:".",1:"s.") c:%ZD'=$p %ZD u $p:(ctrap="":exc="") q ; ERR u $p w !,$p($zs,",",2,99),! ; Warning - Fall-though s $ec="" EXIT i $d(%ZD),%ZD'=$p c %ZD u $p:(ctrap="":exc="") q fis-gtm-V6.0-003/sr_port/global_map.c0000644000032200000250000000631612201176156016302 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "global_map.h" #include "min_max.h" /* "map[]" is assumed to be an array of mstrs whose last mstr has a NULL value for its "addr" field. * "map[]" contains even number of mstrs, each consecutive pair of mstrs (starting from map[0]) point to a range of names. * Also "map[]" is an array of strings arranged in non-decreasing alphabetical order. * Thus "map[]" is an array representing a set of ranges starting from the smallest to the largest. * "beg" and "end" are the end-points of the range (both inclusive) to be inserted into this sorted range set. * Note that a point is represented as a range whose begin and end are the same. */ void global_map(mstr map[], mstr *beg, mstr *end) { mstr *left, *right, rangestart, rangeend, tmpmstr; int rslt; DEBUG_ONLY( MSTRP_CMP(beg, end, rslt); assert(0 >= rslt); ) for (left = map; left->addr; left++) { MSTRP_CMP(left, beg, rslt); if (0 <= rslt) break; } /* left now points to the first mstr in the array that is >= beg */ for (right = left; right->addr; right++) { MSTRP_CMP(right, end, rslt); if (0 < rslt) break; } /* right now points to the first mstr in the array that is > end */ if (left == right) { /* the usual case where {beg, end} has no or complete intersections with any existing range in map[]. * in the case of complete intersection return. * in case of no intersection, insert {beg, end} maintaining sorted order by shifting all higher existing ranges * two positions to the right */ if ((right - map) & 1) return; rangestart = *beg; rangeend = *end; while (left->addr) { /* {rangestart, rangeend} is the current range to be inserted */ tmpmstr = *left; *left++ = rangestart; rangestart = tmpmstr; tmpmstr = *left; *left++ = rangeend; rangeend = tmpmstr; } *left++ = rangestart; *left++ = rangeend; left->addr = 0; return; } /* case where {beg, end} has partial intersections with existing ranges in map[]. * replace intersecting ranges with one union range e.g. replace {1, 10} {5, 15} {12, 20} with {1, 20} */ if (0 == ((left - map) & 1)) *left++ = *beg; if (0 == ((right - map) & 1)) *(--right) = *end; if (left == right) /* possible if {beg, end} is exactly equal to an existing range in map[] */ return; do { *left++ = *right; } while ((right++)->addr); /* note that replacing atleast 2 existing ranges with {begin, end} into one union range will cause a reduction * in the number of ranges in map[] effectively causing higher-valued ranges on the right to shift left. * In that case, we have to be also left-shift the null-valued mstr.addr, hence the ++ is done in the check * for (right++)->addr in the "while" above instead of having "*left++ = *right++" in the loop. */ return; } fis-gtm-V6.0-003/sr_port/global_map.h0000644000032200000250000000111412201176156016276 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GLOBAL_MAP_INCLUDED #define GLOBAL_MAP_INCLUDED void global_map(mstr map[], mstr *beg, mstr *end); #endif /* GLOBAL_MAP_INCLUDED */ fis-gtm-V6.0-003/sr_port/glvn.c0000644000032200000250000000277112201176156015154 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "mdq.h" #include "fullbool.h" error_def(ERR_VAREXPECTED); int glvn(oprtype *a) { triple *oldchain, *ref; oprtype x1; save_se save_state; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; switch (TREF(window_token)) { case TK_IDENT: if (!lvn(a,OC_GETINDX,0)) return FALSE; return TRUE; case TK_CIRCUMFLEX: if (!gvn()) return FALSE; *a = put_tref(newtriple(OC_GVGET)); return TRUE; case TK_ATSIGN: if (SHIFT_SIDE_EFFECTS) { START_GVBIND_CHAIN(&save_state, oldchain); if (!indirection(&x1)) { setcurtchain(oldchain); return FALSE; } ref = newtriple(OC_INDGLVN); PLACE_GVBIND_CHAIN(&save_state, oldchain); } else { if (!indirection(&x1)) return FALSE; ref = newtriple(OC_INDGLVN); } if (TREF(expr_depth)) (TREF(side_effect_base))[TREF(expr_depth)] = (OLD_SE != TREF(side_effect_handling)); ref->operand[0] = x1; *a = put_tref(ref); return TRUE; default: stx_error(ERR_VAREXPECTED); return FALSE; } } fis-gtm-V6.0-003/sr_port/glvn_pool.c0000644000032200000250000000620212201176176016200 0ustar librarygtc/**************************************************************** * * * Copyright 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "gtm_stdio.h" #include "min_max.h" #include "lv_val.h" #include #include "mv_stent.h" #include "compiler.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "opcode.h" #include "glvn_pool.h" #include "parm_pool.h" /* for CAPACITY_ROUND_UP2 macro */ void glvn_pool_init(void) { glvn_pool *pool; uint4 capacity, mval_capacity, slotoff; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; capacity = INIT_GLVN_POOL_CAPACITY; mval_capacity = INIT_GLVN_POOL_MVAL_CAPACITY; slotoff = (uint4)OFFSETOF(glvn_pool, slot[0]); pool = (glvn_pool *)malloc(ROUND_UP(slotoff, (capacity + 1) * SIZEOF(glvn_pool_entry))); pool->mval_stack = (mval *)malloc(mval_capacity * SIZEOF(mval)); pool->capacity = capacity; pool->top = 0; pool->mval_capacity = mval_capacity; pool->mval_top = 0; memset(pool->for_slot, (int)GLVN_POOL_EMPTY, (MAX_FOR_STACK + 1) * SIZEOF(uint4)); TREF(glvn_pool_ptr) = pool; } void glvn_pool_expand_slots(void) { glvn_pool *pool, *old_pool; uint4 capacity, slotoff; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; old_pool = TREF(glvn_pool_ptr); capacity = 2 * old_pool->capacity; assert(capacity <= MAX_EXPECTED_CAPACITY); /* Don't expect more than this in the test system */ slotoff = (uint4)OFFSETOF(glvn_pool, slot[0]); pool = (glvn_pool *)malloc(ROUND_UP(slotoff, (capacity + 1) * SIZEOF(glvn_pool_entry))); memcpy(pool, old_pool, slotoff + old_pool->top * SIZEOF(glvn_pool_entry)); pool->capacity = capacity; TREF(glvn_pool_ptr) = pool; free(old_pool); } void glvn_pool_expand_mvals(void) { glvn_pool *pool; glvn_pool_entry *slot, *top; int i, n; mval *mval_stack, *old_mval_stack; uint4 mval_capacity; INTPTR_T shift; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; pool = TREF(glvn_pool_ptr); mval_capacity = 2 * pool->mval_capacity; assert(mval_capacity <= MAX_EXPECTED_MVAL_CAPACITY); /* Don't expect more than this in the test system */ old_mval_stack = pool->mval_stack; mval_stack = (mval *)malloc(mval_capacity * SIZEOF(mval)); memcpy(mval_stack, old_mval_stack, pool->mval_top * SIZEOF(mval)); shift = (INTPTR_T)mval_stack - (INTPTR_T)old_mval_stack; for (slot = pool->slot, top = slot + pool->top - 1; slot < top; slot++) { /* Touch up glvn_info pointers, but leave lvn start alone */ n = slot->glvn_info.n; assert(n <= MAX_ACTUALS); if (FIRST_SAVED_ARG(slot)) slot->lvname = (mval *)(shift + (char *)slot->lvname); for (i = FIRST_SAVED_ARG(slot); i < n; i++) slot->glvn_info.arg[i] = (void *)(shift + (char *)slot->glvn_info.arg[i]); } pool->mval_stack = mval_stack; pool->mval_capacity = mval_capacity; free(old_mval_stack); } fis-gtm-V6.0-003/sr_port/glvn_pool.h0000644000032200000250000001554512201176156016215 0ustar librarygtc/**************************************************************** * * * Copyright 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GLVN_POOL_H_INCLUDED #define GLVN_POOL_H_INCLUDED #include "callg.h" #include "compiler.h" #include "lv_val.h" /* Here we provide tools for saving identifying information of local or global variables. For local variables this includes * the variable name itself, as well as copies of each subscript. For global variables we save each argument that needs to * be later passed into op_gvname/op_gvnaked/op_gvextnam. Note that deferring the op_gvnaked call allows us to achieve * correct naked indicator flow. For example, in the command SET @"^(subs)"=rhs, the ^() needs to be evaluated relative to * the expression on the right hand side, and the right hand side needs to happen AFTER the subscripts have been evaluated. * The structure involved - the "glvn pool" - consists of a stack of entries, each corresponding to a single glvn, and * a parallel stack of mvals, each corresponding to some parent entry. Both stacks are expandable, doubling in size whenever * they run out of space. The glvn pool entries can be popped in three different ways. For SET, it's convenient to save the * glvn pool state, i.e. the top of the array of still-relevant entries. After completion of the set, the pool is restored to * this state and younger entries popped. With FOR, it's more convenient defer popping until another FOR loop at the same * nesting level starts. At that time the previously used FOR slot is recycled and everything younger than it is popped. * Finally, when a non-indirect frame is unwound, all younger pool entries are popped. */ #define ANY_SLOT 0 #define FIRST_SAVED_ARG(SLOT) ((OC_SAVLVN == (SLOT)->sav_opcode) ? 1 : 0) /* To avoid breaking gtmpcat, we retain the 'for_ctrl_stack' field of the frame_pointer struct instead of replacing it * with a uint4 'glvn_indx' field. The macros manipulate this field. Also for the convenience of gtmpcat: we declare the * glvn_pool and glvn_pool_entry structs in compiler.h instead of here. This is because gtmpcat does not know to include * glvn_pool.h when going through gtm_threadgbl_defs.h. * When gtmpcat is changed to accommodate a new name, these macros and the stack frame struct need to be changed, * and the glvn_pool structs in compiler.h should probably be moved into this file. */ #define GLVN_INDX(FP) ((uint4)(UINTPTR_T)((FP)->for_ctrl_stack)) #define GLVN_POOL_EMPTY ((uint4)-1) /* this must be an "impossible" value for a real pool */ #define GLVN_POOL_SLOTS_AVAILABLE ((TREF(glvn_pool_ptr))->capacity - (TREF(glvn_pool_ptr))->top) #define GLVN_POOL_MVALS_AVAILABLE ((TREF(glvn_pool_ptr))->mval_capacity - (TREF(glvn_pool_ptr))->mval_top) #define INIT_GLVN_POOL_CAPACITY 8 #define INIT_GLVN_POOL_MVAL_CAPACITY 64 #define GLVN_POOL_UNTOUCHED 0 #define MAX_EXPECTED_CAPACITY 2048 #define MAX_EXPECTED_MVAL_CAPACITY 2048 #define SLOT_NEEDS_REWIND(INDX) (((TREF(glvn_pool_ptr))->top <= (INDX)) && (GLVN_POOL_EMPTY != (INDX))) #define SLOT_OPCODE(INDX) ((TREF(glvn_pool_ptr))->slot[INDX].sav_opcode) #define SET_GLVN_INDX(FP, VALUE) \ { \ (FP)->for_ctrl_stack = (unsigned char *)(UINTPTR_T)(VALUE); \ } #define GLVN_POOL_EXPAND_IF_NEEDED \ { \ if (!TREF(glvn_pool_ptr)) \ glvn_pool_init(); \ else if (!GLVN_POOL_SLOTS_AVAILABLE) \ glvn_pool_expand_slots(); \ } #define ENSURE_GLVN_POOL_SPACE(SPC) \ { \ if (GLVN_POOL_MVALS_AVAILABLE < (uint4)(SPC)) \ { \ glvn_pool_expand_mvals(); \ assert(GLVN_POOL_MVALS_AVAILABLE >= (uint4)(SPC)); \ } \ } #define GET_GLVN_POOL_STATE(SLOT, M) \ { /* Find current available SLOT and mval. */ \ uint4 INDX, MVAL_INDX; \ \ INDX = (TREF(glvn_pool_ptr))->share_slot; \ SLOT = &(TREF(glvn_pool_ptr))->slot[INDX]; \ MVAL_INDX = SLOT->mval_top; \ M = &(TREF(glvn_pool_ptr))->mval_stack[MVAL_INDX]; \ } #define DRAIN_GLVN_POOL_IF_NEEDED \ { \ int I; \ uint4 INDX, FINDX; \ glvn_pool_entry *SLOT; \ \ if ((GLVN_POOL_UNTOUCHED != GLVN_INDX(frame_pointer)) && !(frame_pointer->flags & SFF_INDCE)) \ { /* Someone used an ugly FOR control variable or did an indirect set. */ \ INDX = (GLVN_POOL_EMPTY != GLVN_INDX(frame_pointer)) ? GLVN_INDX(frame_pointer) : 0; \ op_glvnpop(INDX); \ for (I = 1; I <= MAX_FOR_STACK; I++) \ { /* rewind the for_slot array */ \ FINDX = (TREF(glvn_pool_ptr))->for_slot[I]; \ if (SLOT_NEEDS_REWIND(FINDX)) \ { /* reset to precursor */ \ SLOT = &(TREF(glvn_pool_ptr))->slot[FINDX]; \ assert(!SLOT_NEEDS_REWIND(SLOT->precursor)); \ (TREF(glvn_pool_ptr))->for_slot[I] = SLOT->precursor; \ } else /* no higher FOR levels were used by current frame */ \ break; \ } \ } \ } #define INSERT_INDSAVGLVN(CTRL, V, RECYCLE, DO_REF) \ { \ triple *PUSH, *SAV, *PAR; \ \ PUSH = newtriple(OC_GLVNSLOT); \ PUSH->operand[0] = put_ilit((mint)(RECYCLE)); \ CTRL = put_tref(PUSH); \ SAV = newtriple(OC_INDSAVGLVN); \ SAV->operand[0] = V; \ PAR = newtriple(OC_PARAMETER); \ SAV->operand[1] = put_tref(PAR); \ PAR->operand[0] = CTRL; \ PAR->operand[1] = put_ilit((mint)(DO_REF)); /* flag to suppress global reference here */ \ } void glvn_pool_init(void); /* invoked via GLVN_POOL_EXPAND_IF_NEEDED macro */ void glvn_pool_expand_slots(void); /* invoked via GLVN_POOL_EXPAND_IF_NEEDED macro */ void glvn_pool_expand_mvals(void); /* invoked via ENSURE_GLVN_POOL_SPACE macro */ void op_glvnpop(uint4 indx); /* Used by [SET and $ORDER()] */ uint4 op_glvnslot(uint4 recycle); /* Used by [FOR, SET and $ORDER()] */ void op_indsavglvn(mval *target, uint4 slot, uint4 do_ref); /* Used by [SET and $ORDER()] */ void op_indsavlvn(mval *target, uint4 slot); /* Used by [FOR] */ void op_rfrshgvn(uint4 indx, opctype oc); /* Used by [SET and $ORDER()] */ lv_val *op_rfrshlvn(uint4 indx, opctype oc); /* Used by [FOR, SET and $ORDER()] */ void op_savgvn(UNIX_ONLY_COMMA(int argcnt) mval *val_arg, ...); /* Used by [SET and $ORDER()] */ void op_savlvn(UNIX_ONLY_COMMA(int argcnt) lv_val *start, ...); /* Used by [FOR, SET and $ORDER()] */ void op_shareslot(uint4 indx, opctype opcode); /* Used by [FOR, SET and $ORDER()] */ void op_stoglvn(uint4 indx, mval *value); /* Used by [SET] */ #endif /* GLVN_POOL_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/go.mpt0000644000032200000250000000565512201176156015175 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1987, 2008 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %GO ;service@greystone.com %GO;19920722 21:15;global output ;Extracts global data to standard global output (GO) file ;Invoke ^%GO to get interaction ;possible enhancements: ;selection by key list, range and/or wildcard, rather than global name ;callable entry point ; w !,"Global Output Utility",! i '$d(%zdebug) n $et s $et="zg "_$zl_":ERR^%GO" u $p:(ctrap=$c(3):exc="zg "_$zl_":EXIT^%GO") n g,gn,m,n,%ZD,%ZG,%ZH,fmt,fmtdone d ^%GSEL i %ZG=0 w !,"No globals selected" q r !,"Header Label: ",%ZH,! r !,"Output Format: GO or ZWR: ",fmt,! i (fmt="")!($e("ZWR",1,$l(fmt))=$tr(fmt,"zwr","ZWR")) s fmt=1 e s fmt=0 f d q:$l(%ZD) . r !,"Output device: : ",%ZD,! . i '$l(%ZD) s %ZD=$p q . i %ZD="^" q . i %ZD="?" d q . . w !!,"Select the device you want for output" . . w !,"If you wish to exit enter a carat (^)",! . . s %ZD="" . i $zparse(%ZD)="" w " no such device" s %ZD="" q . o %ZD:(newversion:block=2048:record=2044:exception="g noopen"):0 . i '$t w !,%ZD," is not available" s %ZD="" q . q noopen . w !,$p($ZS,",",2,999),! c %ZD s %ZD="" q:%ZD="^" w !! i '$l(%ZH) s %ZH="%GO Global Output Utility" u %ZD w %ZH w:"M"'=$ZCHSET " ",$ZCHSET w !,"GT.M ",$zd($h,"DD-MON-YEAR 24:60:SS") w:fmt " ZWR" w ! s gn="",(m,n)=0 f s gn=$o(%ZG(gn)) q:gn="" s g=gn d . s fmtdone=0 . u $p w:$x>70 ! w gn,?$x\10+1*10 u %ZD i $p=%ZD w ! . s m=m+1 . i $d(@g)'[0 d s n=n+1 . . i fmt zwr @g s fmtdone=1 . . e w g,!,@g,! . f s g=$q(@g) q:g="" d . . i fmt zwr:'fmtdone @g ; don't zwr if already done for unsubscripted global. It takes care for subscripts too . . e w g,!,@g,! . . s n=n+1 u %ZD w !! u $p w !!,"Total of ",n," node",$s(n=1:"",1:"s") w " in ",m," global",$s(m=1:".",1:"s."),!! c:%ZD'=$p %ZD u $p:(ctrap="":exc="") q fw(s) ; variables used in this function are: fwlen, s, cc, fastate, isctl, i, thistime ; initialize this procedure s fwlen=$l(s) i fwlen=0 w ! q i s=+s w s,! q s cc=$e(s) i cc?1C w "$C(",$a(cc) s fastate=2 e w """",cc w:cc="""" cc s fastate=1 ; start the loop to deal with the whole string. f i=2:1:fwlen s cc=$e(s,i,i),isctl=cc?1C d . s thistime=1 . if fastate=1 d . . if (isctl) w """_$C(",$a(cc) s fastate=2,thistime=0 . . else w cc w:cc="""" cc . if (fastate=2)&thistime d . . if (isctl)!(cc="""") w ",",$a(cc) . . else w ")_""",cc s fastate=1 if fastate=1 w """",! else w ")",! q ; ERR u $p w !,$p($zs,",",2,99),! ; Warning - Fall-though s $ec="" EXIT i $d(%ZD),%ZD'=$p c %ZD u $p:(ctrap="":exc="") q fis-gtm-V6.0-003/sr_port/goerrorframe.c0000644000032200000250000000333112201176176016673 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include #include "stack_frame.h" #include "tp_frame.h" #include "golevel.h" #include "error.h" #include "error_trap.h" #ifdef GTM_TRIGGER #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gv_trigger.h" #include "gtm_trigger.h" #endif GBLREF stack_frame *frame_pointer; GBLREF stack_frame *error_frame; void goerrorframe() { stack_frame *fp, *fpprev; int4 unwind; for (unwind = 0, fp = frame_pointer; fp < error_frame; fp = fpprev) { fpprev = fp->old_frame_pointer; # ifdef GTM_TRIGGER if (SFT_TRIGR & fpprev->type) { fpprev = *(stack_frame **)(fpprev + 1); unwind++; /* Skipping over trigger frame but it needs unwinding too */ } # endif unwind++; assert(fpprev); } assert(fp == error_frame); DBGEHND((stderr, "goerrorframe: Unwinding %d frames\n", unwind)); GOFRAMES(unwind, FALSE, FALSE); assert(error_frame == frame_pointer); /* Now that we (the caller mdb_condition_handler) are going to rethrow an error, ensure that the * SFF_ETRAP_ERR bit is set in "error_frame" in case it got reset by flush_jmp. */ SET_ERROR_FRAME(error_frame); assert(error_frame->flags & SFF_ETRAP_ERR); return; } fis-gtm-V6.0-003/sr_port/goframes.c0000644000032200000250000000650112201176176016006 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include /* needed for golevel.h */ #include "error.h" #include "op.h" #include "stack_frame.h" /* needed for golevel.h */ #include "tp_frame.h" /* needed for golevel.h */ #include "golevel.h" #ifdef GTM_TRIGGER #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gdscc.h" #include "gdskill.h" #include "jnl.h" #include "gv_trigger.h" #include "gtm_trigger.h" #include "get_ret_targ.h" GBLREF boolean_t goframes_unwound_trigger; #endif GBLREF boolean_t skip_error_ret; GBLREF tp_frame *tp_pointer; GBLREF stack_frame *frame_pointer; LITREF mval literal_null; #ifdef GTM_TRIGGER void goframes(int4 frames, boolean_t unwtrigrframe, boolean_t fromzgoto) #else void goframes(int4 frames) #endif { mval *ret_targ; GTMTRIG_ONLY(goframes_unwound_trigger = FALSE); for (ret_targ = NULL; frames--; ) { while (tp_pointer && tp_pointer->fp <= frame_pointer) { OP_TROLLBACK(-1); } if (0 == frames) { ret_targ = (mval *)get_ret_targ(NULL); if (NULL != ret_targ) { *ret_targ = literal_null; ret_targ->mvtype |= MV_RETARG; } } skip_error_ret = TRUE; # ifdef GTM_TRIGGER if (!(SFT_TRIGR & frame_pointer->type)) { /* Normal frame unwind */ DBGTRIGR((stderr, "goframes: unwinding regular frame at %016lx\n", frame_pointer)); op_unwind(); DBGTRIGR((stderr, "goframes: after regular frame unwind: frame_pointer 0x%016lx ctxt value: 0x%016lx\n", frame_pointer, ctxt)); } else { /* Trigger base frame unwind (special case) */ DBGTRIGR((stderr, "goframes: unwinding trigger base frame at %016lx\n", frame_pointer)); gtm_trigger_fini(TRUE, fromzgoto); goframes_unwound_trigger = TRUE; } # else /* If triggers are not enabled, just a normal unwind */ DBGEHND((stderr, "goframes: unwinding regular frame at %016lx\n", frame_pointer)); op_unwind(); # endif assert(FALSE == skip_error_ret); /* op_unwind() should have read and reset this */ skip_error_ret = FALSE; /* be safe in PRO versions */ } # ifdef GTM_TRIGGER if (unwtrigrframe && (SFT_TRIGR & frame_pointer->type)) { /* If we landed on a trigger base frame after unwinding everything, we are in the same boat as if we had run into * one while we were unwinding. We cannot return this frame to (for example) zgoto which is going to morph it into * something else (unwtrigrframe only set when ZGOTO with entryref specified). So if the flag says we should never * land on a trigger frame, go ahead and unwind that one too. */ DBGTRIGR((stderr, "goframes: unwinding trailing trigger base frame at %016lx\n", frame_pointer)); gtm_trigger_fini(TRUE, fromzgoto); goframes_unwound_trigger = TRUE; } # endif return; } fis-gtm-V6.0-003/sr_port/golevel.h0000644000032200000250000000344212201176156015644 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GOLEVEL_H__ #define __GOLEVEL_H__ /* golevel() will unwind up to the counted frame corresponding to level specified by the parm. The first flag indicates * whether or not it is ok to land on a $ZINTERRUPT frame or not (which it is not ok when unwinding a $ZINTERRUPT). Also, * In a trigger environment, an additional flag that determines if landing on a trigger frame means the unwind should * continue or not is supplied. This flag is passed to goframes() which does the actual unwind of a specific number of * rames (counted and uncounted). Note goframes is used by both golevel and goerrorframe. */ #ifdef GTM_TRIGGER #define GOLEVEL(level, unwtrigrframe) golevel(level, unwtrigrframe) #define GOFRAMES(frames, unwtrigrframe, fromzgoto) goframes(frames, unwtrigrframe, fromzgoto) void golevel(int4 level, boolean_t unwtrigrframe); void goframes(int4 frames, boolean_t unwtrigrframe, boolean_t fromzgoto); #else #define GOLEVEL(level, unwtrigrframe) golevel(level) #define GOFRAMES(frames, unwtrigrframe, fromzgoto) goframes(frames) void golevel(int4 level); /* unwind upto the counted frame corresponding to frame level "level" */ void goframes(int4 frames); /* unwind "frames" number of frames */ #endif void goerrorframe(void); /* unwind upto (but not including) the frame pointed to by the "error_frame" * global */ #endif fis-gtm-V6.0-003/sr_port/gsel.mpt0000644000032200000250000000700412201176156015510 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1987, 2006 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %GSEL ;GT.M %GSEL utility - global select into a local array ;invoke ^%GSEL to create %ZG - a local array of existing globals, interactively ; n add,beg,cnt,end,g,gd,gdf,k,out,pat,stp,i,c,g1 i '$d(%zdebug) n $et s $et="zg "_$zl_":ERR^%GSEL" u $p:(ctrap=$c(3):exc="zg "_$zl_":LOOP^%GSEL") d init,main u $p:(ctrap="":exc="") q GD n add,beg,cnt,end,g,gd,gdf,k,out,pat,stp s cnt=0,(out,gd,gdf)=1 d main i gdf s %ZG="*" d setup,it w !,"Total of ",cnt," global",$s(cnt=1:".",1:"s."),! q CALL n add,beg,cnt,end,g,gd,gdf,k,out,pat,stp,i,c,g1 s (cnt,gd)=0 i $d(%ZG)>1 s g="" f s g=$o(%ZG(g)) q:'$l(g) s cnt=cnt+1 i $g(%ZG)'?.N s out=0 d setup,it s %ZG=cnt q s out=1 d main q init k %ZG s (cnt,gd)=0,out=1 q main f d inter q:'$l(%ZG) s %ZG=cnt q inter r !,"Global ^",%ZG,! q:'$l(%ZG) i $e(%ZG)="?",$l(%ZG)=1 d help q i (%ZG="?D")!(%ZG="?d") d cur q d setup,it w !,$s(gd:"T",1:"Current t"),"otal of ",cnt," global",$s(cnt=1:".",1:"s."),! q setup i gd s add=1,cnt=0,g=%ZG k %ZG s %ZG=g e i "'-"[$e(%ZG) s add=0,g=$e(%ZG,2,999) e s add=1,g=%ZG s g=$tr(g,"? !""#$&'()+'-./;<=>@[]\^_`{}|~","%") s g=$tr(g,$c(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,127)) s g1="" f i=1:1:$l(g) s c=$e(g,i) if $a(c)<128 s g1=g1_c ; Filter out "all" non-ascii characters (be it M or UTF-8) s g=g1 s end=$p(g,":",2),beg=$p(g,":") i end=beg s end="" q it s gdf=0 i end'?."*",end']beg q s g=beg d pat i pat["""" d start f d search q:'$l(g) d save i pat["""",'$l(end) q s beg=stp i '$l(g) s g=stp s pat=".E",stp="^"_$e(end)_$tr($e(end,2,9999),"%","z") d start f d search q:'$l(g) d save s g=end d pat i pat["""" s:beg]g g=beg d start f d search q:'$l(g) d save q pat n tmpstp i $e(g)="%" s g="!"_$e(g,2,9999) s pat=g f q:$l(g,"%")<2 s g=$p(g,"%",1)_"#"_$p(g,"%",2,999),pat=$p(pat,"%",1)_"""1E1"""_$p(pat,"%",2,999) f q:$l(g,"*")<2 s g=$p(g,"*",1)_"$"_$p(g,"*",2,999),pat=$p(pat,"*",1)_""".E1"""_$p(pat,"*",2,999) i $e(g)="!" s g="%"_$e(g,2,9999),pat="%"_$e(pat,2,9999) i pat["""" s pat="1""^"_pat_"""" s tmpstp="z",$p(tmpstp,"z",30)="z" s g="^"_$p($p(g,"#"),"$"),stp=g_$e(tmpstp,$l(g)-1,31) q start i g="^" s g="^%" i g?@pat,$d(@g) d save q search f s g=$o(@g) s:g]stp g="" q:g?@pat!'$l(g) q save i add,'$d(%ZG(g)) s %ZG(g)="",cnt=cnt+1 d prt:out i 'add,$d(%ZG(g)) k %ZG(g) s cnt=cnt-1 d prt:out q prt w:$x>70 ! w g,?$x\10+1*10 q help ; w !,?2,"",?25,"to leave",!,?2,"""*""",?25,"for all" w !,?2,"global",?25,"for 1 global" w !,?2,"global1:global2",?25,"for a range" w !,?2,"""*"" as a wildcard",?25,"permitting any number of characters" w !,?2,"""%"" as a wildcard",?25,"for a single character in positions other than the first" w !,?2,"""?"" as a wildcard",?25,"for a single character in positions other than the first" i gd q w !,?2,"""'"" as the 1st character",!,?25,"to remove globals from the list" w !,?2,"?D",?25,"for the currently selected globals",! q cur w ! s g="" f s g=$o(%ZG(g)) q:'$l(g) w:$x>70 ! w g,?($x\10+1*10) q ERR u $p w !,$p($ZS,",",2,999),! u $p:(ctrap="":exc="") s $ec="" q LOOP d main u $p:(ctrap="":exc="") q fis-gtm-V6.0-003/sr_port/gtm_assert.c0000644000032200000250000000314612201176156016353 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_assert - invoked via the "GTMASSERT" macro. * * gtm_assert raises the ERR_GTMASSERT error condition which is * intended to be a replacement for the ubiquitous ERR_GTMCHECK. BYPASSOK * It differs from ERR_GTMCHECK in that it indicates the module BYPASSOK * name and line number of its invocation so one can determine * exactly which ERR_GTMASSERT caused the termination. * * The "GTMASSERT" macro differs from the "assert" macro in that * it is significant regardless of the definition or lack thereof * of the macro "DEBUG" and is therefore valid for PRO images as * well as for DBG and BTA images. * * Note that the assertpro() macro is preferred in most instances where a specific condition * is being tested. */ #include "mdef.h" #include "send_msg.h" LITREF char gtm_release_name[]; LITREF int4 gtm_release_name_len; error_def(ERR_GTMASSERT); void gtm_assert(int file_name_len, char file_name[], int line_no) { send_msg (VARLSTCNT(7) ERR_GTMASSERT, 5, gtm_release_name_len, gtm_release_name, file_name_len, file_name, line_no); rts_error (VARLSTCNT(7) ERR_GTMASSERT, 5, gtm_release_name_len, gtm_release_name, file_name_len, file_name, line_no); } fis-gtm-V6.0-003/sr_port/gtm_assert2.c0000644000032200000250000000267012201176156016436 0ustar librarygtc/**************************************************************** * * * Copyright 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_assert2 - invoked via the "assertpro" macro. * * gtm_assert2 is driven by the assertpro() macro which is intended to be a replacement for * most instances of the GTMASSERT macro which gave no indication of the cause of the GTMASSERT * error. The GTMASSERT2 message output from this routine also contains the failing assertpro() * text very similar to what the ASSERT error does. */ #include "mdef.h" #include "send_msg.h" LITREF char gtm_release_name[]; LITREF int4 gtm_release_name_len; error_def(ERR_GTMASSERT2); int gtm_assert2(int condlen, char *condtext, int file_name_len, char file_name[], int line_no) { send_msg(VARLSTCNT(9) ERR_GTMASSERT2, 7, gtm_release_name_len, gtm_release_name, file_name_len, file_name, line_no, condlen, condtext); rts_error(VARLSTCNT(9) ERR_GTMASSERT2, 7, gtm_release_name_len, gtm_release_name, file_name_len, file_name, line_no, condlen, condtext); return 0; /* Required for assertpro() macro which assumes (syntactically) this rtn returns a result */ } fis-gtm-V6.0-003/sr_port/gtm_bintim.h0000644000032200000250000000111112201176156016327 0ustar librarygtc/**************************************************************** * * * Copyright 2003 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_BINTIM_INCLUDED #define GTM_BINTIM_INCLUDED int gtm_bintim (char *s, jnl_proc_time *timep); #endif /* GTM_BINTIM_INCLUDED */ fis-gtm-V6.0-003/sr_port/gtm_byteswap_64.c0000644000032200000250000000157412201176156017224 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" qw_num gtm_byteswap_64(qw_num num64) { #ifndef INT8_SUPPORTED qw_num swap_qw; uint32_t swap_uint32; QWASSIGN(swap_qw, num64); swap_uint32 = GTM_BYTESWAP_32(swap_qw.value[lsb_index]); swap_qw.value[lsb_index] = GTM_BYTESWAP_32(swap_qw.value[msb_index]); swap_qw.value[msb_index] = swap_uint32; return (swap_qw); #else GTMASSERT; /* should use GTM_BYTESWAP_64 macro, not gtm_byteswap_64 function */ return 0; #endif } fis-gtm-V6.0-003/sr_port/gtm_c_stack_trace.h0000644000032200000250000000504112201176156017640 0ustar librarygtc/**************************************************************** * * * Copyright 2009, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_C_STACK_TRACE_H #define GTM_C_STACK_TRACE_H #define ONCE 1 #define TWICE 2 #ifdef VMS #define GET_C_STACK_MULTIPLE_PIDS(MESSAGE, CNL_PID_ARRAY, MAX_PID_SLOTS, STUCK_CNT) #define GET_C_STACK_FROM_SCRIPT(MESSAGE, WAITINGPID, BLOCKINGPID, COUNT) #define GET_C_STACK_FOR_KIP(KIP_PIDS_ARR_PTR, TRYNUM, MAX_TRY, STUCK_CNT, MAX_PID_SLOTS) #elif defined(UNIX) void gtm_c_stack_trace(char *message, pid_t waiting_pid, pid_t blocking_pid, uint4 count); #define GET_C_STACK_MULTIPLE_PIDS(MESSAGE, CNL_PID_ARRAY, MAX_PID_SLOTS, STUCK_CNT) \ { \ uint4 index; \ pid_t pid; \ GBLREF uint4 process_id; \ \ for (index = 0; MAX_PID_SLOTS > index; index++) \ { \ pid = CNL_PID_ARRAY[index]; \ if (0 != pid) \ GET_C_STACK_FROM_SCRIPT(MESSAGE, process_id, pid, STUCK_CNT); \ } \ } #define GET_C_STACK_FROM_SCRIPT(MESSAGE, WAITINGPID, BLOCKINGPID, COUNT) \ { \ gtm_c_stack_trace(MESSAGE, WAITINGPID, BLOCKINGPID, COUNT); \ } #define GET_C_STACK_FOR_KIP(KIP_PIDS_ARR_PTR, TRYNUM, MAX_TRY, STUCK_CNT, MAX_PID_SLOTS) \ { \ boolean_t invoke_c_stack = FALSE; \ char *kip_wait_string = NULL; \ \ DEBUG_ONLY( \ /* If we had waited for half the max time, get a C stack trace on the processes currently \ * doing the kill \ */ \ if ((MAX_TRY / 2) == TRYNUM) \ { \ invoke_c_stack = TRUE; \ kip_wait_string = "KILL_IN_PROG_HALFWAIT"; \ } \ ) \ /* If we had waited for max time, get a C stack trace on the processes currently doing the kill \ * irrespective of whether it's pro or dbg \ */ \ if (MAX_TRY <= TRYNUM) \ { \ invoke_c_stack = TRUE; \ kip_wait_string = "KILL_IN_PROG_WAIT"; \ } \ if (invoke_c_stack) \ GET_C_STACK_MULTIPLE_PIDS(kip_wait_string, KIP_PIDS_ARR_PTR, MAX_PID_SLOTS, STUCK_CNT); \ } #else #error UNSUPPORTED PLATFORM #endif #endif fis-gtm-V6.0-003/sr_port/gtm_caseconv.h0000644000032200000250000000122712201176156016656 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_CASECONV_included #define GTM_CASECONV_included void lower_to_upper(uchar_ptr_t d, uchar_ptr_t s, int4 len); void upper_to_lower(uchar_ptr_t d, uchar_ptr_t s, int4 len); #endif /*GTM_CASECONV_included*/ fis-gtm-V6.0-003/sr_port/gtm_common_defs.h0000644000032200000250000001141112201176156017342 0ustar librarygtc/**************************************************************** * * * Copyright 2012, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_COMMON_DEFS_H #define GTM_COMMON_DEFS_H #if defined(__ia64) || defined(__x86_64__) || defined(__sparc) || defined(__s390__) || defined (_AIX) # define GTM64 #endif #ifdef GTM64 # define GTM64_ONLY(X) X # define NON_GTM64_ONLY(X) #else # define GTM64_ONLY(X) # define NON_GTM64_ONLY(X) X #endif #ifndef __vms # define readonly # define GBLDEF # define GBLREF extern # define LITDEF const # define LITREF extern const # define error_def(x) LITREF int x #else # ifdef __cplusplus # define GBLDEF # define GBLREF extern # define LITDEF const # define LITREF extern const # else # define GBLDEF globaldef # define GBLREF globalref # define LITDEF const globaldef # define LITREF const globalref # endif #endif /* Use GBLDEF to define STATICDEF for variables and STATICFNDEF, STATICFNDCL for functions. Define STATICDEF to "GBLDEF". This way * we know such usages are intended to be "static" but yet can effectively debug these variables since they are externally * visible. For functions, do not use the "static" keyword to make them externally visible. Note that a STATICREF for variables * does not make sense since statics are supposed to be used only within one module. */ #define STATICDEF GBLDEF #define STATICFNDCL extern #define STATICFNDEF #ifndef TRUE # define TRUE 1 #endif #ifndef FALSE # define FALSE 0 #endif #ifndef NULL # define NULL ((void *) 0) #endif #if defined(__ia64) || defined(__MVS__) # define INTCAST(X) ((int)(X)) # define UINTCAST(X) ((uint4)(X)) # define STRLEN(X) ((int)(strlen(X))) # define USTRLEN(X) ((unsigned int)(strlen(X))) # define OFFSETOF(X,Y) ((int)(offsetof(X,Y))) #else # define INTCAST(X) X # define UINTCAST(X) X # define STRLEN(X) strlen(X) # define USTRLEN(X) strlen(X) # define OFFSETOF(X,Y) offsetof(X,Y) #endif #ifndef __vms # define DIR_SEPARATOR '/' #endif /* the LITERAL version of the macro should be used over STRING whenever possible for efficiency reasons */ #define STR_LIT_LEN(LITERAL) (SIZEOF(LITERAL) - 1) #define LITERAL_AND_LENGTH(LITERAL) (LITERAL), (SIZEOF(LITERAL) - 1) #define LENGTH_AND_LITERAL(LITERAL) (SIZEOF(LITERAL) - 1), (LITERAL) #define STRING_AND_LENGTH(STRING) (STRING), (STRLEN((char *)(STRING))) #define LENGTH_AND_STRING(STRING) (strlen((char *)(STRING))), (STRING) #define LEN_AND_LIT(LITERAL) LENGTH_AND_LITERAL(LITERAL) #define LIT_AND_LEN(LITERAL) LITERAL_AND_LENGTH(LITERAL) #define STR_AND_LEN(STRING) STRING_AND_LENGTH(STRING) #define LEN_AND_STR(STRING) LENGTH_AND_STRING(STRING) #define ARRAYSIZE(arr) SIZEOF(arr)/SIZEOF(arr[0]) /* # of elements defined in the array */ #define ARRAYTOP(arr) (&arr[0] + ARRAYSIZE(arr)) /* address of the TOP of the array (first byte AFTER * array limits).Use &arr[0] + size instead of * &arr[size] to avoid compiler warning. */ #define MEMCMP_LIT(SOURCE, LITERAL) memcmp(SOURCE, LITERAL, SIZEOF(LITERAL) - 1) #define MEMCPY_LIT(TARGET, LITERAL) memcpy(TARGET, LITERAL, SIZEOF(LITERAL) - 1) #define DIVIDE_ROUND_UP(VALUE, MODULUS) (((VALUE) + ((MODULUS) - 1)) / (MODULUS)) #define DIVIDE_ROUND_DOWN(VALUE, MODULUS) ((VALUE) / (MODULUS)) #define ROUND_UP(VALUE, MODULUS) (DIVIDE_ROUND_UP(VALUE, MODULUS) * (MODULUS)) #define ROUND_DOWN(VALUE, MODULUS) (DIVIDE_ROUND_DOWN(VALUE, MODULUS) * (MODULUS)) /* Macro to copy a source string to a malloced area that is set to the destination pointer. * Since it is possible that DST might have multiple pointer dereferences in its usage, we * use a local pointer variable and finally assign it to DST thereby avoiding duplication of * those pointer dereferences (one for the malloc and one for the strcpy). * There are two macros depending on whether a string or literal is passed. */ #define MALLOC_CPY_STR(DST, SRC) \ { \ char *mcs_ptr; \ int mcs_len; \ \ mcs_len = STRLEN(SRC) + 1; \ mcs_ptr = malloc(mcs_len); \ memcpy(mcs_ptr, SRC, mcs_len); \ DST = mcs_ptr; \ } #define MALLOC_CPY_LIT(DST, SRC) \ { \ char *mcs_ptr; \ int mcs_len; \ \ mcs_len = SIZEOF(SRC); \ mcs_ptr = malloc(mcs_len); \ memcpy(mcs_ptr, SRC, mcs_len); \ DST = mcs_ptr; \ } #define MALLOC_INIT(DST, SIZ) \ { \ void *lcl_ptr; \ \ lcl_ptr = malloc(SIZ); \ memset(lcl_ptr, 0, SIZ); \ DST = lcl_ptr; \ } #endif /* GTM_COMMON_DEFS_H */ fis-gtm-V6.0-003/sr_port/gtm_ctype.h0000644000032200000250000000635612201176156016211 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_ctype.h - interlude to system header file. */ #ifndef GTM_CTYPEH #define GTM_CTYPEH #if defined(__osf__) && defined(__alpha) /* On Tru64, contains declarations of arrays of 64-bit pointers * in system library routines. The following pragma's are necessary * to ensure that references to those arrays declare them as 64-bit * pointer arrays, even if the including C program is compiled with * 32-bit pointer options. */ #pragma pointer_size (save) #pragma pointer_size (long) #endif #include /* The behavior of the system-defined ISxxxxx macros can vary based on the current locale and platform. * In the "C" locale, characters are classified according to the rules of the US-ASCII 7-bit coded character set. * In non-"C" locales (for example, UTF-8 mode) the result of ISXXXXX might not be what is expected * For example, ISALNUM(240) will return TRUE in UTF8 mode and FALSE in M mode (C locale) on Solaris. * Therefore define ISxxxxx_ASCII variant macros that additionally do check for ASCII. * Callers that need to check for a ISxxxxx property within the ASCII range should use the ISxxxxx_ASCII variants. * This makes the return value consistent across all platforms and independent of the locale. * We do not expect any callers of the non-ASCII macros in the GT.M codebase. */ #ifdef ISALNUM #undef ISALNUM #endif #define ISALNUM isalnum #define ISALNUM_ASCII(CH) (IS_ASCII(CH) && ISALNUM(CH)) #ifdef ISALPHA #undef ISALPHA #endif #define ISALPHA isalpha #define ISALPHA_ASCII(CH) (IS_ASCII(CH) && ISALPHA(CH)) #ifdef ISCNTRL #undef ISCNTRL #endif #define ISCNTRL iscntrl #define ISCNTRL_ASCII(CH) (IS_ASCII(CH) && ISCNTRL(CH)) #ifdef ISDIGIT #undef ISDIGIT #endif #define ISDIGIT isdigit #define ISDIGIT_ASCII(CH) (IS_ASCII(CH) && ISDIGIT(CH)) #ifdef ISGRAPH #undef ISGRAPH #endif #define ISGRAPH isgraph #define ISGRAPH_ASCII(CH) (IS_ASCII(CH) && ISGRAPH(CH)) #ifdef ISLOWER #undef ISLOWER #endif #define ISLOWER islower #define ISLOWER_ASCII(CH) (IS_ASCII(CH) && ISLOWER(CH)) #ifdef ISPRINT #undef ISPRINT #endif #define ISPRINT isprint #define ISPRINT_ASCII(CH) (IS_ASCII(CH) && ISPRINT(CH)) #ifdef ISPUNCT #undef ISPUNCT #endif #define ISPUNCT ispunct #define ISPUNCT_ASCII(CH) (IS_ASCII(CH) && ISPUNCT(CH)) #ifdef ISSPACE #undef ISSPACE #endif #define ISSPACE isspace #define ISSPACE_ASCII(CH) (IS_ASCII(CH) && ISSPACE(CH)) #ifdef ISUPPER #undef ISUPPER #endif #define ISUPPER isupper #define ISUPPER_ASCII(CH) (IS_ASCII(CH) && ISUPPER(CH)) #ifdef ISXDIGIT #undef ISXDIGIT #endif #define ISXDIGIT isxdigit #define ISXDIGIT_ASCII(CH) (IS_ASCII(CH) && ISXDIGIT(CH)) #ifdef TOLOWER #undef TOLOWER #endif #define TOLOWER tolower #ifdef TOUPPER #undef TOUPPER #endif #define TOUPPER toupper #if defined(__osf__) && defined(__alpha) #pragma pointer_size (restore) #endif #endif fis-gtm-V6.0-003/sr_port/gtm_dirent.h0000644000032200000250000000123112201176156016335 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_dirent.h - interlude to system header file. */ #ifndef GTM_DIRENTH #define GTM_DIRENTH #include #define OPENDIR opendir #define READDIR(dir, rddr_res) (rddr_res = readdir(dir)) #endif fis-gtm-V6.0-003/sr_port/gtm_env_init.c0000644000032200000250000003316512201176156016671 0ustar librarygtc/**************************************************************** * * * Copyright 2004, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_stdlib.h" #include /* For offsetof macro */ #include "gtm_logicals.h" #include "logical_truth_value.h" #include "trans_numeric.h" #include "trans_log_name.h" #include "gtmdbglvl.h" #include "iosp.h" #include "wbox_test_init.h" #include "gtm_env_init.h" /* for gtm_env_init() and gtm_env_init_sp() prototype */ #include "gt_timer.h" #include "io.h" #include "iotcpdef.h" #include "iosocketdef.h" #include "gtm_malloc.h" #include "cache.h" #include "gdsroot.h" /* needed for gdsfhead.h */ #include "gdskill.h" /* needed for gdsfhead.h */ #include "gdsbt.h" /* needed for gdsfhead.h */ #include "gdsfhead.h" /* needed for MAXTOTALBLKS_MAX macro */ #include "mvalconv.h" #include "fullbool.h" #include "trace_table.h" #include "parse_trctbl_groups.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdscc.h" #include "filestruct.h" #include "buddy_list.h" /* needed for tp.h */ #include "jnl.h" #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #ifdef DEBUG # define INITIAL_DEBUG_LEVEL GDL_Simple #else # define INITIAL_DEBUG_LEVEL GDL_None #endif #ifdef FULLBLOCKWRITES # define DEFAULT_FBW_FLAG TRUE #else # define DEFAULT_FBW_FLAG FALSE #endif #define SIZEOF_prombuf ggl_prombuf GBLREF boolean_t dollar_zquit_anyway; /* if TRUE compile QUITs to not care whether or not they're from an extrinsic */ GBLREF uint4 gtmDebugLevel; /* Debug level (0 = using default sm module so with a DEBUG build, even level 0 implies basic debugging) */ GBLREF boolean_t gtm_fullblockwrites; /* Do full (not partial) database block writes T/F */ GBLREF boolean_t certify_all_blocks; GBLREF uint4 gtm_blkupgrade_flag; /* controls whether dynamic block upgrade is attempted or not */ GBLREF boolean_t gtm_dbfilext_syslog_disable; /* control whether db file extension message is logged or not */ GBLREF uint4 gtm_max_sockets; /* Maximum sockets in a socket device that can be created by this process */ GBLREF bool undef_inhibit; GBLREF uint4 outOfMemoryMitigateSize; /* Reserve that we will freed to help cleanup if run out of memory */ GBLREF uint4 max_cache_memsize; /* Maximum bytes used for indirect cache object code */ GBLREF uint4 max_cache_entries; /* Maximum number of cached indirect compilations */ GBLREF block_id gtm_tp_allocation_clue; /* block# hint to start allocation for created blocks in TP */ GBLREF boolean_t gtm_stdxkill; /* Use M Standard exclusive kill instead of historical GTM */ GBLREF boolean_t ztrap_new; /* Each time $ZTRAP is set it is automatically NEW'd */ GBLREF size_t gtm_max_storalloc; /* Used for testing: creates an allocation barrier */ GBLREF boolean_t ipv4_only; /* If TRUE, only use AF_INET. */ void gtm_env_init(void) { mstr val, trans; boolean_t ret, is_defined; uint4 tdbglvl, tmsock, reservesize, memsize, cachent, trctblsize, trctblbytes; int4 status; char buf[MAX_TRANS_NAME_LEN]; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (!TREF(gtm_env_init_started)) { TREF(gtm_env_init_started) = TRUE; /* See if a debug level has been specified. Do this first since gtmDebugLevel needs * to be initialized before any mallocs are done in the system. */ gtmDebugLevel = INITIAL_DEBUG_LEVEL; val.addr = GTM_DEBUG_LEVEL_ENVLOG; val.len = SIZEOF(GTM_DEBUG_LEVEL_ENVLOG) - 1; if (tdbglvl = trans_numeric(&val, &is_defined, TRUE)) /* Note assignment!! */ { /* Some kind of debugging was asked for.. */ tdbglvl |= GDL_Simple; /* Make sure simple debugging turned on if any is */ if ((GDL_SmChkFreeBackfill | GDL_SmChkAllocBackfill) & tdbglvl) tdbglvl |= GDL_SmBackfill; /* Can't check it unless it's filled in */ if (GDL_SmStorHog & tdbglvl) tdbglvl |= GDL_SmBackfill | GDL_SmChkAllocBackfill; gtmDebugLevel |= tdbglvl; } /* gtm_boolean environment/logical */ val.addr = GTM_BOOLEAN; val.len = SIZEOF(GTM_BOOLEAN) - 1; TREF(gtm_fullbool) = trans_numeric(&val, &is_defined, TRUE); /* gtm_boolean environment/logical */ val.addr = GTM_SIDE_EFFECT; val.len = SIZEOF(GTM_SIDE_EFFECT) - 1; TREF(side_effect_handling) = trans_numeric(&val, &is_defined, TRUE); if (!is_defined) /* default to original behavior */ TREF(side_effect_handling) = OLD_SE; /* NOUNDEF environment/logical */ val.addr = GTM_NOUNDEF; val.len = SIZEOF(GTM_NOUNDEF) - 1; assert(FALSE == undef_inhibit); /* should have been set to FALSE at global variable definition time */ ret = logical_truth_value(&val, FALSE, &is_defined); if (is_defined) undef_inhibit = ret; /* if the logical is not defined, we want undef_inhibit to take its default value */ /* gtm_trace_gbl_name environment; it controls implicit MPROF testing */ val.addr = GTM_MPROF_TESTING; val.len = SIZEOF(GTM_MPROF_TESTING) - 1; if (SS_NORMAL == (status = TRANS_LOG_NAME(&val, &trans, buf, SIZEOF(buf), do_sendmsg_on_log2long))) { /* Note assignment above */ if (SIZEOF(buf) >= trans.len) { if (('0' == (char)(*trans.addr)) || (0 == trans.len)) { (TREF(mprof_env_gbl_name)).str.len = 0; /* this malloc is just so that mprof_env_gbl_name.str.addr is not NULL for subsequent * checks in gtm_startup.c and gtm$startup.c */ (TREF(mprof_env_gbl_name)).str.addr = malloc(1); } else { (TREF(mprof_env_gbl_name)).str.len = trans.len; (TREF(mprof_env_gbl_name)).str.addr = malloc(trans.len); memcpy((TREF(mprof_env_gbl_name)).str.addr, trans.addr, trans.len); } (TREF(mprof_env_gbl_name)).mvtype = MV_STR; } } else (TREF(mprof_env_gbl_name)).str.addr = NULL; # ifdef DEBUG /* GTM_GVUNDEF_FATAL environment/logical */ val.addr = GTM_GVUNDEF_FATAL; val.len = SIZEOF(GTM_GVUNDEF_FATAL) - 1; assert(FALSE == TREF(gtm_gvundef_fatal)); /* should have been set to FALSE by gtm_threadgbl_defs */ ret = logical_truth_value(&val, FALSE, &is_defined); if (is_defined) TREF(gtm_gvundef_fatal) = ret; /* if logical is not defined, gtm_gvundef_fatal takes the default value */ # endif /* Initialize variable that controls TP allocation clue (for created blocks) */ val.addr = GTM_TP_ALLOCATION_CLUE; val.len = SIZEOF(GTM_TP_ALLOCATION_CLUE) - 1; gtm_tp_allocation_clue = (block_id)trans_numeric(&val, &is_defined, TRUE); if (!is_defined) gtm_tp_allocation_clue = (block_id)MAXTOTALBLKS_MAX; /* Full Database-block Write mode */ val.addr = GTM_FULLBLOCKWRITES; val.len = SIZEOF(GTM_FULLBLOCKWRITES) - 1; gtm_fullblockwrites = logical_truth_value(&val, FALSE, &is_defined); if (!is_defined) gtm_fullblockwrites = DEFAULT_FBW_FLAG; /* GDS Block certification */ val.addr = GTM_GDSCERT; val.len = SIZEOF(GTM_GDSCERT) - 1; ret = logical_truth_value(&val, FALSE, &is_defined); if (is_defined) certify_all_blocks = ret; /* if the logical is not defined, we want to take default value */ /* Initialize null subscript's collation order */ val.addr = LCT_STDNULL; val.len = SIZEOF(LCT_STDNULL) - 1; ret = logical_truth_value(&val, FALSE, &is_defined); if (is_defined) TREF(local_collseq_stdnull) = ret; /* Initialize eXclusive Kill variety (GTM vs M Standard) */ val.addr = GTM_STDXKILL; val.len = SIZEOF(GTM_STDXKILL) - 1; ret = logical_truth_value(&val, FALSE, &is_defined); if (is_defined) gtm_stdxkill = ret; /* Initialize variables for white box testing. Even though these white-box test variables only control the * flow of the DBG builds, the PRO builds check on these variables (for example, in tp_restart.c to decide * whether to fork_n_core or not) so need to do this initialization for PRO builds as well. */ wbox_test_init(); /* Initialize variable that controls dynamic GT.M block upgrade */ val.addr = GTM_BLKUPGRADE_FLAG; val.len = SIZEOF(GTM_BLKUPGRADE_FLAG) - 1; gtm_blkupgrade_flag = trans_numeric(&val, &is_defined, TRUE); /* Initialize whether database file extensions need to be logged in the operator log */ val.addr = GTM_DBFILEXT_SYSLOG_DISABLE; val.len = SIZEOF(GTM_DBFILEXT_SYSLOG_DISABLE) - 1; ret = logical_truth_value(&val, FALSE, &is_defined); if (is_defined) gtm_dbfilext_syslog_disable = ret; /* if the logical is not defined, we want to take default value */ /* Initialize maximum sockets in a single socket device createable by this process */ gtm_max_sockets = MAX_N_SOCKET; val.addr = GTM_MAX_SOCKETS; val.len = SIZEOF(GTM_MAX_SOCKETS) - 1; if ((tmsock = trans_numeric(&val, &is_defined, TRUE)) && MAX_MAX_N_SOCKET > tmsock) /* Note assignment!! */ gtm_max_sockets = tmsock; /* Initialize storage to allocate and keep in our back pocket in case run out of memory */ outOfMemoryMitigateSize = GTM_MEMORY_RESERVE_DEFAULT; val.addr = GTM_MEMORY_RESERVE; val.len = SIZEOF(GTM_MEMORY_RESERVE) - 1; if (reservesize = trans_numeric(&val, &is_defined, TRUE)) /* Note assignment!! */ outOfMemoryMitigateSize = reservesize; /* Initialize indirect cache limits (max memory, max entries) */ max_cache_memsize = MAX_CACHE_MEMSIZE * 1024; val.addr = GTM_MAX_INDRCACHE_MEMORY; val.len = SIZEOF(GTM_MAX_INDRCACHE_MEMORY) - 1; if (memsize = trans_numeric(&val, &is_defined, TRUE)) /* Note assignment!! */ max_cache_memsize = memsize * 1024; max_cache_entries = MAX_CACHE_ENTRIES; val.addr = GTM_MAX_INDRCACHE_COUNT; val.len = SIZEOF(GTM_MAX_INDRCACHE_COUNT) - 1; if (cachent = trans_numeric(&val, &is_defined, TRUE)) /* Note assignment!! */ max_cache_entries = cachent; /* Initialize ZQUIT to control funky QUIT compilation */ val.addr = GTM_ZQUIT_ANYWAY; val.len = SIZEOF(GTM_ZQUIT_ANYWAY) - 1; ret = logical_truth_value(&val, FALSE, &is_defined); if (is_defined) dollar_zquit_anyway = ret; /* Initialize ZPROMPT to desired GTM prompt or default */ val.addr = GTM_PROMPT; val.len = SIZEOF(GTM_PROMPT) - 1; if (SS_NORMAL == (status = TRANS_LOG_NAME(&val, &trans, buf, SIZEOF(buf), do_sendmsg_on_log2long))) { /* Non-standard prompt requested */ assert(SIZEOF(buf) > trans.len); if (SIZEOF_prombuf >= trans.len) { (TREF(gtmprompt)).len = trans.len; memcpy((TREF(gtmprompt)).addr, trans.addr, trans.len); } } /* Initialize tpnotacidtime */ TREF(tpnotacidtime) = TPNOTACID_DEFAULT_TIME; val.addr = GTM_TPNOTACIDTIME; val.len = SIZEOF(GTM_TPNOTACIDTIME) - 1; if ((status = trans_numeric(&val, &is_defined, TRUE)) && (0 <= status) && (TPNOTACID_MAX_TIME >= status) && is_defined) TREF(tpnotacidtime) = status; /* NOTE assignment above */ /* Initialize $gtm_tprestart_log_first */ val.addr = GTM_TPRESTART_LOG_LIMIT; val.len = STR_LIT_LEN(GTM_TPRESTART_LOG_LIMIT); TREF(tprestart_syslog_limit) = trans_numeric(&val, &is_defined, TRUE); if (0 > TREF(tprestart_syslog_limit)) TREF(tprestart_syslog_limit) = 0; /* Initialize $gtm_tprestart_log_delta */ val.addr = GTM_TPRESTART_LOG_DELTA; val.len = STR_LIT_LEN(GTM_TPRESTART_LOG_DELTA); TREF(tprestart_syslog_delta) = trans_numeric(&val, &is_defined, TRUE); if (0 > TREF(tprestart_syslog_delta)) TREF(tprestart_syslog_delta) = 0; /* See if this is a GT.M Development environment, not a production environment */ if (GETENV("gtm_environment_init")) TREF(gtm_environment_init) = TRUE; /* in-house */ /* See if a trace table is desired. If we have been asked to trace one or more groups, we also * see if a specific size has been specified. A default size is provided. */ val.addr = GTM_TRACE_GROUPS; val.len = SIZEOF(GTM_TRACE_GROUPS) - 1; if (SS_NORMAL == (status = TRANS_LOG_NAME(&val, &trans, buf, SIZEOF(buf), do_sendmsg_on_log2long))) { /* Trace-group(s) have been declared - figure out which ones */ assert(SIZEOF(buf) > trans.len); parse_trctbl_groups(&trans); if (0 != TREF(gtm_trctbl_groups)) { /* At least one valid group was specified */ val.addr = GTM_TRACE_TABLE_SIZE; val.len = SIZEOF(GTM_TRACE_TABLE_SIZE) - 1; trctblsize = trans_numeric(&val, &is_defined, TRUE); if (0 < (trctblsize = (0 < trctblsize) ? trctblsize : TRACE_TABLE_SIZE_DEFAULT)) /* assignment! */ { trctblbytes = trctblsize * SIZEOF(trctbl_entry); TREF(gtm_trctbl_start) = malloc(trctblbytes); TREF(gtm_trctbl_end) = TREF(gtm_trctbl_start) + trctblsize; TREF(gtm_trctbl_cur) = TREF(gtm_trctbl_start) - 1; /* So doesn't skip 1st entry */ memset(TREF(gtm_trctbl_start), 0, trctblbytes); } } } # ifdef UNIX /* Initialize jnl_extract_nocol */ val.addr = GTM_EXTRACT_NOCOL; val.len = STR_LIT_LEN(GTM_EXTRACT_NOCOL); TREF(jnl_extract_nocol) = trans_numeric(&val, &is_defined, TRUE); # endif /* Initialize dollar_zmaxtptime */ val.addr = GTM_ZMAXTPTIME; val.len = SIZEOF(GTM_ZMAXTPTIME) - 1; if ((status = trans_numeric(&val, &is_defined, TRUE)) && (0 <= status) && (TPTIMEOUT_MAX_TIME >= status)) TREF(dollar_zmaxtptime) = status; /* NOTE assignment above */ /* See if $gtm_ztrap_new/GTM_ZTRAP_NEW has been specified */ val.addr = ZTRAP_NEW; val.len = SIZEOF(ZTRAP_NEW) - 1; ztrap_new = logical_truth_value(&val, FALSE, NULL); /* See if $gtm_max_storalloc is set */ val.addr = GTM_MAX_STORALLOC; val.len = SIZEOF(GTM_MAX_STORALLOC) - 1; gtm_max_storalloc = trans_numeric(&val, &is_defined, TRUE); # ifdef UNIX /* See if gtm_ipv4_only is set */ val.addr = GTM_IPV4_ONLY; val.len = SIZEOF(GTM_IPV4_ONLY) - 1; ipv4_only = logical_truth_value(&val, FALSE, NULL); # endif /* Platform specific initializations */ gtm_env_init_sp(); } } fis-gtm-V6.0-003/sr_port/gtm_env_init.h0000644000032200000250000000107312201176156016667 0ustar librarygtc/**************************************************************** * * * Copyright 2004 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GTM_ENV_INIT_DEFINED void gtm_env_init(void); void gtm_env_init_sp(void); #define __GTM_ENV_INIT_DEFINED #endif fis-gtm-V6.0-003/sr_port/gtm_env_xlate_init.c0000644000032200000250000000364312201176156020064 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_limits.h" #include "iosp.h" #include "trans_log_name.h" #include "gtm_logicals.h" #include "error.h" #include "gtm_env_xlate_init.h" #include "stringpool.h" GBLREF mstr env_gtm_env_xlate; void gtm_env_xlate_init(void) { int4 status; mstr val, tn; char buf[GTM_PATH_MAX]; error_def(ERR_TRNLOGFAIL); error_def(ERR_LOGTOOLONG); val.addr = GTM_ENV_XLATE; val.len = STR_LIT_LEN(GTM_ENV_XLATE); if (SS_NORMAL == (status = TRANS_LOG_NAME(&val, &tn, buf, SIZEOF(buf), dont_sendmsg_on_log2long))) { UNIX_ONLY( env_gtm_env_xlate.len = tn.len; env_gtm_env_xlate.addr = (char *)malloc(tn.len); memcpy(env_gtm_env_xlate.addr, buf, tn.len); ) VMS_ONLY( /* In op_gvextnam, the logical name is used in VMS, rather than its value (by lib$find_image_symbol), * so only whether the logical name translates is checked here. */ env_gtm_env_xlate.len = val.len; env_gtm_env_xlate.addr = val.addr; ) } else if (SS_NOLOGNAM == status) env_gtm_env_xlate.len = 0; # ifdef UNIX else if (SS_LOG2LONG == status) rts_error(VARLSTCNT(5) ERR_LOGTOOLONG, 3, LEN_AND_LIT(GTM_ENV_XLATE), SIZEOF(buf) - 1); # endif else rts_error(VARLSTCNT(5) ERR_TRNLOGFAIL, 2, LEN_AND_LIT(GTM_ENV_XLATE), status); return; } fis-gtm-V6.0-003/sr_port/gtm_env_xlate_init.h0000644000032200000250000000127212201176156020065 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_ENV_XLATE_INIT_H #define GTM_ENV_XLATE_INIT_H #define GTM_ENV_XLATE_ROUTINE_NAME "gtm_env_xlate" void gtm_env_xlate_init(void); mval* gtm_env_translate(mval* val1, mval* val2, mval* val_xlated); #endif /* GTM_ENV_XLATE_INIT_H */ fis-gtm-V6.0-003/sr_port/gtm_event_log.h0000644000032200000250000000175412201176156017044 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2008 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GTM_EVENT_LOG_H__ #define __GTM_EVENT_LOG_H__ /* GTM external logging */ #define GTM_EVENT_LOG_HARDCODE_RTN_NAME /* undef this to use env variable */ #ifdef GTM_EVENT_LOG_HARDCODE_RTN_NAME # define GTM_EVENT_LOG_RTN "GtmEventLog" extern int GtmEventLog(int argc, char *category, char *code, char *msg); #endif #define GTM_EVENT_LOG_ARGC 3 /* excluding the argument count - category, code and msg */ int gtm_event_log_init(void); int gtm_event_log_close(void); int gtm_event_log(int argc, char *category, char *code, char *msg); #endif fis-gtm-V6.0-003/sr_port/gtm_facility.h0000644000032200000250000000107612201176156016663 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GTM_FACILITY_H__ #define __GTM_FACILITY_H__ typedef enum { mcompile_v1y0, mupip_create_v1y0 } gtm_facility; #endif fis-gtm-V6.0-003/sr_port/gtm_fcntl.h0000644000032200000250000000306512201176156016165 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_fcntl.h - interlude to system header file. */ #ifndef GTM_FCNTLH #define GTM_FCNTLH #include #ifndef GTM_FD_TRACE # define CREAT creat # define OPEN open # define OPEN3 open #else /* Note we no longer redefine open to gtm_open because of the problems it creates requiring includes to be specified in * a specific order (anything that includes this include must come BEFORE gdsfhead to avoid errors). This ordering was * nearly impossible when trace flags were specified in error.h or gtm_trigger_src.h. At the time of this removal (10/2012), * a search was completed to verify no open() calls existed that needed this support but that does not prevent new calls from * being added. Therefore, attentiveness is required. */ # define CREAT gtm_creat # define OPEN gtm_open # define OPEN3 gtm_open3 # undef creat /* in case this is already defined by (at least AIX and HPUX seem to do this) */ # define creat gtm_creat #endif int gtm_open(const char *pathname, int flags); int gtm_open3(const char *pathname, int flags, mode_t mode); int gtm_creat(const char *pathname, mode_t mode); #endif fis-gtm-V6.0-003/sr_port/gtm_fetch.c0000644000032200000250000000545512201176176016152 0ustar librarygtc/**************************************************************** * * * Copyright 2009, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include #include "stack_frame.h" #include "lookup_variable_htent.h" #include "op.h" #include "lv_val.h" #ifdef DEBUG /* all of below is needed by the gv_target/cs_addrs assert */ #include "gdsroot.h" #include "gdskill.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #endif GBLREF stack_frame *frame_pointer; GBLREF symval *curr_symval; #ifdef DEBUG GBLREF int process_exiting; GBLREF gv_namehead *gv_target; GBLREF sgmnt_addrs *cs_addrs; #endif #ifdef UNIX void gtm_fetch(unsigned int cnt_arg, unsigned int indxarg, ...) #elif defined(VMS) void gtm_fetch(unsigned int indxarg, ...) #else #error unsupported platform #endif { va_list var; unsigned int indx; unsigned int cnt; stack_frame *fp; ht_ent_mname **htepp; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(!process_exiting); /* Verify that no process unwound the exit frame and continued */ DEBUG_ONLY(DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE);) /* surrounding DEBUG_ONLY needed because gdsfhead.h is * not included for pro builds and so the macro and its * parameters would be undefined in that case causing a * compile-time error. */ assert(!TREF(in_zwrite)); /* Verify in_zwrite was not left on */ VAR_START(var, indxarg); VMS_ONLY(va_count(cnt);) UNIX_ONLY(cnt = cnt_arg;) /* need to preserve stack copy on i386 */ fp = frame_pointer; if (0 < cnt) { /* All generated code comes here to verify instantiation of a given set of variables from the local variable table */ indx = indxarg; for ( ; ; ) { htepp = &fp->l_symtab[indx]; if (NULL == *htepp) *htepp = lookup_variable_htent(indx); assert(NULL != (*htepp)->value); assert(LV_IS_BASE_VAR((*htepp)->value)); assert(NULL != LV_SYMVAL((lv_val *)((*htepp)->value))); if (0 < --cnt) indx = va_arg(var, int4); else break; } } else { /* GT.M calls come here to verify instantiation of the entire local variable table */ indx = fp->vartab_len; htepp = &fp->l_symtab[indx]; for (; indx > 0;) { --indx; --htepp; if (NULL == *htepp) *htepp = lookup_variable_htent(indx); else if (NULL == (*htepp)->value) lv_newname(*htepp, curr_symval); /* Alias processing may have removed the lv_val */ } } va_end(var); } fis-gtm-V6.0-003/sr_port/gtm_ffs.c0000644000032200000250000000253612201176156015632 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_ffs.h" #define BITS_PER_UCHAR 8 int gtm_ffs (uint4 offset, uchar_ptr_t addr, uint4 size) { uchar_ptr_t c; int i, j, top; c = addr + (offset / BITS_PER_UCHAR); if (i = (offset & (BITS_PER_UCHAR - 1))) { /* partial byte starting at offset */ for (j = 0; (i < BITS_PER_UCHAR) && (j < size); j++, i++) { if (*c & (1 << i)) return (offset + j); } c++; } assert(c == (addr + (offset + BITS_PER_UCHAR - 1) / BITS_PER_UCHAR)); for (i = ROUND_UP2(offset, BITS_PER_UCHAR), top = ROUND_DOWN2(size + offset, BITS_PER_UCHAR); i < top; c++, i += BITS_PER_UCHAR) { /* full bytes offset to end */ if (*c) { for (j = 0; j < BITS_PER_UCHAR; j++) { if (*c & (1 << j)) return (i + j); } } } for (j = 0, top = size + offset; i < top; j++, i++) { /* partial byte at end */ assert(j < BITS_PER_UCHAR); if (*c & (1 << j)) return i; } return -1; } fis-gtm-V6.0-003/sr_port/gtm_ffs.h0000644000032200000250000000111112201176156015623 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_FFS_INCLUDED #define GTM_FFS_INCLUDED int gtm_ffs(uint4 offset, uchar_ptr_t addr, uint4 size); #endif /* GTM_FFS_INCLUDED */ fis-gtm-V6.0-003/sr_port/gtm_file_remove.h0000644000032200000250000000107012201176156017345 0ustar librarygtc/**************************************************************** * * * Copyright 2003 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GTM_FILE_REMOVE_ #define __GTM_FILE_REMOVE_ int4 gtm_file_remove(char *fn, int fn_len, uint4 *ustatus); #endif fis-gtm-V6.0-003/sr_port/gtm_file_stat.h0000644000032200000250000000427412201176156017034 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_FILE_STAT_INCLUDED #define GTM_FILE_STAT_INCLUDED /* Note that FILE_READONLY also implies FILE_PRESENT and the callers can use this information if necessary */ #define FILE_NOT_FOUND 0 #define FILE_PRESENT 1 #define FILE_READONLY 2 #define FILE_STAT_ERROR 4 /* Copy the filename from "src" to "dest" using the following rules. * (i) removing the version information * (ii) doing compression of contiguous directory delimiters (']' or '>' followed by '<' or '['). * (iii) transform every '<' to a '[' and every '>' to a ']' * e.g. * src = user:[library.]gtmshr.exe;23 * dst = user:[library.v990.pro]gtmshr.exe * * Note that without (iii) we would have got the following mixed notation for "dst" which is incorrect * as the '[' is balanced by a '>' (at the end of ".pro>") instead of a corresponding ']'. * * e.g. src = user:[library.]gtmshr.exe;23 * dst = user:[library.v990.pro>gtmshr.exe */ #ifdef VMS #define fncpy_nover(src, src_len, dest, dest_len) \ { \ unsigned char *sptr, *dptr; \ for (sptr = (unsigned char *)src, dptr = dest; sptr < (src + src_len) && (';' != *sptr); ) \ { \ if (('>' == *sptr || ']' == *sptr) && ('<' == *(sptr + 1) || '[' == *(sptr + 1))) \ sptr += 2; \ else if ('<' == *sptr) \ { \ *dptr++ = '['; \ sptr++; \ } else if ('>' == *sptr) \ { \ *dptr++ = ']'; \ sptr++; \ } else \ *dptr++ = *sptr++; \ } \ dest_len = dptr - (unsigned char *)(dest); \ *(dptr) = 0; \ } #endif int gtm_file_stat(mstr *file, mstr *def, mstr *ret, boolean_t check_prv, uint4 *status); #endif /* GTM_FILE_STAT_INCLUDED */ fis-gtm-V6.0-003/sr_port/gtm_iconv.h0000644000032200000250000000124212201176156016170 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_iconv.h - interlude to system header file. */ #ifndef GTM_ICONVH #define GTM_ICONVH #ifdef USING_ICONV #define _OSF_SOURCE #include #undef _OSF_SOURCE #define ICONV_OPEN iconv_open #endif #endif fis-gtm-V6.0-003/sr_port/gtm_imagetype_init.c0000644000032200000250000000430312201176156020055 0ustar librarygtc/**************************************************************** * * * Copyright 2010, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtmimagename.h" #include "gtm_imagetype_init.h" GBLREF boolean_t skip_dbtriggers; GBLREF boolean_t is_replicator; GBLREF boolean_t run_time; GBLREF boolean_t write_after_image; GBLREF boolean_t dse_running; GBLREF enum gtmImageTypes image_type; #ifdef UNIX GBLREF boolean_t jnlpool_init_needed; GBLREF boolean_t span_nodes_disallowed; #endif void gtm_imagetype_init(enum gtmImageTypes img_type) { boolean_t is_svc_or_gtcm; NON_GTMTRIG_ONLY(skip_dbtriggers = TRUE;) /* Do not invoke triggers for trigger non-supporting platforms. */ UNIX_ONLY(span_nodes_disallowed = (GTCM_GNP_SERVER_IMAGE == img_type) || (GTCM_SERVER_IMAGE == img_type);) is_svc_or_gtcm = ((GTM_SVC_DAL_IMAGE == img_type) || (GTCM_GNP_SERVER_IMAGE == img_type) || (GTCM_SERVER_IMAGE == img_type)); if (is_svc_or_gtcm) skip_dbtriggers = TRUE; /* SUN RPC DAL server and GT.CM OMI and GNP servers do not invoke triggers */ if (is_svc_or_gtcm || (GTM_IMAGE == img_type)) { is_replicator = TRUE; /* can go through t_end() and write jnl records to the jnlpool for replicated db */ run_time = TRUE; } else if (DSE_IMAGE == img_type) { dse_running = TRUE; write_after_image = TRUE; /* if block change is done, after image of the block needs to be written */ } # ifdef UNIX else if (MUPIP_IMAGE == img_type) run_time = FALSE; /* GT.M typically opens journal pool during the first update (in gvcst_put, gvcst_kill or op_ztrigger). But, if * anticipatory freeze is enabled, we want to open journal pool for any reads done by GT.M as well (basically at the time * of first database open (in gvcst_init). So, set jnlpool_init_needed to TRUE if this is GTM_IMAGE. */ jnlpool_init_needed = (GTM_IMAGE == img_type); # endif image_type = img_type; return; } fis-gtm-V6.0-003/sr_port/gtm_imagetype_init.h0000644000032200000250000000110612201176156020060 0ustar librarygtc/**************************************************************** * * * Copyright 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_IMAGETYPE_INIT_INCLUDED #define GTM_IMAGETYPE_INIT_INCLUDED void gtm_imagetype_init(enum gtmImageTypes img_type); #endif fis-gtm-V6.0-003/sr_port/gtm_inet.h0000644000032200000250000000153412201176156016015 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_inet.h - interlude to system header file. */ #ifndef GTM_INETH #define GTM_INETH #ifdef VMS #include #endif #if defined(_AIX) || defined (__MVS__) #include #endif #include #ifndef __MVS__ #include #endif #ifdef NeedInAddrPort typedef uint32_t in_addr_t; #endif #define INET_ADDR inet_addr #define INET_NTOA inet_ntoa #endif fis-gtm-V6.0-003/sr_port/gtm_ipv6.h0000644000032200000250000001055112201176156015741 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_ipv6.h - interlude to system header file. */ #ifndef GTM_IPV6H #define GTM_IPV6H #include /* Make sure we have AI_V4MAPPED/AI_NUMERICSERV defined if available */ GBLREF boolean_t ipv4_only; /* If TRUE, only use AF_INET. */ /* ai_canonname must be set NULL for AIX. Otherwise, freeaddrinfo() freeing the ai_canonname will hit SIG-11 * other field which were not initialized as 0 will also causes getaddrinfo()to fail * Setting AI_PASSIVE will give you a wildcard address if addr is NULL, i.e. INADDR_ANY or IN6ADDR_ANY * AI_NUMERICSERV is to pass the numeric port to address, it is to inhibit the name resolution to improve efficience * AI_ADDRCONFIG: IPv4 addresses are returned only if the local system has at least one IPv4 address configured; IPv6 addresses are only returned if the local system has at least one IPv6 address configured. For now we only use IPv6 address. So not use this flag here. * AI_V4MAPPED: IPv4 mapped addresses are acceptable * (Note: for snail, AI_V4MAPPED is defined but AI_NUMERICSERV is not defined) */ #if (defined(__hppa) || defined(__vms) || defined(__osf__)) #define GTM_IPV6_SUPPORTED FALSE #else #define GTM_IPV6_SUPPORTED TRUE #endif #if !GTM_IPV6_SUPPORTED #define SERVER_HINTS(hints, af) \ { \ assert(AF_INET6 != af); \ memset(&hints, 0, SIZEOF(struct addrinfo)); \ hints.ai_family = AF_INET; \ hints.ai_socktype = SOCK_STREAM; \ hints.ai_protocol = IPPROTO_TCP; \ hints.ai_flags = AI_PASSIVE; \ } #define CLIENT_HINTS(hints) \ { \ memset(&hints, 0, SIZEOF(struct addrinfo)); \ hints.ai_family = AF_INET; \ hints.ai_socktype = SOCK_STREAM; \ hints.ai_protocol = IPPROTO_TCP; \ hints.ai_flags = 0; \ } #define CLIENT_HINTS_AF(hints, af) \ { \ assert(AF_INET == af); \ memset(&hints, 0, SIZEOF(struct addrinfo)); \ hints.ai_family = AF_INET; \ hints.ai_socktype = SOCK_STREAM; \ hints.ai_protocol = IPPROTO_TCP; \ hints.ai_flags = 0; \ } #elif (defined(AI_V4MAPPED) && defined(AI_NUMERICSERV)) #define SERVER_HINTS(hints, af) \ { \ memset(&hints, 0, SIZEOF(struct addrinfo)); \ hints.ai_family = af; \ hints.ai_socktype = SOCK_STREAM; \ hints.ai_protocol = IPPROTO_TCP; \ hints.ai_flags = AI_V4MAPPED | AI_PASSIVE | AI_NUMERICSERV; \ } #define CLIENT_HINTS(hints) \ { \ memset(&hints, 0, SIZEOF(struct addrinfo)); \ hints.ai_family = (ipv4_only ? AF_INET : AF_UNSPEC); \ hints.ai_socktype = SOCK_STREAM; \ hints.ai_protocol = IPPROTO_TCP; \ hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; \ } #define CLIENT_HINTS_AF(hints, af) \ { \ memset(&hints, 0, SIZEOF(struct addrinfo)); \ hints.ai_family = af; \ hints.ai_socktype = SOCK_STREAM; \ hints.ai_protocol = IPPROTO_TCP; \ hints.ai_flags = AI_V4MAPPED; \ } #else #error "Ok, so we do have non-AI_V4MAPPED/AI_NUMERICSERV machines with IPv6 support" #define SERVER_HINTS(hints, af) \ { \ memset(&hints, 0, SIZEOF(struct addrinfo)); \ hints.ai_family = af; \ hints.ai_socktype = SOCK_STREAM; \ hints.ai_protocol = IPPROTO_TCP; \ hints.ai_flags = AI_PASSIVE; \ } #define CLIENT_HINTS(hints) \ { \ memset(&hints, 0, SIZEOF(struct addrinfo)); \ hints.ai_family = (ipv4_only ? AF_INET : AF_UNSPEC); \ hints.ai_socktype = SOCK_STREAM; \ hints.ai_protocol = IPPROTO_TCP; \ hints.ai_flags = AI_ADDRCONFIG; \ } #define CLIENT_HINTS_AF(hints, af) \ { \ memset(&hints, 0, SIZEOF(struct addrinfo)); \ hints.ai_family = AF_INET; \ hints.ai_socktype = SOCK_STREAM; \ hints.ai_protocol = IPPROTO_TCP; \ hints.ai_flags = 0; \ } #endif #define FREEADDRINFO(ai_ptr) \ { \ if(ai_ptr) \ freeaddrinfo(ai_ptr); \ } union gtm_sockaddr_in46 { struct sockaddr_in ipv4; # if GTM_IPV6_SUPPORTED struct sockaddr_in6 ipv6; # endif }; #endif fis-gtm-V6.0-003/sr_port/gtm_limits.h0000644000032200000250000000502412201176156016355 0ustar librarygtc/**************************************************************** * * * Copyright 2002, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* Interlude to */ #ifndef GTM_LIMITSH #define GTM_LIMITSH #include #ifdef __hpux #include #endif /* The value 1023 for PATH_MAX is derived using pathconf("path", _PC_PATH_MAX) on z/OS and * we figure other POSIX platforms are at least as capable if they don't define PATH_MAX. * Since we can't afford to call a function on each use of PATH_MAX/GTM_PATH_MAX, this * value is hardcoded here. * * Note on Linux (at least), PATH_MAX is actually defined in . We would include * that here unconditionally but on AIX, param.h includes limits.h. Note that regardless of where * it gets defined, PATH_MAX needs to be defined prior to including stdlib.h. This is because in a * pro build, at least Linux verifies the 2nd parm of realpath() is PATH_MAX bytes or more. * Since param.h sets PATH_MAX to 4K on Linux, this can cause structures defined as GTM_PATH_MAX * to raise an error when used in the 2nd argument of realpath(). */ #ifndef PATH_MAX # ifdef __linux__ # include # else # define PATH_MAX 1023 # endif #endif /* Now define our version which includes space for a terminating NULL byte */ #define GTM_PATH_MAX PATH_MAX + 1 #if defined(LLONG_MAX) /* C99 and others */ #define GTM_INT64_MIN LLONG_MIN #define GTM_INT64_MAX LLONG_MAX #define GTM_UINT64_MAX ULLONG_MAX #elif defined(LONG_LONG_MAX) #define GTM_INT64_MIN LONG_LONG_MIN #define GTM_INT64_MAX LONG_LONG_MAX #define GTM_UINT64_MAX ULONG_LONG_MAX #elif defined(LONGLONG_MAX) #define GTM_INT64_MIN LONGLONG_MIN #define GTM_INT64_MAX LONGLONG_MAX #define GTM_UINT64_MAX ULONGLONG_MAX #elif defined(__INT64_MAX) /* OpenVMS Alpha */ #define GTM_INT64_MIN __INT64_MIN #define GTM_INT64_MAX __INT64_MAX #define GTM_UINT64_MAX __UINT64_MAX #elif defined(INTMAX_MAX) /* HP-UX */ #define GTM_INT64_MIN INTMAX_MIN #define GTM_INT64_MAX INTMAX_MAX #define GTM_UINT64_MAX UINTMAX_MAX #elif LONG_MAX != INT_MAX /* Tru64 */ #define GTM_INT64_MIN LONG_MIN #define GTM_INT64_MAX LONG_MAX #define GTM_UINT64_MAX ULONG_MAX #else #error Unable to determine 64 bit MAX in gtm_limits.h #endif #endif fis-gtm-V6.0-003/sr_port/gtm_malloc.c0000644000032200000250000000333012201176156016314 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2008 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_malloc -- the default version The bulk of the GTM storage manager code now sits in gtm_malloc_src.h and is included twice: once in gtm_malloc.c and again in gtm_malloc_dbg.c. The reason for this is that the production modules built for distribution in the field can have both forms of storage mgmt available in the event that it becomes necessary to chase a corruption issue. It can now be done without resorting to a "debug" version. Several different levels of debugging will also be made available to catch various problems. If the DEBUG flag is not defined (indicating a pro build), the gtm_malloc module will expand without all the asserts and special checking making for a compact and efficient storage manager. The gtm_malloc_dbg module will expand AS IF DEBUG had been specified supplying an alternate assert filled version of storage mgmnt with several different levels of storage validation available. If the DEBUG flag is defined (debug or beta build), the gtm_malloc module will expand with all debugging information intact and the gtm_malloc_dbg module will expand as call backs to the gtm_malloc module since it makes little sense to expand the identical module twice. */ #include "caller_id.h" #include "gtm_malloc_src.h" fis-gtm-V6.0-003/sr_port/gtm_malloc.h0000644000032200000250000000767112201176156016335 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_MALLOC_H__included #define GTM_MALLOC_H__included #define GTM_MEMORY_RESERVE_DEFAULT 64 /* 64K reserve "backpocket-cache" released on out-of-memory error */ typedef GTM64_ONLY(gtm_uint8) NON_GTM64_ONLY(unsigned int) gtm_msize_t; /* Each allocated block has the following structure. The actual address returned to the user for 'malloc' and supplied by the * user for 'free' is actually the storage beginning at the 'userStorage.userStart' area. This holds true even for storage * that is truely malloc'd. Note that true allocated length is kept even in the pro header. */ typedef struct storElemStruct { /* While the following chars and short are not the best for performance, they enable us to keep the header size to * 8 bytes in a pro build. This is important since our minimum allocation size is 16 bytes leaving 8 bytes for data. * Also I have not researched what they are, there are a bunch of 8 byte allocates in GT.M that if we were to go to * a 16 byte header would make the minimum block size 32 bytes thus doubling the storage requirements for these small * blocks. SE 03/2002 [Note 16 byte header is the norm in 64 bit] */ signed char queueIndex; /* Index into TwoTable for this size of element */ unsigned char state; /* State of this block */ unsigned short extHdrOffset; /* For MAXTWO sized elements: offset to the * header that describes the extent. */ GTM64_ONLY(char filler[4];) /* Explicit filler to align the length - may be repurposed */ gtm_msize_t realLen; /* Real (total) length of allocation */ # ifdef DEBUG struct storElemStruct *fPtr; /* Next storage element on free/allocated queue */ struct storElemStruct *bPtr; /* Previous storage element on free/allocated queue */ unsigned char *allocatedBy; /* Who allocated storage */ gtm_msize_t allocLen; /* Requested length of allocation */ gtm_msize_t smTn; /* Storage management transaction number allocated at */ unsigned char headMarker[GTM64_ONLY(8)NON_GTM64_ONLY(4)]; /* Header that should not be modified during usage */ union { struct storElemStruct *deferFreeNext; /* Pointer to next deferred free block */ unsigned char userStart; /* First byte of user useable storage */ } userStorage; # else union /* In production mode, the links are used only when element is free */ { struct storElemStruct *deferFreeNext; /* Pointer to next deferred free block */ struct /* Free block information */ { struct storElemStruct *fPtr; /* Next storage element on free queue */ struct storElemStruct *bPtr; /* Previous storage element on free queue */ } links; unsigned char userStart; /* First byte of user useable storage */ } userStorage; # endif } storElem; size_t gtm_bestfitsize(size_t); void verifyFreeStorage(void); void verifyAllocatedStorage(void); void raise_gtmmemory_error(void); void printMallocInfo(void); void printMallocDump(void); /* When verifying the storage chains, check the allocated chain first in case overruns for allocated storage * have damaged the free chains. This way we find the culprit rather than the symptom. Of course, in the case * where free'd storage is continued to be used, this method breaks down but it is hoped the chosen way finds * the greater number of issues rather than their symptoms. */ #define VERIFY_STORAGE_CHAINS \ { \ GBLREF uint4 gtmDebugLevel; \ if (GDL_SmAllocVerf & gtmDebugLevel) \ verifyAllocatedStorage(); \ if (GDL_SmFreeVerf & gtmDebugLevel) \ verifyFreeStorage(); \ } #endif /* GTM_MALLOC_H__included */ fis-gtm-V6.0-003/sr_port/gtm_malloc_dbg.c0000644000032200000250000000614512201176156017137 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_malloc_dbg -- the debugging version The bulk of the GTM storage manager code now sits in gtm_malloc_src.h and is included twice: once in gtm_malloc.c and again in gtm_malloc_dbg.c. The reason for this is that the production modules built for distribution in the field can have both forms of storage mgmt available in the event that it becomes necessary to chase a corruption issue. It can now be done without resorting to a "debug" version. Several different levels of debugging will also be made available to catch various problems. If the DEBUG flag is not defined (indicating a pro build), the gtm_malloc module will expand without all the asserts and special checking making for a compact and efficient storage manager. The gtm_malloc_dbg module will expand AS IF DEBUG had been specified supplying an alternate assert filled version of storage mgmnt with several different levels of storage validation available. If the DEBUG flag is defined (debug or beta build), the gtm_malloc module will expand with all debugging information intact and the gtm_malloc_dbg module will expand as call backs to the gtm_malloc module since it makes little sense to expand the identical module twice. */ #ifndef DEBUG /* We have a PRO build -- generate a full debug version with debug versions of our global names */ # define gtmSmInit gtmSmInit_dbg # define gtm_malloc gtm_malloc_dbg # define gtm_free gtm_free_dbg # define findStorElem findStorElem_dbg # define processDeferredFrees processDeferredFrees_dbg # define release_unused_storage release_unused_storage_dbg # define raise_gtmmemory_error raise_gtmmemory_error_dbg # define gtm_bestfitsize gtm_bestfitsize_dbg # define DEBUG # define PRO_BUILD # define GTM_MALLOC_DEBUG # include "caller_id.h" # include "gtm_malloc_src.h" #else /* We have a DEBUG build -- Nobody should call gtm_malloc_dbg directly */ # include "mdef.h" # include "gtm_malloc.h" /* Include some defs for these rtns to keep the compiler quiet for this routine. Nobody should be calling these directly so we don't want them where they can get included anywhere else. Note the real versions of these routines are defined and only used/callable from the gtm_malloc_src.h include so when we define them here for completeness in a dbg build, we change the return signature to not return anything (saves us from having to put a "return" after the GTMASSERTS). These are just "catchalls" in case the expansion functioned incorrectly. */ void gtm_malloc_dbg(size_t size); void gtm_free_dbg(void *addr); void gtm_malloc_dbg(size_t size) { GTMASSERT; } void gtm_free_dbg(void *addr) { GTMASSERT; } #endif fis-gtm-V6.0-003/sr_port/gtm_malloc_src.h0000644000032200000250000017040212201176156017175 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* Storage manager for "smaller" pieces of storage. Uses power-of-two * "buddy" system as described by Knuth. Currently manages pieces of * size 2K - SIZEOF(header). * * This include file is included in both gtm_malloc.c and gtm_malloc_dbg.c. * See the headers of those modules for explanations of how the storage * manager build is actually accomplished. * * Debugging is controlled via the "gtmdbglvl" environment variable in * the Unix environment and the GTM$DBGLVL logical in the VMS environment. * If this variable is set to a non-zero value, the debugging environment * is enabled. The debugging features turned on will correspond to the bit * values defined gtmdbglvl.h. Note that this mechanism is versatile enough * that non-storage-managment debugging is also hooked in here. The * debugging desired is a mask for the features desired. For example, if the * value 4 is set, then tracing is enabled. If the value is set to 6, then * both tracing and statistics are enabled. Because the code is expanded * twice in a "Pro" build, these debugging features are available even * in a pro build and can thus be enabled in the field without the need for * a "debug" version to be installed in order to chase a corruption or other * problem. */ #include "mdef.h" /* If this is a pro build (meaning PRO_BUILD is defined), avoid the memcpy() override. That code is only * appropriate for a pure debug build. */ #ifdef PRO_BUILD # define BYPASS_MEMCPY_OVERRIDE /* Instruct gtm_string.h not to override memcpy() */ #endif /* We are the redefined versions so use real versions in this module */ #undef malloc #undef free #include #include #include #include #include #include #if !defined(VMS) && !defined(__MVS__) # include #endif #include "gtm_stdio.h" #include "gtm_stdlib.h" #include "gtm_string.h" #include "eintr_wrappers.h" #include "gtmdbglvl.h" #include "io.h" #include "iosp.h" #include "min_max.h" #include "mdq.h" #include "error.h" #include "trans_log_name.h" #include "gtmmsg.h" #include "print_exit_stats.h" #include "mmemory.h" #include "gtm_logicals.h" #include "cache.h" #include "gtm_malloc.h" #include "have_crit.h" #include "gtm_env_init.h" #ifdef UNIX # include "gtmio.h" # include "deferred_signal_handler.h" #endif /* This routine is compiled twice, once as debug and once as pro and put into the same pro build. The alternative * memory manager is selected with the debug flags (any non-zero gtmdbglvl setting invokes debug memory manager in * a pro build). So the global variables (defined using the STATICD macro) have to be two different fields. * One for pro, one for dbg. The fields have different values and different sizes between the two compiles but * exist in the same build. They cannot coexist. That is why STATICD is defined to be static for PRO and GBLDEF for DBG. * This is the reason why we cannot use the STATICDEF macro here because that is defined to be a GBLDEF for PRO and DBG. * * To debug this routine effectively, normally static routines are turned into GBLDEFs. Also, for vars that * need one copy, define GBLRDEF to GBLDEF for debug and GBLREF for pro. This is because the pro builds always * have a debug version in them satisfiying the GBLREF but the debug builds won't have any pro code in them so * the define must be in the debug version. Also note that we cannot use the STATICDEF macro (instead of the * STATICD below) since that evaluates to a GBLDEF in both PRO and DBG which */ #ifdef DEBUG # define STATICD GBLDEF # define STATICR extern # define GBLRDEF GBLDEF #else # define STATICD static # define STATICR static # define GBLRDEF GBLREF #endif #ifdef GTM64 # define gmaAdr "%016lx" # define gmaFill " " # define gmaLine "--------" #else # define gmaAdr "%08lx" # define gmaFill " " # define gmaLine " " #endif #ifdef VMS /* These routines for VMS are AST-safe */ # define MALLOC(size, addr) \ { \ int msize, errnum; \ void *maddr; \ if ((0 < gtm_max_storalloc) && ((size + totalRmalloc + totalRallocGta) > gtm_max_storalloc)) \ { /* Boundary check for $gtm_max_storalloc (if set) */ \ gtmMallocErrorSize = size; \ gtmMallocErrorCallerid = CALLERID; \ gtmMallocErrorErrno = ERR_MALLOCMAXVMS; \ raise_gtmmemory_error(); \ } \ msize = size; \ errnum = lib$get_vm(&msize, &maddr); \ if (SS$_NORMAL != errnum) \ { \ gtmMallocErrorSize = size; \ gtmMallocErrorCallerid = CALLERID; \ gtmMallocErrorErrno = errnum; \ raise_gtmmemory_error(); \ } \ addr = (void *)maddr; \ } # define FREE(size, addr) \ { \ int msize, errnum; \ void *maddr; \ msize = size; \ maddr = addr; \ errnum = lib$free_vm(&msize, &maddr); \ if (SS$_NORMAL != errnum) \ { \ --gtmMallocDepth; \ assert(FALSE); \ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_FREEMEMORY, 1, CALLERID, errnum); \ } \ } # define GTM_MALLOC_REENT #else /* These routines for Unix are NOT thread-safe */ # define MALLOC(size, addr) \ { \ if ((0 < gtm_max_storalloc) && ((size + totalRmalloc + totalRallocGta) > gtm_max_storalloc)) \ { /* Boundary check for $gtm_max_storalloc (if set) */ \ gtmMallocErrorSize = size; \ gtmMallocErrorCallerid = CALLERID; \ gtmMallocErrorErrno = ERR_MALLOCMAXUNIX; \ raise_gtmmemory_error(); \ } \ addr = (void *)malloc(size); \ if (NULL == (void *)addr) \ { \ gtmMallocErrorSize = size; \ gtmMallocErrorCallerid = CALLERID; \ gtmMallocErrorErrno = errno; \ raise_gtmmemory_error(); \ } \ } # define FREE(size, addr) free(addr); #endif #ifdef GTM_MALLOC_REENT # define GMR_ONLY(statement) statement # define NON_GMR_ONLY(statement) #else # define GMR_ONLY(statement) # define NON_GMR_ONLY(statement) statement #endif #define MAXTWO 2048 /* How many "MAXTWO" elements to allocate at one time. This minimizes the waste since our subblocks must * be aligned on a suitable power of two boundary for the buddy-system to work properly. */ #define ELEMS_PER_EXTENT 16 #define MAXDEFERQUEUES 10 #ifdef DEBUG # define STOR_EXTENTS_KEEP 1 /* Keep only one extent in debug for maximum testing */ # define MINTWO NON_GTM64_ONLY(64) GTM64_ONLY(128) # define MAXINDEX NON_GTM64_ONLY(5) GTM64_ONLY(4) # define STE_FP(p) p->fPtr # define STE_BP(p) p->bPtr #else # define STOR_EXTENTS_KEEP 5 # define MINTWO NON_GTM64_ONLY(16) GTM64_ONLY(32) # define MAXINDEX NON_GTM64_ONLY(7) GTM64_ONLY(6) # define STE_FP(p) p->userStorage.links.fPtr # define STE_BP(p) p->userStorage.links.bPtr #endif /* Following are values used in queueIndex in a storage element. Note that both * values must be less than zero for the current code to function correctly. */ #define QUEUE_ANCHOR -1 #define REAL_MALLOC -2 /* Define number of malloc and free calls we will keep track of */ #define MAXSMTRACE 128 #ifdef DEBUG # define INCR_CNTR(x) ++x # define INCR_SUM(x, y) x += y # define DECR_CNTR(x) --x # define DECR_SUM(x, y) x -= y # define SET_MAX(max, tst) {max = MAX(max, tst);} # define SET_ELEM_MAX(qtype, idx) SET_MAX(qtype##ElemMax[idx], qtype##ElemCnt[idx]) # define TRACE_MALLOC(addr, len, tn) \ { \ if (GDL_SmTrace & gtmDebugLevel) \ DBGFPF((stderr, "Malloc at 0x%lx of %ld bytes from 0x%lx (tn=%ld)\n", addr, len, CALLERID, tn)); \ } # define TRACE_FREE(addr, len, tn) \ { \ if (GDL_SmTrace & gtmDebugLevel) \ DBGFPF((stderr, "Free at 0x%lx of %d bytes from 0x%lx (tn=%ld)\n", addr, len, CALLERID, tn)); \ } #else # define INCR_CNTR(x) # define INCR_SUM(x, y) # define DECR_CNTR(x) # define DECR_SUM(x, y) # define SET_MAX(max, tst) # define SET_ELEM_MAX(qtype, idx) # define TRACE_MALLOC(addr, len, tn) # define TRACE_FREE(addr, len, tn) #endif #ifdef DEBUG_SM # define DEBUGSM(x) (PRINTF x, FFLUSH(stdout)) # else # define DEBUGSM(x) #endif /* Macro to return an index into the TwoTable for a given size (round up to next power of two) * Use the size2Index table to get the proper index. This table is indexed by the number of * storage "blocks" being requested. A storage block is the size of the smallest power of two * block we can allocate (size MINTWO). */ #ifdef DEBUG # define GetSizeIndex(size) (size ? size2Index[(size - 1) / MINTWO] : assert(FALSE)) #else # define GetSizeIndex(size) (size2Index[(size - 1) / MINTWO]) #endif /* Note we use unsigned char * instead of caddr_t for all references to caller_id so the caller id * is always 4 bytes. On Tru64, caddr_t is 8 bytes which will throw off the size of our * storage header in debug mode. */ #ifdef GTM_MALLOC_DEBUG # define CALLERID (smCallerId) #else # define CALLERID ((unsigned char *)caller_id()) #endif /* Define "routines" to enqueue and dequeue storage elements. Use define so we don't * have to depend on each implementation's compiler inlining to get efficient code here. */ #define ENQUEUE_STOR_ELEM(qtype, idx, elem) \ { \ storElem *qHdr, *fElem; \ qHdr = &qtype##StorElemQs[idx]; \ STE_FP(elem) = fElem = STE_FP(qHdr); \ STE_BP(elem) = qHdr; \ STE_FP(qHdr) = STE_BP(fElem) = elem; \ INCR_CNTR(qtype##ElemCnt[idx]); \ SET_ELEM_MAX(qtype, idx); \ } #define DEQUEUE_STOR_ELEM(qtype, elem) \ { \ STE_FP(STE_BP(elem)) = STE_FP(elem); \ STE_BP(STE_FP(elem)) = STE_BP(elem); \ DECR_CNTR(qtype##ElemCnt[elem->queueIndex]); \ } #define GET_QUEUED_ELEMENT(sizeIndex, uStor, qHdr, sEHdr) \ { \ qHdr = &freeStorElemQs[sizeIndex]; \ uStor = STE_FP(qHdr); /* First element on queue */ \ if (QUEUE_ANCHOR != uStor->queueIndex) /* Does element exist? (Does queue point to itself?) */ \ { \ DEQUEUE_STOR_ELEM(free, uStor); /* It exists, dequeue it for use */ \ if (MAXINDEX == sizeIndex) \ { /* Allocating a MAXTWO block. Increment use counter for this subblock's block */ \ sEHdr = (storExtHdr *)((char *)uStor + uStor->extHdrOffset); \ ++sEHdr->elemsAllocd; \ } \ } else \ uStor = findStorElem(sizeIndex); \ assert(0 == ((unsigned long)uStor & (TwoTable[sizeIndex] - 1))); /* Verify alignment */ \ } #ifdef INT8_SUPPORTED # define ChunkSize 8 # define ChunkType gtm_int64_t # define ChunkValue 0xdeadbeefdeadbeefLL #else # define ChunkSize 4 # define ChunkType int4 # define ChunkValue 0xdeadbeef #endif #define AddrMask (ChunkSize - 1) /* States that storage can be in (although the possibilities are limited with only one byte of information) */ enum ElemState {Allocated = 0x42, Free = 0x24}; /* At the end of each super-block is this header which is used to track when all of the elements that * a block of real allocated storage was broken into have become free. At that point, we can return * the chunk to the OS. */ typedef struct storExtHdrStruct { struct { struct storExtHdrStruct *fl, *bl; /* In case we need to visit the entire list */ } links; unsigned char *extentStart; /* First byte of real extent (not aligned) */ storElem *elemStart; /* Start of array of MAXTWO elements */ int elemsAllocd; /* MAXTWO sized element count. When 0 this block is free */ } storExtHdr; /* Structure where malloc and free call trace information is kept */ typedef struct { unsigned char *smAddr; /* Addr allocated or released */ unsigned char *smCaller; /* Who called malloc/free */ gtm_msize_t smSize; /* Size allocated or freed */ gtm_msize_t smTn; /* What transaction it was */ } smTraceItem; /* Our extent must be aligned on a MAXTWO byte boundary hence we allocate one more extent than * we actually want so we can be guarranteed usable storage. However if that allocation actually * starts on a MAXTWO boundary (on guarranteed 8 byte boundary), then we get an extra element. * Here we define our extent size and provide an initial sanity value for "extent_used". If the * allocator ever gets this extra block, this field will be increased by the size of one element * to compensate. */ #define EXTENT_SIZE ((MAXTWO * (ELEMS_PER_EXTENT + 1)) + SIZEOF(storExtHdr)) static unsigned int extent_used = ((MAXTWO * ELEMS_PER_EXTENT) + SIZEOF(storExtHdr)); #ifdef DEBUG /* For debug builds, keep track of the last MAXSMTRACE mallocs and frees. */ GBLDEF volatile int smLastMallocIndex; /* Index to entry of last malloc-er */ GBLDEF volatile int smLastFreeIndex; /* Index to entry of last free-er */ GBLDEF smTraceItem smMallocs[MAXSMTRACE]; /* Array of recent allocators */ GBLDEF smTraceItem smFrees[MAXSMTRACE]; /* Array of recent releasers */ GBLDEF volatile unsigned int smTn; /* Storage management (wrappable) transaction number */ GBLDEF unsigned int outOfMemorySmTn; /* smTN when ran out of memory */ #endif GBLREF uint4 gtmDebugLevel; /* Debug level (0 = using default sm module so with * a DEBUG build, even level 0 implies basic debugging) */ GBLREF int process_exiting; /* Process is on it's way out */ GBLREF volatile int4 gtmMallocDepth; /* Recursion indicator. Volatile so it gets stored immediately */ GBLREF volatile void *outOfMemoryMitigation; /* Reserve that we will freed to help cleanup if run out of memory */ GBLREF uint4 outOfMemoryMitigateSize; /* Size of above reserve in Kbytes */ GBLREF int mcavail; GBLREF mcalloc_hdr *mcavailptr, *mcavailbase; GBLREF size_t totalRallocGta; /* Size allocated by gtm_text_alloc if at all */ GBLREF size_t gtm_max_storalloc; /* Max value for $ZREALSTOR or else memory error is raised */ GBLREF void (*cache_table_relobjs)(void); /* Function pointer to call cache_table_rebuild() */ UNIX_ONLY(GBLREF ch_ret_type (*ht_rhash_ch)();) /* Function pointer to hashtab_rehash_ch */ UNIX_ONLY(GBLREF ch_ret_type (*jbxm_dump_ch)();) /* Function pointer to jobexam_dump_ch */ UNIX_ONLY(GBLREF ch_ret_type (*stpgc_ch)();) /* Function pointer to stp_gcol_ch */ /* This var allows us to call ourselves but still have callerid info */ GBLREF unsigned char *smCallerId; /* Caller of top level malloc/free */ GBLREF volatile int4 fast_lock_count; /* Stop stale/epoch processing while we have our parts exposed */ OS_PAGE_SIZE_DECLARE #define SIZETABLEDIM MAXTWO/MINTWO STATICD int size2Index[SIZETABLEDIM]; GBLRDEF boolean_t gtmSmInitialized; /* Initialized indicator */ GBLRDEF size_t gtmMallocErrorSize; /* Size of last failed malloc */ GBLRDEF unsigned char *gtmMallocErrorCallerid; /* Callerid of last failed malloc */ GBLRDEF int gtmMallocErrorErrno; /* Errno at point of last failure */ GBLRDEF readonly struct { unsigned char nullHMark[4]; unsigned char nullStr[1]; unsigned char nullTMark[4]; } NullStruct #ifdef DEBUG /* Note, tiz important the first 4 bytes of this are same as markerChar defined below as that is the value both nullHMark * and nullTMark are asserted against to validate against corruption. */ = {0xde, 0xad, 0xbe, 0xef, 0x00, 0xde, 0xad, 0xbe, 0xef} #endif ; #ifdef DEBUG /* Arrays allocated with size of MAXINDEX + 2 are sized to hold an extra * entry for "real malloc" type allocations. Note that the arrays start with * the next larger element with GTM64 due to increased overhead from the * 8 byte pointers. */ STATICD readonly uint4 TwoTable[MAXINDEX + 2] = { # ifndef GTM64 64, # endif 128, 256, 512, 1024, 2048, 0xFFFFFFFF}; /* Powers of two element sizes */ # ifdef GTM64 STATICD readonly unsigned char markerChar[8] = {0xde, 0xad, 0xbe, 0xef, 0xef, 0xbe, 0xad, 0xde}; # else STATICD readonly unsigned char markerChar[4] = {0xde, 0xad, 0xbe, 0xef}; # endif #else STATICD readonly uint4 TwoTable[MAXINDEX + 2] = { # ifndef GTM64 16, # endif 32, 64, 128, 256, 512, 1024, 2048, 0xFFFFFFFF}; #endif STATICD storElem freeStorElemQs[MAXINDEX + 1]; /* Need full element as queue anchor for dbl-linked * list since ptrs not at top of element. */ STATICD storExtHdr storExtHdrQ; /* List of storage blocks we allocate here */ STATICD uint4 curExtents; /* Number of current extents */ #ifdef GTM_MALLOC_REENT STATICD storElem *deferFreeQueues[MAXDEFERQUEUES]; /* Where deferred (nested) frees are queued for later processing */ STATICD boolean_t deferFreeExists; /* A deferred free is pending on a queue */ #endif #ifdef DEBUG STATICD storElem allocStorElemQs[MAXINDEX + 2]; /* The extra element is for queueing "real" malloc'd entries */ # ifdef INT8_SUPPORTED STATICD readonly unsigned char backfillMarkC[8] = {0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}; # else STATICD readonly unsigned char backfillMarkC[4] = {0xde, 0xad, 0xbe, 0xef}; # endif #endif GBLREF size_t totalRmalloc; /* Total storage currently (real) malloc'd (includes extent blocks) */ GBLREF size_t totalAlloc; /* Total allocated (includes allocation overhead but not free space */ GBLREF size_t totalUsed; /* Sum of user allocated portions (totalAlloc - overhead) */ #ifdef DEBUG /* Define variables used to instrument how our algorithm works */ STATICD uint4 totalMallocs; /* Total malloc requests */ STATICD uint4 totalFrees; /* Total free requests */ STATICD uint4 totalExtents; /* Times we allocated more storage */ STATICD uint4 maxExtents; /* Highwater mark of extents */ STATICD size_t rmallocMax; /* Maximum value of totalRmalloc */ STATICD uint4 mallocCnt[MAXINDEX + 2]; /* Malloc count satisfied by each queue size */ STATICD uint4 freeCnt[MAXINDEX + 2]; /* Free count for element in each queue size */ STATICD uint4 elemSplits[MAXINDEX + 2]; /* Times a given queue size block was split */ STATICD uint4 elemCombines[MAXINDEX + 2]; /* Times a given queue block was formed by buddies being recombined */ STATICD uint4 freeElemCnt[MAXINDEX + 2]; /* Current count of elements on the free queue */ STATICD uint4 allocElemCnt[MAXINDEX + 2]; /* Current count of elements on the allocated queue */ STATICD uint4 freeElemMax[MAXINDEX + 2]; /* Maximum number of blocks on the free queue */ STATICD uint4 allocElemMax[MAXINDEX + 2]; /* Maximum number of blocks on the allocated queue */ GMR_ONLY(STATICD uint4 reentMallocs;) /* Total number of reentrant mallocs made */ GMR_ONLY(STATICD uint4 deferFreePending;) /* Total number of frees that were deferred */ #endif error_def(ERR_INVMEMRESRV); error_def(ERR_MEMORYRECURSIVE); UNIX_ONLY(error_def(ERR_MEMORY);) UNIX_ONLY(error_def(ERR_SYSCALL);) UNIX_ONLY(error_def(ERR_MALLOCMAXUNIX);) VMS_ONLY(error_def(ERR_FREEMEMORY);) VMS_ONLY(error_def(ERR_VMSMEMORY);) VMS_ONLY(error_def(ERR_MALLOCMAXVMS);) /* Internal prototypes */ void gtmSmInit(void); storElem *findStorElem(int sizeIndex); void release_unused_storage(void); #ifdef DEBUG void backfill(unsigned char *ptr, gtm_msize_t len); boolean_t backfillChk(unsigned char *ptr, gtm_msize_t len); #else void *gtm_malloc_dbg(size_t); void gtm_free_dbg(void *); void raise_gtmmemory_error_dbg(void); size_t gtm_bestfitsize_dbg(size_t); #endif VMS_ONLY(error_def(ERR_FREEMEMORY);) error_def(ERR_INVMEMRESRV); UNIX_ONLY(error_def(ERR_MEMORY);) error_def(ERR_MEMORYRECURSIVE); VMS_ONLY(error_def(ERR_VMSMEMORY);) UNIX_ONLY(error_def(ERR_SYSCALL);) /* Initialize the storage manangement system. Things to initialize: * * - Initialize size2Index table. This table is used to convert a malloc request size * to a storage queue index. * - Initialize queue anchor fwd/bkwd pointers to point to queue anchors so we * build a circular queue. This allows elements to be added and removed without * end-of-queue special casing. The queue anchor element is easily recognized because * it's queue index size will be set to a special value. * - Initialize debug mode. See if gtm_debug_level environment variable is set and * retrieve it's value if yes. */ void gtmSmInit(void) /* Note renamed to gtmSmInit_dbg when included in gtm_malloc_dbg.c */ { char *ascNum; storElem *uStor; int i, sizeIndex, testSize, blockSize, save_errno; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; /* If this routine is entered and environment vars have not yet been processed with a call to gtm_env_init(), * then do this now. Since this will likely trigger a call to this routine *again*, verify if we still need * to do this and if not, just return. */ if (!TREF(gtm_env_init_started)) { gtm_env_init(); if (gtmSmInitialized) return; /* A nested call took care of this already so we're done! */ } /* WARNING!! Since this is early initialization, the following asserts are not well behaved if they do * indeed trip. The best that can be hoped for is they give a condition handler exhausted error on * GTM startup. Unfortunately, more intelligent responses are somewhat elusive since no output devices * are setup nor (potentially) most of the GTM runtime. */ assert(MINTWO == TwoTable[0]); # if defined(__linux__) && !defined(__i386) /* This will make sure that all the memory allocated using 'malloc' will be in heap and no 'mmap' is used. * This is needed to make sure that the offset calculation that we do at places(que_ent, chache_que, etc..) * using 2 'malloc'ed memory can be hold in an integer. Though this will work without any problem as the * current GT.M will not allocate memory more than 4GB, we should find a permanant solution by migrating those * offset fields to long and make sure all other related application logic works fine. */ mallopt(M_MMAP_MAX, 0); # endif /* __linux__ && !__i386 */ /* Check that the storage queue offset in a storage element has sufficient reach * to cover an extent. */ assert(((extent_used - SIZEOF(storExtHdr)) <= ((1 << (SIZEOF(uStor->extHdrOffset) * 8)) - 1))); /* Initialize size table used to get a storage queue index */ sizeIndex = 0; testSize = blockSize = MINTWO; for (i = 0; i < SIZETABLEDIM; i++, testSize += blockSize) { if (testSize > TwoTable[sizeIndex]) ++sizeIndex; size2Index[i] = sizeIndex; } /* Need to initialize the fwd/bck ptrs in the anchors to point to themselves */ for (uStor = &freeStorElemQs[0], i = 0; i <= MAXINDEX; ++i, ++uStor) { STE_FP(uStor) = STE_BP(uStor) = uStor; uStor->queueIndex = QUEUE_ANCHOR; } DEBUG_ONLY( for (uStor = &allocStorElemQs[0], i = 0; i <= (MAXINDEX + 1); ++i, ++uStor) { STE_FP(uStor) = STE_BP(uStor) = uStor; uStor->queueIndex = QUEUE_ANCHOR; } ); dqinit(&storExtHdrQ, links); /* One last task before we consider ourselves initialized. Allocate the out-of-memory mitigation storage * that we will hold onto but not use. If we get an out-of-memory error, this storage will be released back * to the OS for it or GTM to use as necessary while we try to go about an orderly shutdown of our process. * The term "release" here means a literal release. The thinking is we don't know whether GTM's small storage * manager will make use of this storage (32K at a time) or if a larger malloc() will be done by libc for * buffers or what not so we will just give this chunk back to the OS to use as it needs it. */ if (0 < outOfMemoryMitigateSize) { assert(NULL == outOfMemoryMitigation); outOfMemoryMitigation = malloc(outOfMemoryMitigateSize * 1024); if (NULL == outOfMemoryMitigation) { save_errno = errno; gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_INVMEMRESRV, 2, RTS_ERROR_LITERAL(UNIX_ONLY("$gtm_memory_reserve")VMS_ONLY("GTM_MEMORY_RESERVE")), save_errno); exit(save_errno); } } gtmSmInitialized = TRUE; } /* Recursive routine used to obtain an element on a given size queue. If no * elements of that size are available, we recursively call ourselves to get * an element of the next larger queue which we will then split in half to * get the one we need and place the remainder back on the free queue of its * new smaller size. If we run out of queues, we obtain a fresh new 'hunk' of * storage, carve it up into the largest block size we handle and process as * before. */ storElem *findStorElem(int sizeIndex) /* Note renamed to findStorElem_dbg when included in gtm_malloc_dbg.c */ { unsigned char *uStorAlloc; storElem *uStor, *uStor2, *qHdr; storExtHdr *sEHdr; int hdrSize; unsigned int i; ++sizeIndex; DEBUG_ONLY(hdrSize = OFFSETOF(storElem, userStorage)); /* Size of storElem header */ if (MAXINDEX >= sizeIndex) { /* We have more queues to search */ GET_QUEUED_ELEMENT(sizeIndex, uStor, qHdr, sEHdr); /* We have a larger than necessary element now so break it in half and put * the second half on the queue one size smaller than us. */ INCR_CNTR(elemSplits[sizeIndex]); --sizeIndex; /* Dealing now with smaller element queue */ assert(sizeIndex >= 0 && sizeIndex < MAXINDEX); uStor2 = (storElem *)((unsigned long)uStor + TwoTable[sizeIndex]); uStor2->state = Free; uStor2->queueIndex = sizeIndex; assert(0 == ((unsigned long)uStor2 & (TwoTable[sizeIndex] - 1))); /* Verify alignment */ DEBUG_ONLY( memcpy(uStor2->headMarker, markerChar, SIZEOF(uStor2->headMarker)); /* Put header tag in place */ /* Backfill entire block being freed so usage of it will cause problems */ if (GDL_SmBackfill & gtmDebugLevel) backfill((unsigned char *)uStor2 + hdrSize, TwoTable[sizeIndex] - hdrSize); ); ENQUEUE_STOR_ELEM(free, sizeIndex, uStor2); /* Place on free queue */ } else { /* Nothing left to search, [real]malloc a new ALIGNED block of storage and put it on our queues */ ++curExtents; SET_MAX(maxExtents, curExtents); INCR_CNTR(totalExtents); /* Allocate size for one more subblock than we want. This guarrantees us that we can put our subblocks * on a power of two boundary necessary for buddy alignment. */ MALLOC(EXTENT_SIZE, uStorAlloc); uStor2 = (storElem *)uStorAlloc; /* Make addr "MAXTWO" byte aligned */ uStor = (storElem *)(((unsigned long)(uStor2) + MAXTWO - 1) & (unsigned long) -MAXTWO); totalRmalloc += EXTENT_SIZE; SET_MAX(rmallocMax, totalRmalloc); sEHdr = (storExtHdr *)((char *)uStor + (ELEMS_PER_EXTENT * MAXTWO)); DEBUGSM(("debugsm: Allocating extent at 0x%08lx\n", uStor)); /* If the storage given to us was aligned, we have ELEMS_PER_EXTENT+1 blocks, else we have * ELEMS_PER_EXTENT blocks. We won't put the first element on the queue since that block is * being returned to be split. */ if (uStor == uStor2) { i = 0; /* The storage was suitably aligned, we get an extra block free */ sEHdr = (storExtHdr *)((char *)sEHdr + MAXTWO); extent_used = EXTENT_SIZE; /* New max for sanity checks */ } else i = 1; /* The storage was not aligned. Have planned number of blocks with some waste */ assert(((char *)sEHdr + SIZEOF(*sEHdr)) <= ((char *)uStorAlloc + EXTENT_SIZE)); for (uStor2 = uStor; ELEMS_PER_EXTENT > i; ++i) { /* Place all but first entry on the queue */ uStor2 = (storElem *)((unsigned long)uStor2 + MAXTWO); assert(0 == ((unsigned long)uStor2 & (TwoTable[MAXINDEX] - 1))); /* Verify alignment */ uStor2->state = Free; uStor2->queueIndex = MAXINDEX; uStor2->extHdrOffset = (char *)sEHdr - (char *)uStor2; assert(extent_used > uStor2->extHdrOffset); DEBUG_ONLY( memcpy(uStor2->headMarker, markerChar, SIZEOF(uStor2->headMarker)); /* Backfill entire block on free queue so we can detect trouble * with premature usage or overflow from something else */ if (GDL_SmBackfill & gtmDebugLevel) backfill((unsigned char *)uStor2 + hdrSize, TwoTable[MAXINDEX] - hdrSize); ); ENQUEUE_STOR_ELEM(free, MAXINDEX, uStor2); /* Place on free queue */ } uStor->extHdrOffset = (char *)sEHdr - (char *)uStor; uStor->state = Free; sizeIndex = MAXINDEX; /* Set up storage block header */ sEHdr->extentStart = uStorAlloc; sEHdr->elemStart = uStor; sEHdr->elemsAllocd = 1; dqins(&storExtHdrQ, links, sEHdr); } assert(sizeIndex >= 0 && sizeIndex <= MAXINDEX); uStor->queueIndex = sizeIndex; /* This is now a smaller block */ return uStor; } #ifdef GTM_MALLOC_REENT /* Routine to process deferred frees in the deferred free queues */ void processDeferredFrees() /* Note renamed to processDeferredFrees_dbg when included in gtm_malloc_dbg.c */ { int dqIndex; storElem *uStor, *uStorNext; assert(0 == gtmMallocDepth); do { deferFreeExists = FALSE; /* Run queue in reverse order so we can process the highest index queues first freeing them * up that much sooner. This eliminates the problem of index creep. */ for (dqIndex = MAXDEFERQUEUES - 1; 0 <= dqIndex; --dqIndex) { /* Check if queue is empty or not once outside of the gtmMallocDepth lock 'cause * we don't want to get the lock unless we really need to. */ if (deferFreeQueues[dqIndex]) { gtmMallocDepth = dqIndex + 2; uStor = deferFreeQueues[dqIndex]; /* Dequeue entire chain at this location */ deferFreeQueues[dqIndex] = NULL; gtmMallocDepth = 0; for (; uStor; uStor = uStorNext) /* Release all elements on this queue */ { uStorNext = uStor->userStorage.deferFreeNext; gtm_free(&uStor->userStorage.userStart); } } } } while (deferFreeExists); } #endif /* Note, if the below declaration changes, corresponding changes in gtmxc_types.h needs to be done. */ /* Obtain free storage of the given size */ void *gtm_malloc(size_t size) /* Note renamed to gtm_malloc_dbg when included in gtm_malloc_dbg.c */ { unsigned char *retVal; storElem *uStor, *qHdr; storExtHdr *sEHdr; gtm_msize_t tSize; int sizeIndex, i, hdrSize; unsigned char *trailerMarker; boolean_t reentered; # ifndef DEBUG /* If we are not expanding for DEBUG, check now if DEBUG has been turned on. * If it has, we are in the wrong module Jack. This IF is structured so that * if this is the normal (default/optimized) case we will fall into the code * and handle the rerouting at the end. */ if (GDL_None == gtmDebugLevel) { # endif /* Note that this if is also structured for maximum fallthru. The else will * be near the end of this entry point. */ if (gtmSmInitialized) { hdrSize = OFFSETOF(storElem, userStorage); /* Size of storElem header */ NON_GTM64_ONLY(assertpro((size + hdrSize) >= size)); /* Check for wrap in 32 bit platforms */ assert((hdrSize + SIZEOF(markerChar)) < MINTWO); NON_GMR_ONLY(fast_lock_count++); ++gtmMallocDepth; /* Nesting depth of memory calls */ reentered = (1 < gtmMallocDepth); NON_GMR_ONLY( if (reentered) { --gtmMallocDepth; assert(FALSE); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MEMORYRECURSIVE); } ); INCR_CNTR(totalMallocs); INCR_CNTR(smTn); /* Validate null string not overwritten */ assert(0 == memcmp(&NullStruct.nullHMark[0], markerChar, SIZEOF(NullStruct.nullHMark))); assert(0 == memcmp(&NullStruct.nullTMark[0], markerChar, SIZEOF(NullStruct.nullHMark))); DEBUG_ONLY( GMR_ONLY(if (!reentered)) { /* Verify the storage chains before we play */ VERIFY_STORAGE_CHAINS; } ); if (0 != size) { GMR_ONLY(size = MAX(SIZEOF(char *), size);) /* Need room for deferred free next pointer */ tSize = size + hdrSize; /* Add in header size */ DEBUG_ONLY( tSize += SIZEOF(markerChar); /* Add in room for trailer label */ /* If being a storage hog, we want to make sure we have plenty of room for * filler. For strings up to MAXTWO in length, we pad with an additional 50% * of storage with a minimum of 32 bytes and a maximum of 256 bytes. For larger * strings, we pad with 256 bytes. Since selecting GDL_SmStorHog also turns on * GDL_SmBackfill and GDL_SmChkAllocBackfill, this padding will be backfilled and * checked during allocate storage validation calls. */ if (GDL_SmStorHog & gtmDebugLevel) { if (MAXTWO >= size) tSize += (MIN(MAX(size / 2, 32), 256)); else tSize += 256; } ); /* The difference between $ZALLOCSTOR and $ZUSEDSTOR (totalAlloc and totalUsed global vars) is * that when you allocate, say 16 bytes, that comes out of a 32 byte chunk (with the pro storage * mgr) with the rest being unusable. In a debug build (or a pro build with $gtmdbglvl set to * something non-zero), $ZUSEDSTOR is incremented by 16 bytes (the requested allocation) while * $ZALLOCSTOR is incremented by 32 bytes (the actual allocation). But, in a pro build using * the pro memory manager, we do not track the user-allocated size anywhere. We know it when * we do the allocation of course, but when it comes time to free it, we no longer know what * the user requested size was. We only know that it came out of a 32 byte block. In order for * the free to be consistent with the allocation, we have to use the one value we know at both * malloc and free times - 32 bytes. The net result is that $ZALLOCSTOR and $ZUSEDSTOR report * the same value in a pro build with the pro stmgr while they will be quite different in a * debug build or a pro build with $gtmdbglvl engaged. The difference between them shows the * allocation overhead of gtm_malloc itself. */ if (MAXTWO >= tSize GMR_ONLY(&& !reentered)) { /* Use our memory manager for smaller pieces */ sizeIndex = GetSizeIndex(tSize); /* Get index to size we need */ assert(sizeIndex >= 0 && sizeIndex <= MAXINDEX); GET_QUEUED_ELEMENT(sizeIndex, uStor, qHdr, sEHdr); tSize = TwoTable[sizeIndex]; uStor->realLen = tSize; } else { /* Use regular malloc to obtain the piece */ MALLOC(tSize, uStor); totalRmalloc += tSize; SET_MAX(rmallocMax, totalRmalloc); uStor->queueIndex = REAL_MALLOC; uStor->realLen = tSize; DEBUG_ONLY(sizeIndex = MAXINDEX + 1); /* Just so the ENQUEUE below has a queue since * we use -1 as the "real" queueindex for * malloc'd storage and we don't record allocated * storage in other than debug mode. */ } totalUsed += DEBUG_ONLY(size) PRO_ONLY(tSize); totalAlloc += tSize; INCR_CNTR(mallocCnt[sizeIndex]); uStor->state = Allocated; # ifdef DEBUG /* Fill in extra debugging fields in header */ uStor->allocatedBy = CALLERID; /* Who allocated us */ uStor->allocLen = size; /* User requested size */ memcpy(uStor->headMarker, markerChar, SIZEOF(uStor->headMarker)); trailerMarker = (unsigned char *)&uStor->userStorage.userStart + size; /* Where to put trailer */ memcpy(trailerMarker, markerChar, SIZEOF(markerChar)); /* Small trailer */ if (GDL_SmInitAlloc & gtmDebugLevel) /* Initialize the space we are allocating */ backfill((unsigned char *)&uStor->userStorage.userStart, size); if (GDL_SmBackfill & gtmDebugLevel) { /* Use backfill method of after-allocation metadata */ backfill(trailerMarker + SIZEOF(markerChar), (uStor->realLen - size - hdrSize - SIZEOF(markerChar))); } uStor->smTn = smTn; /* Transaction number */ GMR_ONLY(if (!reentered)) { ENQUEUE_STOR_ELEM(alloc, sizeIndex, uStor); } # ifdef GTM_MALLOC_REENT else { /* Reentrant allocates cannot be put on our allocated queue -- sorry too dangerous */ uStor->fPtr = uStor->bPtr = NULL; INCR_CNTR(allocElemCnt[sizeIndex]); INCR_CNTR(reentMallocs); } # endif # endif retVal = &uStor->userStorage.userStart; assert(((long)retVal & (long)-8) == (long)retVal); /* Assert we have an 8 byte boundary */ } else /* size was 0 */ retVal = &NullStruct.nullStr[0]; DEBUG_ONLY( /* Record this transaction in debugging history */ ++smLastMallocIndex; if (MAXSMTRACE <= smLastMallocIndex) smLastMallocIndex = 0; smMallocs[smLastMallocIndex].smAddr = retVal; smMallocs[smLastMallocIndex].smSize = size; smMallocs[smLastMallocIndex].smCaller = CALLERID; smMallocs[smLastMallocIndex].smTn = smTn; ); TRACE_MALLOC(retVal, size, smTn); --gtmMallocDepth; GMR_ONLY( /* Check on deferred frees */ if (0 == gtmMallocDepth && deferFreeExists) processDeferredFrees(); ); NON_GMR_ONLY(--fast_lock_count); DEFERRED_EXIT_HANDLING_CHECK; return retVal; } else /* Storage mgmt has not been initialized */ { gtmSmInit(); /* Reinvoke gtm_malloc now that we are initialized. Note that this one time (the first * call to malloc), we will not record the proper caller id in the storage header or in * the traceback table. The caller will show up as gtm_malloc(). However, all subsequent * calls will be correct. */ return (void *)gtm_malloc(size); } # ifndef DEBUG } else { /* We have a non-DEBUG module but debugging is turned on so redirect the call to the appropriate module */ smCallerId = (unsigned char *)caller_id(); return (void *)gtm_malloc_dbg(size); } # endif } /* Note, if the below declaration changes, corresponding changes in gtmxc_types.h needs to be done. */ /* Release the free storage at the given address */ void gtm_free(void *addr) /* Note renamed to gtm_free_dbg when included in gtm_malloc_dbg.c */ { storElem *uStor, *buddyElem; storExtHdr *sEHdr; unsigned char *trailerMarker; int sizeIndex, hdrSize, saveIndex, dqIndex, freedElemCnt; gtm_msize_t saveSize, allocSize; # ifndef DEBUG /* If we are not expanding for DEBUG, check now if DEBUG has been turned on. * If it has, we are in the wrong module Jack. This IF is structured so that * if this is the normal (optimized) case we will fall into the code and * handle the rerouting at the end. */ if (GDL_None == gtmDebugLevel) { # endif assertpro(gtmSmInitialized); /* Storage must be init'd before can free anything */ /* If we are exiting, don't bother with frees. Process destruction can do it *UNLESS* we are handling an * out of memory condition with the proviso that we can't return memory if we are already nested. */ if (process_exiting && (0 != gtmMallocDepth || error_condition != UNIX_ONLY(ERR_MEMORY) VMS_ONLY(ERR_VMSMEMORY))) return; NON_GMR_ONLY(++fast_lock_count); ++gtmMallocDepth; /* Recursion indicator */ # ifdef GTM_MALLOC_REENT /* If we are attempting to do a reentrant free, we will instead put the free on a queue to be released * at a later time. Ironically, since we cannot be sure of any queues of available blocks, we have to * malloc a small block to carry this info which we will free with the main storage. */ if (1 < gtmMallocDepth) { if ((unsigned char *)addr != &NullStruct.nullStr[0]) { dqIndex = gtmMallocDepth - 2; /* 0 origin index into defer queues */ assertpro(MAXDEFERQUEUES > dqIndex); /* Can't run out of queues */ hdrSize = offsetof(storElem, userStorage); uStor = (storElem *)((unsigned long)addr - hdrSize); /* Backup ptr to element header */ uStor->userStorage.deferFreeNext = deferFreeQueues[dqIndex]; deferFreeQueues[dqIndex] = uStor; deferFreeExists = TRUE; INCR_CNTR(deferFreePending); } --gtmMallocDepth; return; } # else if (1 < gtmMallocDepth) { --gtmMallocDepth; assert(FALSE); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MEMORYRECURSIVE); } # endif INCR_CNTR(smTn); /* Bump the transaction number */ /* Validate null string not overwritten */ assert(0 == memcmp(&NullStruct.nullHMark[0], markerChar, SIZEOF(NullStruct.nullHMark))); assert(0 == memcmp(&NullStruct.nullTMark[0], markerChar, SIZEOF(NullStruct.nullHMark))); /* verify chains before we attempt dequeue */ DEBUG_ONLY(VERIFY_STORAGE_CHAINS); INCR_CNTR(totalFrees); if ((unsigned char *)addr != &NullStruct.nullStr[0]) { hdrSize = OFFSETOF(storElem, userStorage); uStor = (storElem *)((unsigned long)addr - hdrSize); /* Backup ptr to element header */ sizeIndex = uStor->queueIndex; # ifdef DEBUG if (GDL_SmInitAlloc & gtmDebugLevel) /* Initialize the space we are de-allocating */ backfill((unsigned char *)&uStor->userStorage.userStart, uStor->allocLen); TRACE_FREE(addr, uStor->allocLen, smTn); saveSize = uStor->allocLen; /* Extra checking for debugging. Note that these sanity checks are only done in debug * mode. The thinking is that we will bypass the checks in the general case for speed but * if we really need to chase a storage related problem, we should switch to the debug version * in the field to turn on these and other checks. */ assert(Allocated == uStor->state); assert(0 == memcmp(uStor->headMarker, markerChar, SIZEOF(uStor->headMarker))); trailerMarker = (unsigned char *)&uStor->userStorage.userStart + uStor->allocLen;/* Where trailer was put */ assert(0 == memcmp(trailerMarker, markerChar, SIZEOF(markerChar))); if (GDL_SmChkAllocBackfill & gtmDebugLevel) { /* Use backfill check method for after-allocation metadata */ assert(backfillChk(trailerMarker + SIZEOF(markerChar), (uStor->realLen - uStor->allocLen - hdrSize - SIZEOF(markerChar)))); } /* Remove element from allocated queue unless element is from a reentered malloc call. In that case, just * manipulate the counters. */ if (NULL != uStor->fPtr) { if (0 <= uStor->queueIndex) { DEQUEUE_STOR_ELEM(alloc, uStor); } else { /* Shenanigans so that counts are maintained properly in debug mode */ saveIndex = uStor->queueIndex; uStor->queueIndex = MAXINDEX + 1; DEQUEUE_STOR_ELEM(alloc, uStor); uStor->queueIndex = saveIndex; } } else DECR_CNTR(allocElemCnt[((0 <= uStor->queueIndex) ? uStor->queueIndex : MAXINDEX + 1)]); # endif totalUsed -= DEBUG_ONLY(uStor->allocLen) PRO_ONLY(uStor->realLen); if (sizeIndex >= 0) { /* We can put the storage back on one of our simple queues */ assert(0 == ((unsigned long)uStor & (TwoTable[sizeIndex] - 1))); /* Verify alignment */ assert(sizeIndex >= 0 && sizeIndex <= MAXINDEX); uStor->state = Free; DEBUG_ONLY(uStor->smTn = smTn); /* For freed blocks, set Tn when were freed */ INCR_CNTR(freeCnt[sizeIndex]); assert(uStor->realLen == TwoTable[sizeIndex]); totalAlloc -= TwoTable[sizeIndex]; /* First, if there are larger queues than this one, see if it has a buddy that it can * combine with. */ while (sizeIndex < MAXINDEX) { buddyElem = (storElem *)((unsigned long)uStor ^ TwoTable[sizeIndex]);/* Address of buddy */ assert(0 == ((unsigned long)buddyElem & (TwoTable[sizeIndex] - 1)));/* Verify alignment */ assert(buddyElem->state == Allocated || buddyElem->state == Free); assert(buddyElem->queueIndex >= 0 && buddyElem->queueIndex <= sizeIndex); if (buddyElem->state == Allocated || buddyElem->queueIndex != sizeIndex) /* All possible combines done */ break; /* Remove buddy from its queue and make a larger element for a larger queue */ DEQUEUE_STOR_ELEM(free, buddyElem); if (buddyElem < uStor) /* Pick lower address buddy for top of new bigger block */ uStor = buddyElem; ++sizeIndex; assert(sizeIndex >= 0 && sizeIndex <= MAXINDEX); INCR_CNTR(elemCombines[sizeIndex]); uStor->queueIndex = sizeIndex; } DEBUG_ONLY( /* Backfill entire block being freed so usage of it will cause problems */ if (GDL_SmBackfill & gtmDebugLevel) backfill((unsigned char *)uStor + hdrSize, TwoTable[sizeIndex] - hdrSize); ); ENQUEUE_STOR_ELEM(free, sizeIndex, uStor); if (MAXINDEX == sizeIndex) { /* Freeing/Coagulating a MAXTWO block. Decrement use counter for this element's block */ sEHdr = (storExtHdr *)((char *)uStor + uStor->extHdrOffset); --sEHdr->elemsAllocd; assert(0 <= sEHdr->elemsAllocd); /* Check for an extent being ripe for return to the system. Requirements are: * 1) All subblocks must be free (elemsAllocd == 0). * 2) There must be more than STOR_EXTENTS_KEEP extents already allocated. * If these conditions are met, we will dequeue each individual element from * it's queue and release the entire extent in a (real) free. */ if (STOR_EXTENTS_KEEP < curExtents && 0 == sEHdr->elemsAllocd) { /* Release this extent */ DEBUGSM(("debugsm: Extent being freed from 0x%08lx\n", sEHdr->elemStart)); DEBUG_ONLY(freedElemCnt = 0); for (uStor = sEHdr->elemStart; (char *)uStor < (char *)sEHdr; uStor = (storElem *)((char *)uStor + MAXTWO)) { DEBUG_ONLY(++freedElemCnt); assert(Free == uStor->state); assert(MAXINDEX == uStor->queueIndex); DEQUEUE_STOR_ELEM(free, uStor); DEBUGSM(("debugsm: ... element removed from free q 0x%08lx\n", uStor)); } assert(ELEMS_PER_EXTENT <= freedElemCnt); /* one loop to free them all */ assert((char *)uStor == (char *)sEHdr); dqdel(sEHdr, links); FREE(EXTENT_SIZE, sEHdr->extentStart); totalRmalloc -= EXTENT_SIZE; --curExtents; assert(curExtents); } } } else { assert(REAL_MALLOC == sizeIndex); /* Better be a real malloc type block */ INCR_CNTR(freeCnt[MAXINDEX + 1]); /* Count free of malloc */ allocSize = saveSize = uStor->realLen; DEBUG_ONLY( /* Backfill entire block being freed so usage of it will cause problems */ if (GDL_SmBackfill & gtmDebugLevel) backfill((unsigned char *)uStor, allocSize); ); FREE(allocSize, uStor); totalRmalloc -= allocSize; totalAlloc -= allocSize; } } DEBUG_ONLY( /* Make trace entry for this free */ ++smLastFreeIndex; if (MAXSMTRACE <= smLastFreeIndex) smLastFreeIndex = 0; smFrees[smLastFreeIndex].smAddr = addr; smFrees[smLastFreeIndex].smSize = saveSize; smFrees[smLastFreeIndex].smCaller = CALLERID; smFrees[smLastFreeIndex].smTn = smTn; ); --gtmMallocDepth; GMR_ONLY( /* Check on deferred frees */ if (0 == gtmMallocDepth && deferFreeExists) processDeferredFrees(); ); NON_GMR_ONLY(--fast_lock_count); # ifndef DEBUG } else { /* If not a debug module and debugging is enabled, reroute call to * the debugging version. */ smCallerId = (unsigned char *)caller_id(); gtm_free_dbg(addr); } # endif DEFERRED_EXIT_HANDLING_CHECK; } /* When an out-of-storage type error is encountered, besides releasing our memory reserve, we also * want to release as much unused storage within various GTM queues that we can find. */ void release_unused_storage(void) /* Note renamed to release_unused_storage_dbg when included in gtm_malloc_dbg.c */ { mcalloc_hdr *curhdr, *nxthdr; /* Release compiler storage if we aren't in the compiling business currently */ if (NULL != mcavailbase && mcavailptr == mcavailbase && mcavail == mcavailptr->size) { /* Buffers are unused and subject to release */ for (curhdr = mcavailbase; curhdr; curhdr = nxthdr) { nxthdr = curhdr->link; gtm_free(curhdr); } mcavail = 0; mcavailptr = mcavailbase = NULL; } /* If the cache_table_rebuild() routine is available in this executable, call it through its function pointer. */ if (NULL != cache_table_relobjs) (*cache_table_relobjs)(); /* Release object code in indirect cache */ } /* Raise ERR_MEMORY or ERR_VMSMEMORY. Separate routine since is called from hashtable logic in place of the * previous HTEXPFAIL error message. As such, it checks and properly deals with which flavor is running * (debug or non-debug). */ void raise_gtmmemory_error(void) /* Note renamed to raise_gtmmemory_error_dbg when included in gtm_malloc_dbg.c */ { void *addr; # ifndef DEBUG /* If we are not expanding for DEBUG, check now if DEBUG has been turned on. * If it has, we are in the wrong module Jack. This IF is structured so that * if this is the normal (optimized) case we will fall into the code and * handle the rerouting at the end. * * Note: The DEBUG expansion of this code in a pro build actually has a different * entry point name (raise_gtmmeory_error_dbg) and if malloc debugging options are * on in pro, we need to call that version, but since efficiency in pro trumps * clarity, we put the redirecting call at the bottom of the if-else block to * avoid disrupting the instruction pipeline. */ if (GDL_None == gtmDebugLevel) { # endif if (NULL != (addr = (void *)outOfMemoryMitigation) /* Note assignment */ UNIX_ONLY(&& !(ht_rhash_ch == active_ch->ch || jbxm_dump_ch == active_ch->ch || stpgc_ch == active_ch->ch))) { /* Free our reserve only if not in certain condition handlers (on UNIX) since it is * going to unwind this error and ignore it. On VMS the error will not be trapped. */ outOfMemoryMitigation = NULL; UNIX_ONLY(free(addr)); VMS_ONLY(lib$free_vm(addr)); DEBUG_ONLY(if (0 == outOfMemorySmTn) outOfMemorySmTn = smTn); /* Must decr gtmMallocDepth after release above but before the * call to release_unused_storage() below. */ --gtmMallocDepth; release_unused_storage(); } else --gtmMallocDepth; UNIX_ONLY(--fast_lock_count); DEFERRED_EXIT_HANDLING_CHECK; UNIX_ONLY(rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_MEMORY, 2, gtmMallocErrorSize, gtmMallocErrorCallerid, gtmMallocErrorErrno)); VMS_ONLY(rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_VMSMEMORY, 2, gtmMallocErrorSize, gtmMallocErrorCallerid)); # ifndef DEBUG } else /* If not a debug module and debugging is enabled, reroute call to the debugging version. */ raise_gtmmemory_error_dbg(); # endif } /* Return the maximum size that would fully utilize a storage block given the input size. If the size will not * fit in one of the buddy list queue elems, it is returned unchanged. Otherwise, the size of the buddy list queue * element minus the overhead will be returned as the best fit size. */ size_t gtm_bestfitsize(size_t size) { size_t tSize; int hdrSize, sizeIndex; # ifndef DEBUG /* If we are not expanding for DEBUG, check now if DEBUG has been turned on. * If it has, we are in the wrong module Jack. This IF is structured so that * if this is the normal (optimized) case we will fall into the code and * handle the rerouting at the end. * * Note: The DEBUG expansion of this code in a pro build actually has a different * entry point name (gtm_bestfitsize_dbg) and if malloc debugging options are * on in pro, we need to call that version, but since efficiency in pro trumps * clarity, we put the redirecting call at the bottom of the if-else block to * avoid disrupting the instruction pipeline. */ if (GDL_None == gtmDebugLevel) { # endif hdrSize = OFFSETOF(storElem, userStorage); /* Size of storElem header */ tSize = size + hdrSize DEBUG_ONLY(+ SIZEOF(markerChar)); if (MAXTWO >= tSize) { /* Allocation would fit in a buddy list queue */ sizeIndex = GetSizeIndex(tSize); tSize = TwoTable[sizeIndex]; return (tSize - hdrSize DEBUG_ONLY(- SIZEOF(markerChar))); } return size; # ifndef DEBUG } /* If not a debug module and debugging is enabled, reroute call to * the debugging version. */ return gtm_bestfitsize_dbg(size); # endif } /* Note that the DEBUG define takes on an additional meaning in this module. Not only are routines defined within * intended for DEBUG builds but they are also only generated ONCE rather than twice like most of the routines are * in this module. */ #ifdef DEBUG /* Backfill the requested area with marker text. We do this by doing single byte * stores up to the point where we can do aligned stores of the native register * length. Then fill the area as much as possible and finish up potentially with * a few single byte unaligned bytes at the end. */ void backfill(unsigned char *ptr, gtm_msize_t len) { unsigned char *c; ChunkType *chunkPtr; gtm_msize_t unalgnLen, chunkCnt; if (0 != len) { /* Process unaligned portion first */ unalgnLen = (gtm_msize_t)ptr & AddrMask; /* Past an alignment point */ if (unalgnLen) { unalgnLen = ChunkSize - unalgnLen; /* How far to go to get to alignment point */ unalgnLen = MIN(unalgnLen, len); /* Make sure not going too far */ c = backfillMarkC; len -= unalgnLen; do { *ptr++ = *c++; --unalgnLen; } while(unalgnLen); } /* Now, do aligned portion */ assert(0 == ((gtm_msize_t)ptr & AddrMask)); /* Verify aligned */ chunkCnt = len / ChunkSize; chunkPtr = (ChunkType *)ptr; while (chunkCnt--) { *chunkPtr++ = ChunkValue; len -= SIZEOF(ChunkType); } /* Do remaining unaligned portion if any */ if (len) { ptr = (unsigned char *)chunkPtr; c = backfillMarkC; do { *ptr++ = *c++; --len; } while(len); } } } /* ** still under ifdef DEBUG ** */ /* Check the given backfilled area that it was filled in exactly as * the above backfill routine would have filled it in. Again, do any * unaligned single chars first, then aligned native length areas, * then any stragler unaligned chars. */ boolean_t backfillChk(unsigned char *ptr, gtm_msize_t len) { unsigned char *c; ChunkType *chunkPtr; gtm_msize_t unalgnLen, chunkCnt; if (0 != len) { /* Process unaligned portion first */ unalgnLen = (gtm_msize_t)ptr & AddrMask; /* Past an alignment point */ if (unalgnLen) { unalgnLen = ChunkSize - unalgnLen; /* How far to go to get to alignment point */ unalgnLen = MIN(unalgnLen, len); /* Make sure not going too far */ c = backfillMarkC; len -= unalgnLen; do { if (*ptr++ == *c++) --unalgnLen; else return FALSE; } while(unalgnLen); } /* Now, do aligned portion */ assert(0 == ((gtm_msize_t)ptr & AddrMask)); /* Verify aligned */ chunkCnt = len / ChunkSize; chunkPtr = (ChunkType *)ptr; while (chunkCnt--) { if (*chunkPtr++ == ChunkValue) len -= SIZEOF(ChunkType); else return FALSE; } /* Do remaining unaligned portion if any */ if (len) { ptr = (unsigned char *)chunkPtr; c = backfillMarkC; do { if (*ptr++ == *c++) --len; else return FALSE; } while(len); } } return TRUE; } /* ** still under ifdef DEBUG ** */ /* Routine to run the free storage chains to verify that everything is in the correct place */ void verifyFreeStorage(void) { storElem *eHdr, *uStor; uint4 i; int hdrSize; hdrSize = OFFSETOF(storElem, userStorage); /* Looping for each free queue */ for (eHdr = &freeStorElemQs[0], i = 0; i <= MAXINDEX; ++i, ++eHdr) { for (uStor = STE_FP(eHdr); uStor->queueIndex != QUEUE_ANCHOR; uStor = STE_FP(uStor)) { assert(((MAXINDEX + 1) >= i)); /* Verify loop limits */ assert(((i == uStor->queueIndex) && (MAXINDEX <= MAXINDEX)) || (((MAXINDEX + 1) == i) && (REAL_MALLOC == uStor->queueIndex))); /* Verify queue index */ assert(0 == ((unsigned long)uStor & (TwoTable[i] - 1))); /* Verify alignment */ assert(Free == uStor->state); /* Verify state */ assert(0 == memcmp(uStor->headMarker, markerChar, SIZEOF(uStor->headMarker))); /* Vfy metadata marker */ assert(MAXINDEX != i || extent_used > uStor->extHdrOffset); if (GDL_SmChkFreeBackfill & gtmDebugLevel) /* Use backfill check method for verifying freed storage is untouched */ assert(backfillChk((unsigned char *)uStor + hdrSize, TwoTable[i] - hdrSize)); } } } /* ** still under ifdef DEBUG ** */ /* Routine to run the allocated chains to verify that the markers are all still in place */ void verifyAllocatedStorage(void) { storElem *eHdr, *uStor; unsigned char *trailerMarker; uint4 i; int hdrSize; hdrSize = OFFSETOF(storElem, userStorage); /* Looping for MAXINDEX+1 will check the real-malloc'd chains too */ for (eHdr = &allocStorElemQs[0], i = 0; i <= (MAXINDEX + 1); ++i, ++eHdr) { for (uStor = STE_FP(eHdr); uStor->queueIndex != QUEUE_ANCHOR; uStor = STE_FP(uStor)) { assert(((MAXINDEX + 1) >= i)); /* Verify loop not going nutz */ assert(((i == uStor->queueIndex) && (MAXINDEX <= MAXINDEX)) || (((MAXINDEX + 1) == i) && (REAL_MALLOC == uStor->queueIndex))); /* Verify queue index */ if (i != MAXINDEX + 1) /* If not verifying real mallocs,*/ assert(0 == ((unsigned long)uStor & (TwoTable[i] - 1))); /* .. verify alignment */ assert(Allocated == uStor->state); /* Verify state */ assert(0 == memcmp(uStor->headMarker, markerChar, SIZEOF(uStor->headMarker))); /* Vfy metadata markers */ trailerMarker = (unsigned char *)&uStor->userStorage.userStart+uStor->allocLen;/* Where trailer was put */ assert(0 == memcmp(trailerMarker, markerChar, SIZEOF(markerChar))); assert(MAXINDEX != i || extent_used > uStor->extHdrOffset); if (GDL_SmChkAllocBackfill & gtmDebugLevel) /* Use backfill check method for after-allocation metadata */ assert(backfillChk(trailerMarker + SIZEOF(markerChar), (uStor->realLen - uStor->allocLen - hdrSize - SIZEOF(markerChar)))); } } } /* ** still under ifdef DEBUG ** */ /* Routine to print the end-of-process info -- either allocation statistics or malloc trace dump. * Note that the use of FPRINTF here instead of util_out_print is historical. The output was at one * time going to stdout and util_out_print goes to stderr. If necessary or desired, these could easily * be changed to use util_out_print instead of FPRINTF. */ void printMallocInfo(void) { int i, j; if (GDL_SmStats & gtmDebugLevel) { FPRINTF(stderr, "\nMalloc small storage performance:\n"); FPRINTF(stderr, "Total mallocs: %d, total frees: %d, total extents: %d, total rmalloc bytes: %ld," " max rmalloc bytes: %ld\n", totalMallocs, totalFrees, totalExtents, totalRmalloc, rmallocMax); FPRINTF(stderr, "Total (currently) allocated (includes overhead): %ld, Total (currently) used (no overhead): %ld\n", totalAlloc, totalUsed); FPRINTF(stderr, "Maximum extents: %d, Current extents: %d, Released extents: %d\n", maxExtents, curExtents, (totalExtents - curExtents)); GMR_ONLY( FPRINTF(stderr, "Total reentrant mallocs: %d, total deferred frees: %d\n", reentMallocs, deferFreePending); ) FPRINTF(stderr, "\nQueueSize Mallocs Frees Splits Combines CurCnt MaxCnt CurCnt MaxCnt\n"); FPRINTF(stderr, " Free Free Alloc Alloc\n"); FPRINTF(stderr, "-----------------------------------------------------------------------------------------\n"); { for (i = 0; i <= MAXINDEX + 1; ++i) { FPRINTF(stderr, "%9d %9d %9d %9d %9d %9d %9d %9d %9d\n", TwoTable[i], mallocCnt[i], freeCnt[i], elemSplits[i], elemCombines[i], freeElemCnt[i], freeElemMax[i], allocElemCnt[i], allocElemMax[i]); } } } if (GDL_SmDumpTrace & gtmDebugLevel) { FPRINTF(stderr, "\nMalloc Storage Traceback: gtm_malloc() addr: 0x"gmaAdr"\n", >m_malloc); FPRINTF(stderr, "TransNumber "gmaFill" AllocAddr Size "gmaFill" CallerAddr\n"); FPRINTF(stderr, "------------------------------------------------"gmaLine gmaLine"\n"); for (i = 0,j = smLastMallocIndex; i < MAXSMTRACE; ++i,--j)/* Loop through entire table, start with last elem used */ { if (0 > j) /* Wrap as necessary */ j = MAXSMTRACE - 1; if (0 != smMallocs[j].smTn) FPRINTF(stderr, "%9d 0x"gmaAdr" %10d 0x"gmaAdr"\n", smMallocs[j].smTn, smMallocs[j].smAddr, smMallocs[j].smSize, smMallocs[j].smCaller); } FPRINTF(stderr, "\n\nFree Storage Traceback:\n"); FPRINTF(stderr, "TransNumber "gmaFill" FreeAddr Size "gmaFill" CallerAddr\n"); FPRINTF(stderr, "------------------------------------------------"gmaLine gmaLine"\n"); for (i = 0, j = smLastFreeIndex; i < MAXSMTRACE; ++i, --j)/* Loop through entire table, start with last elem used */ { if (0 > j) /* Wrap as necessary */ j = MAXSMTRACE - 1; if (0 != smFrees[j].smTn) FPRINTF(stderr, "%9d 0x"gmaAdr" %10d 0x"gmaAdr"\n", smFrees[j].smTn, smFrees[j].smAddr, smFrees[j].smSize, smFrees[j].smCaller); } FPRINTF(stderr, "\n"); FFLUSH(stderr); } printMallocDump(); } /* ** still under ifdef DEBUG ** */ /* Routine to print storage dump. This is called as part of print_malloc_info but is also potentially separately called from * op_view so is a separate routine. */ void printMallocDump(void) { storElem *eHdr, *uStor; int i; if (GDL_SmDump & gtmDebugLevel) { FPRINTF(stderr, "\nMalloc Storage Dump: gtm_malloc() addr: 0x"gmaAdr"\n", >m_malloc); FPRINTF(stderr, gmaFill"Malloc Addr "gmaFill" Alloc From Malloc Size Trans Number\n"); FPRINTF(stderr, " ----------------------------------------------------------"gmaLine gmaLine"\n"); /* Looping for each allocated queue */ for (eHdr = &allocStorElemQs[0], i = 0; i <= (MAXINDEX + 1); ++i, ++eHdr) { for (uStor = STE_FP(eHdr); uStor->queueIndex != QUEUE_ANCHOR; uStor = STE_FP(uStor)) { FPRINTF(stderr, " 0x"gmaAdr" 0x"gmaAdr" %10d %10d\n", &uStor->userStorage.userStart, uStor->allocatedBy, uStor->allocLen, uStor->smTn); } } FFLUSH(stderr); } } #endif fis-gtm-V6.0-003/sr_port/gtm_maxstr.c0000644000032200000250000000626612201176156016376 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2003 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "error.h" #include "gtm_maxstr.h" /* GT.M string buffer stack where each entry is allocated geometrically on the need basis */ GBLDEF mstr maxstr_buff[MAXSTR_STACK_SIZE]; GBLDEF int maxstr_stack_level = -1; /* This handler is to release the heap storage allocated within a function in case of errors. * The suggested protocol is that after a function is done with using the string buffer, the macro * MAXSTR_BUFF_FINI used in the function epilog releases the malloc'd storage. But if an error * occurs within the function body, the function epilog is not executed so this condition handler * should do the same so that the storage is not kept dangling. */ CONDITION_HANDLER(gtm_maxstr_ch) { START_CH; if (maxstr_buff[maxstr_stack_level].addr) { free(maxstr_buff[maxstr_stack_level].addr); maxstr_buff[maxstr_stack_level].addr = NULL; } maxstr_buff[maxstr_stack_level].len = 0; maxstr_stack_level--; NEXTCH; } /* The routine checks if the currently available buffer (either 32K automatic or >32K malloc'd) * is sufficient for the new space requirement. If not sufficient, it keeps doubling the buffer size * and checks until a new buffer size is large enough to accommodate the incoming string. It then * allocates the new buffer and releases the previously malloc'd buffer. * Note that if strings fit within 32K, the automating buffer is used and no heap storage is used. * Parameters: * * space_needed - buffer space needed to accommodate the string that is about to be written * buff - address of the pointer to the beginning of the buffer. If reallocation occurs, buff will be * modified to point to the reallocated buffer. * space_occupied - how full is the buffer? * * Returns the new allocated buffer size. */ int gtm_maxstr_alloc(int space_needed, char** buff, int space_occupied) { int new_buff_size; if (space_needed > (maxstr_buff[maxstr_stack_level].len - space_occupied)) { /* Existing buffer is not sufficient. reallocate the buffer with the double the size */ new_buff_size = maxstr_buff[maxstr_stack_level].len; while (space_needed > new_buff_size - space_occupied) new_buff_size += new_buff_size; if (NULL != maxstr_buff[maxstr_stack_level].addr) { assert(maxstr_buff[maxstr_stack_level].addr == *buff); maxstr_buff[maxstr_stack_level].addr = (char *)malloc(new_buff_size); memcpy(maxstr_buff[maxstr_stack_level].addr, *buff, space_occupied); free(*buff); } else { maxstr_buff[maxstr_stack_level].addr = (char *)malloc(new_buff_size); memcpy(maxstr_buff[maxstr_stack_level].addr, *buff, space_occupied); } *buff = maxstr_buff[maxstr_stack_level].addr; maxstr_buff[maxstr_stack_level].len = new_buff_size; } return maxstr_buff[maxstr_stack_level].len; } fis-gtm-V6.0-003/sr_port/gtm_maxstr.h0000644000032200000250000001051012201176156016366 0ustar librarygtc/**************************************************************** * * * Copyright 2003 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_MAXSTR_INCLUDED #define GTM_MAXSTR_INCLUDED /* The following macros should be used whenever an automatic string buffer * of size MAX_STRLEN needs to be declared in a function. Given that MAX_STRLEN * is enhanced to 1MB, allocating 1MB of local buffer on stack is not viable and * may lead to C stack overflows. The following macros employ an adaptive * scheme where an inital buffer of size 32K is allocated on stack and whenever * the buffer is found to be insufficient, the algorithm reallocates the buffer in * malloc'd space by doubling the previous size. * * If the string fits within 32K, there is [almost] no additional penalty since * the buffer is on stack as before. * * For any future requirement of MAX_STRLEN automatic buffers, the following macros * should be used. An example below: * * func() * { * char buffer[MAX_STRLEN]; * mstr src, dst; * * ... * dst.addr = &buffer[0]; * memcpy(dst.addr, src.addr, len) * ... * * return * } * * should be replaced something like * * #include "gtm_maxstr.h" * func() * { * MAXSTR_BUFF_DECL(buffer); * mstr src, dst; * * MAXSTR_BUFF_INIT; * ... * ... * dst.addr = &buffer[0]; * MAXSTR_BUFF_ALLOC(src.len, &dst.addr, 0); * ... * ... * MAXSTR_BUFF_FINI; * return; * } * */ /* The maximum nested depth of MAXSTR_BUFF_INIT/MAXSTR_BUFF_FINI allowed. We do not expect * many nesting levels. When the buffer stack overflows, GT.M asserts. */ #define MAXSTR_STACK_SIZE 10 GBLREF mstr maxstr_buff[]; /* Buffer stack for nested MAXSTR_BUFF_INIT/MAXSTR_BUFF_FINI */ /* Each entry in the buffer stack where each entry points to the buffer and it's size. Note that * although mstr is chosen as the entry type, it does not represent a GT.M string in the * traditional sense. The addr field point to the malloc'd buffer and is NULL if no * reallocation occured, i.e. buffer lies on the stack. The len field stores the current * buffer size which can grow geometrically. */ GBLREF int maxstr_stack_level; /* Current (0-index based) depth of nested MAXSTR_BUFF_INIT/MAXSTR_BUFF_FINI */ #define MAXSTR_BUFF_DECL(var) char var[MAX_STRBUFF_INIT]; #define MAXSTR_BUFF_INIT \ { \ ESTABLISH(gtm_maxstr_ch); \ maxstr_stack_level++; \ assert(maxstr_stack_level < MAXSTR_STACK_SIZE); \ maxstr_buff[maxstr_stack_level].len = MAX_STRBUFF_INIT; \ maxstr_buff[maxstr_stack_level].addr = NULL; \ } #define MAXSTR_BUFF_INIT_RET \ { \ ESTABLISH_RET(gtm_maxstr_ch, -1); \ maxstr_stack_level++; \ assert(maxstr_stack_level < MAXSTR_STACK_SIZE); \ maxstr_buff[maxstr_stack_level].len = MAX_STRBUFF_INIT; \ maxstr_buff[maxstr_stack_level].addr = NULL; \ } /* The following macro checks whether the existing available buffer is sufficient * and if not, it reallocates the buffer to the sufficient size. * space_needed - buffer space needed to accommodate the string that is about to be written. * buff - pointer to the beginning of the buffer. If reallocation occurs, buff will be * modified to point to the reallocated buffer. * space_occupied - how full is the buffer? * returns - size of the allocated buffer (whether reallocated or not). */ #define MAXSTR_BUFF_ALLOC(space_needed, buff, space_occupied) \ gtm_maxstr_alloc((space_needed), &(buff), (space_occupied)) #define MAXSTR_BUFF_FINI \ { \ if (maxstr_buff[maxstr_stack_level].addr) \ { \ free(maxstr_buff[maxstr_stack_level].addr); \ maxstr_buff[maxstr_stack_level].addr = NULL; \ } \ maxstr_buff[maxstr_stack_level].len = 0; \ maxstr_stack_level--; \ REVERT; /* gtm_maxstr_ch() */ \ } int gtm_maxstr_alloc(int space_needed, char** buff, int space_occupied); #endif /* GTM_MAXSTR_INCLUDED */ fis-gtm-V6.0-003/sr_port/gtm_memcmp.c0000644000032200000250000000165712201176156016335 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_memcmp - GT.M interlude to C library memcmp function. * * gtm_memcmp is an interlude to the supplied C library memcmp that * prevents memory addressing errors that can occur when the length * of the items to be compared is zero and the supplied function * does not first validate its input parameters. */ #include "mdef.h" #include "gtm_string.h" #undef memcmp int gtm_memcmp (const void *a, const void *b, size_t len) { return (int)(len == 0 ? len : memcmp(a, b, len)); } fis-gtm-V6.0-003/sr_port/gtm_memcpy_validate_and_execute.c0000644000032200000250000000330012201176156022551 0ustar librarygtc/**************************************************************** * * * Copyright 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #define BYPASS_MEMCPY_OVERRIDE /* Want to run original system memcpy() here */ #include "gtm_string.h" #include "gtm_memcpy_validate_and_execute.h" #ifdef DEBUG /* Is only a debugging routine - nothing to see here for a production build - move along */ /* Identify memcpy() invocations that should be memmove() instead. If this routine assert fails, the arguments * overlap so should be converted to memmove(). One exception to that rule which is currently bypassed is when * source and target are equal. There are no known implementation of memcpy() that would break in such a * condition so since at least two of these currently exist in GT.M (one in gtmcrypt.h on UNIX and one in * mu_cre_file on VMS), this routine does not cause an assert fail in that case. */ void *gtm_memcpy_validate_and_execute(void *target, const void *src, size_t len) { assert((0 <= (signed)len) && (len <= MAXPOSINT4)); /* nothing beyond max positive int4 allowed */ if (target == src) /* Allow special case to go through but avoid actual memcpy() call */ return target; assert(((char *)(target) > (char *)(src)) ? ((char *)(target) >= ((char *)(src) + (len))) : ((char *)(src) >= ((char *)(target) + (len)))); return memcpy(target, src, len); } #endif fis-gtm-V6.0-003/sr_port/gtm_memcpy_validate_and_execute.h0000644000032200000250000000111612201176156022561 0ustar librarygtc/**************************************************************** * * * Copyright 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_MVAE_INCLUDED #define GTM_MVAE_INCLUDED void *gtm_memcpy_validate_and_execute(void *target, const void *src, size_t len); #endif fis-gtm-V6.0-003/sr_port/gtm_netdb.h0000644000032200000250000000306612201176156016154 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_netdb.h - interlude to system header file. */ #ifndef GTM_NETDBH #define GTM_NETDBH #include #define MAX_GETHOST_TRIES 8 /* Macro to issue an rts_error_csa() with the results of getaddrinfo() or getnameinfo(). * Takes ERR_GETADDRINFO or ERR_GETNAMEINFO as the mnemonic. */ #define RTS_ERROR_ADDRINFO(CSA, MNEMONIC, ERRCODE) \ { \ if (EAI_SYSTEM == ERRCODE) \ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(4) MNEMONIC, 0, errno, 0); \ else \ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(6) MNEMONIC, 0, \ ERR_TEXT, 2, RTS_ERROR_STRING(gai_strerror(ERRCODE))); \ } /* Same as above, but with a literal string context description. */ #define RTS_ERROR_ADDRINFO_CTX(CSA, MNEMONIC, ERRCODE, CONTEXT) \ { \ if (EAI_SYSTEM == ERRCODE) \ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(8) MNEMONIC, 0, \ ERR_TEXT, 2, RTS_ERROR_LITERAL(CONTEXT), errno, 0); \ else \ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(10) MNEMONIC, 0, \ ERR_TEXT, 2, RTS_ERROR_LITERAL(CONTEXT), \ ERR_TEXT, 2, RTS_ERROR_STRING(gai_strerror(ERRCODE))); \ } #endif fis-gtm-V6.0-003/sr_port/gtm_newintrinsic.c0000644000032200000250000001352112201176176017566 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "mv_stent.h" #include "stack_frame.h" #include "tp_frame.h" #include "gtm_string.h" #include "gtm_newintrinsic.h" #include "op.h" GBLREF mv_stent *mv_chain; GBLREF unsigned char *stackbase, *stacktop, *msp, *stackwarn; GBLREF stack_frame *frame_pointer; GBLREF tp_frame *tp_pointer; GBLREF symval *curr_symval; GBLREF uint4 dollar_tlevel; #ifdef GTM_TRIGGER GBLREF mval dollar_ztwormhole; #endif /* Note this module follows the basic pattern of op_newvar which handles the same function except for local vars instead of intrinsic vars. */ void gtm_newintrinsic(mval *intrinsic) { mv_stent *mv_st_ent, *mvst_tmp, *mvst_prev; stack_frame *fp, *fp_prev, *fp_fix; tp_frame *tpp; unsigned char *old_sp, *top; int indx; int4 shift_size; error_def(ERR_STACKOFLOW); error_def(ERR_STACKCRIT); assert(intrinsic); if (frame_pointer->type & SFT_COUNT) { /* Current (youngest) frame is NOT an indirect frame. Create restore entry for intrinsic var. */ PUSH_MV_STENT(MVST_MSAV); mv_chain->mv_st_cont.mvs_msav.v = *intrinsic; mv_chain->mv_st_cont.mvs_msav.addr = intrinsic; } else { /* Current (youngest) frame IS an indirect frame. The situation is more complex because this is not a true stackframe. It has full access to the base "counted" frame's vars and any new done here must behave as if it were done in the base/counted frame. To accomplish this, we actually find the base frame we are executing in, then shift all frames younger than that up by the size of the mvstent entry we need to save/restore the value being new'd and then go into each frame modified and fixup all the addresses. */ fp = frame_pointer; fp_prev = fp->old_frame_pointer; assert(fp_prev); /* Find relevant base (counted) frame */ while (!(fp_prev->type & SFT_COUNT)) { fp = fp_prev; fp_prev = fp->old_frame_pointer; assert(fp_prev); } /* top is beginning of earliest indirect stackframe before counted base frame. It is the point where we will shift to make room to insert an mv_stent into the base frame. */ top = (unsigned char *)(fp + 1); old_sp = msp; shift_size = mvs_size[MVST_MSAV]; msp -= shift_size; if (msp <= stackwarn) { if (msp <= stacktop) { msp = old_sp; rts_error(VARLSTCNT(1) ERR_STACKOFLOW); } else rts_error(VARLSTCNT(1) ERR_STACKCRIT); } /* Ready, set, shift the younger indirect frames to make room for mv_stent */ memmove(msp, old_sp, top - (unsigned char *)old_sp); mv_st_ent = (mv_stent *)(top - shift_size); mv_st_ent->mv_st_type = MVST_MSAV; ADJUST_FRAME_POINTER(frame_pointer, shift_size); /* adjust all the pointers in all the stackframes that were moved */ for (fp_fix = frame_pointer; fp_fix != fp_prev; fp_fix = fp_fix->old_frame_pointer) { if ((unsigned char *)fp_fix->l_symtab < top && (unsigned char *)fp_fix->l_symtab > stacktop) fp_fix->l_symtab = (ht_ent_mname **)((char *)fp_fix->l_symtab - shift_size); if (fp_fix->temps_ptr < top && fp_fix->temps_ptr > stacktop) fp_fix->temps_ptr -= shift_size; if (fp_fix->vartab_ptr < (char *)top && fp_fix->vartab_ptr > (char *)stacktop) fp_fix->vartab_ptr -= shift_size; if ((unsigned char *)fp_fix->old_frame_pointer < top && (char *)fp_fix->old_frame_pointer > (char *)stacktop) { ADJUST_FRAME_POINTER(fp_fix->old_frame_pointer, shift_size); } } /* Adjust stackframe and mvstent pointers in relevant tp_frame blocks */ assert(((NULL == tp_pointer) && !dollar_tlevel) || ((NULL != tp_pointer) && dollar_tlevel)); for (tpp = tp_pointer; (tpp && ((unsigned char *)tpp->fp < top)); tpp = tpp->old_tp_frame) { if ((unsigned char *)tpp->fp > stacktop) tpp->fp = (struct stack_frame_struct *)((char *)tpp->fp - shift_size); /* Note low check for < top may be superfluous here but without a test case to verify, I feel better leaving it in. SE 8/2001 */ if ((unsigned char *)tpp->mvc < top && (unsigned char *)tpp->mvc > stacktop) tpp->mvc = (struct mv_stent_struct *)((char *)tpp->mvc - shift_size); } /* Put new mvstent entry on (into) the mvstent chain */ if ((unsigned char *)mv_chain >= top) { /* Just put new entry on end of chain which preceeds our base frame */ mv_st_ent->mv_st_next = (unsigned int)((char *)mv_chain - (char *)mv_st_ent); mv_chain = mv_st_ent; } else { /* One of the indirect frames has mv_stents associated with it so we have to find the appropriate insertion point for this frame. */ fp = (stack_frame *)((char *)fp - shift_size); mv_chain = (mv_stent *)((char *)mv_chain - shift_size); mvst_tmp = mv_chain; mvst_prev = (mv_stent *)((char *)mvst_tmp + mvst_tmp->mv_st_next); while (mvst_prev < (mv_stent *)fp) { mvst_tmp = mvst_prev; mvst_prev = (mv_stent *)((char *)mvst_tmp + mvst_tmp->mv_st_next); } mvst_tmp->mv_st_next = (unsigned int)((char *)mv_st_ent - (char *)mvst_tmp); mv_st_ent->mv_st_next = (unsigned int)((char *)mvst_prev - (char *)mv_st_ent + shift_size); } /* Save current values of intrinsic var in the inserted mv_stent */ mv_st_ent->mv_st_cont.mvs_msav.v = *intrinsic; mv_st_ent->mv_st_cont.mvs_msav.addr = intrinsic; } /* New the intrinsic var's current value if not $ZTWORMHOLE */ # ifdef GTM_TRIGGER if (&dollar_ztwormhole != intrinsic) { # endif intrinsic->mvtype = MV_STR; intrinsic->str.len = 0; # ifdef GTM_TRIGGER } # endif return; } fis-gtm-V6.0-003/sr_port/gtm_newintrinsic.h0000644000032200000250000000074612201176156017576 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ void gtm_newintrinsic(mval *intrinsic); fis-gtm-V6.0-003/sr_port/gtm_putmsg_list.h0000644000032200000250000000107712201176156017432 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_PUTMSG_LIST_H #define GTM_PUTMSG_LIST_H void gtm_putmsg_list(void *csa, int arg_count, va_list var); #endif fis-gtm-V6.0-003/sr_port/gtm_pwd.h0000644000032200000250000000154412201176156015651 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2008 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_pwd.h - interlude to system header file. */ #ifndef GTM_PWDH #define GTM_PWDH #include #define GETPWUID(uid,getpwuid_res) (getpwuid_res = getpwuid(uid)) /* #define to be gtm_getpwuid to serve as a wrapper for blocking signals since getpwuid is not signal-safe. */ #define getpwuid gtm_getpwuid struct passwd *gtm_getpwuid(uid_t uid); /* Define prototype of "gtm_getpwuid" here */ #endif fis-gtm-V6.0-003/sr_port/gtm_relqueopi.c0000644000032200000250000000564412201176156017064 0ustar librarygtc/**************************************************************** * * * Copyright 2008 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_relqueopi - C-callable relative queue interlocked routines * * These routines perform interlocked operations on doubly-linked * relative queues. They are designed to emulate the VAX machine * instructions (and corresponding VAX C library routines) after * which they are named. * * insqhi - insert entry into queue at head, interlocked * insqti - insert entry into queue at tail, interlocked * remqhi - remove entry from queue at head, interlocked * remqti - remove entry from queue at tail, interlocked */ #include "mdef.h" #include "relqueopi.h" #ifdef DEBUG /* An element that is not present in the queue should have its fl,bl fields zero. * An element that is present in the queue should have its fl,bl fields non-zero. * Ensure/Check this property for all queue operations. * This will help catch a case when an element that is already present in the queue is re-added into the same queue. * Such operations will cause queue corruption and since the queue is in shared memory (given that the interlocked * queue operations are being done), could cause shared memory corruption and database damage (D9H03-002644). */ int gtm_insqhi(que_ent_ptr_t new, que_head_ptr_t base) { int4 status; assert(0 == new->fl); assert(0 == new->bl); status = SYS_INSQHI(new, base); /* We cannot assert that new->fl and new->bl are non-zero at this point since they * could be concurrently removed from the queue right after we inserted it above. */ return status; } int gtm_insqti(que_ent_ptr_t new, que_head_ptr_t base) { int4 status; assert(0 == new->fl); assert(0 == new->bl); status = SYS_INSQTI(new, base); /* We cannot assert that new->fl and new->bl are non-zero at this point since they * could be concurrently removed from the queue right after we inserted it above. */ return status; } void_ptr_t gtm_remqhi(que_head_ptr_t base) { que_ent_ptr_t ret; ret = SYS_REMQHI(base); if (NULL != ret) { # ifndef UNIX /* in Unix, relqueopi.c already does the rest of fl,bl to 0 just before releasing the swap lock */ ret->fl = 0; ret->bl = 0; # endif assert(0 == ret->fl); assert(0 == ret->bl); } return (void_ptr_t)ret; } void_ptr_t gtm_remqti(que_head_ptr_t base) { que_ent_ptr_t ret; ret = SYS_REMQTI(base); if (NULL != ret) { # ifndef UNIX /* in Unix, relqueopi.c already does the rest of fl,bl to 0 just before releasing the swap lock */ ret->fl = 0; ret->bl = 0; # endif assert(0 == ret->fl); assert(0 == ret->bl); } return (void_ptr_t)ret; } #endif fis-gtm-V6.0-003/sr_port/gtm_rename.h0000644000032200000250000000243412201176156016325 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GTM_RENAME_ #define __GTM_RENAME_ /* gtm_rename.h */ #define RENAME_SUCCESS 0 #define RENAME_NOT_REQD 1 #define RENAME_FAILED 2 #ifdef UNIX # define JNLSWITCH_TM_FMT "_%Y%j%H%M%S" /* yearjuliandayhoursminutesseconds */ #else # define JNLSWITCH_TM_FMT "|!Y4|!H04!M0!S0|" /* 'julian' day is added by append_time_stamp() explicitly */ #endif int rename_file_if_exists(char *org_fn, int org_fn_len, char *rename_fn, int *rename_fn_len, uint4 *ustatus); uint4 gtm_rename(char *org_fn, int org_fn_len, char *rename_fn, int rename_len, uint4 *ustatus); uint4 prepare_unique_name(char *org_fn, int org_fn_len, char *prefix, char *suffix, char *rename_fn, int *rename_fn_len, jnl_tm_t now, uint4 *ustatus); uint4 append_time_stamp(char *fn, int *fn_len, jnl_tm_t now); void cre_jnl_file_intrpt_rename(int fn_len, sm_uc_ptr_t fn); #endif fis-gtm-V6.0-003/sr_port/gtm_savetraps.c0000644000032200000250000000154612201176156017064 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_savetraps.h" #include "gtm_newintrinsic.h" GBLREF mval dollar_ztrap; GBLREF mval dollar_etrap; /* Routine called when we need to save the current Xtrap (etrap or ztrap) but don't know which to save. */ void gtm_savetraps(void) { mval *intrinsic; if (dollar_ztrap.str.len) intrinsic = &dollar_ztrap; else intrinsic = &dollar_etrap; gtm_newintrinsic(intrinsic); return; } fis-gtm-V6.0-003/sr_port/gtm_savetraps.h0000644000032200000250000000102112201176156017055 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_SAVETRAPS_H #define GTM_SAVETRAPS_H void gtm_savetraps(void); #endif fis-gtm-V6.0-003/sr_port/gtm_sizeof.h0000644000032200000250000000471112201176156016355 0ustar librarygtc/**************************************************************** * * * Copyright 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_SIZEOF_H_INCLUDED #define GTM_SIZEOF_H_INCLUDED /* Note: sizeof returns a "UNSIGNED long" type by default. When one of the operand in a relational operation * (<, <= etc.) is a SIGNED type and the other is UNSIGNED, both operands are typecast to UNSIGNED (NOT SIGNED) * before performing the comparison. This has unexpected consequences. For example, if a variable XYZ is signed * and has a negative value of -1, one would expect an "if (X < sizeof(char))" to return TRUE (because X is * negative and sizeof of anything is positive) but it actually returns FALSE. We have gotten bit by this at least * twice (C9E09-002635 and C9J10-003208). Therefore we define a SIZEOF macro that returns a "SIGNED long" type and * use it throughout the code base. This way "if (X < SIZEOF(char))" will evaluate correctly irrespective of * whether X is signed or unsigned (if X is signed, since SIZEOF is also signed, a signed comparison occurs; * if X is unsigned, since SIZEOF is signed, C's typecasting rules cause a unsigned comparison to occur). * * In a platform where long is 64-bits and SIZEOF is used in comparisons involving 32-bit variables, a compiler * warning is issued for every 64->32 bit auto cast (zOS compiler for now). To avoid this warning, we define the * SIZEOF macro to return a "SIGNED int" type on zOS. This will take care of the most common sizeof usages. * Whenever SIZEOF needs to be used in expressions involving 64-bit pointer quantities, use ((INTPTR_T)SIZEOF(...)). * Whenever SIZEOF needs to be used in expressions involving 64-bit integer quantities, use ((long)SIZEOF(...)). * * Some modules (like getcaps.c, gtm_tparm.c etc) do not include mdef.h for reasons stated in the corresponding * files but yet use sizeof. To enable those modules to use the safer SIZEOF macro as well, we create a separate * header file gtm_sizeof.h that is included explicitly by them as well as by mdef.h. */ #if defined(__MVS__) # define SIZEOF(X) ((int)(sizeof(X))) #else # define SIZEOF(X) ((long)sizeof(X)) #endif #endif fis-gtm-V6.0-003/sr_port/gtm_socket.h0000644000032200000250000000532512201176156016350 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_socket.h - interlude to system header file. */ #ifndef GTM_SOCKETH #define GTM_SOCKETH #ifdef VMS #include #else #include #endif #define BIND bind #define CONNECT connect #define ACCEPT accept #define RECVFROM recvfrom #define SENDTO sendto typedef struct sockaddr *sockaddr_ptr; #if defined(__osf__) && defined(__alpha) #define GTM_SOCKLEN_TYPE size_t #elif defined(VMS) #define GTM_SOCKLEN_TYPE size_t #else #define GTM_SOCKLEN_TYPE socklen_t #endif #ifdef GTM_FD_TRACE /* Just like open and close were noted down in gtm_fcntl.h, note down all macros which we are redefining here and could * potentially have been conflictingly defined by the system header file "socket.h". The system define will be used * in gtm_fd_trace.c within the implementation of the GT.M interlude function. Currently none of these functions (socket) * are defined by the system so it is not theoretically necessary but they could be defined in the future. */ # undef socket /* in case this is already defined by */ # define socket gtm_socket #endif int gtm_socket(int domain, int type, int protocol); int gtm_connect(int socket, struct sockaddr *address, size_t address_len); #if defined(VMS) && !defined(_SS_PAD2SIZE) /* No sockaddr_storage on OpenVMS 7.2-1, but we only support AF_INET on VMS, so use sockaddr_in. */ #define sockaddr_storage sockaddr_in /* getnameinfo() inexplicably throws an ACCVIO/NOPRIV on OpenVMS 7.2-1, so revert to the old API. */ #define GETNAMEINFO(SA, SALEN, HOST, HOSTLEN, SERV, SERVLEN, FLAGS, RES) \ { \ assert(((struct sockaddr *)(SA))->sa_family == AF_INET); \ assert((FLAGS & NI_NUMERICHOST) || (NULL == HOST)); \ assert((FLAGS & NI_NUMERICSERV) || (NULL == SERV)); \ assert(FLAGS & (NI_NUMERICHOST | NI_NUMERICSERV)); \ if ((FLAGS & NI_NUMERICHOST) && (NULL != HOST)) \ STRNCPY(HOST, inet_ntoa(((struct sockaddr_in *)(SA))->sin_addr), HOSTLEN); \ if ((FLAGS & NI_NUMERICSERV) && (NULL != SERV)) \ i2asc((uchar_ptr_t)(SERV), ntohs(((struct sockaddr_in *)(SA))->sin_port)); \ RES = 0; \ } #else #define GETNAMEINFO(SA, SALEN, HOST, HOSTLEN, SERV, SERVLEN, FLAGS, RES) \ { \ RES = getnameinfo(SA, SALEN, HOST, HOSTLEN, SERV, SERVLEN, FLAGS); \ } #endif #endif fis-gtm-V6.0-003/sr_port/gtm_stat.h0000644000032200000250000000131312201176156016024 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_stat.h - interlude to system header file. */ #ifndef GTM_STATH #define GTM_STATH #include #define CHMOD chmod #define FCHMOD fchmod #define MKDIR mkdir #define Stat stat #define MKNOD mknod #define LSTAT lstat #endif fis-gtm-V6.0-003/sr_port/gtm_stdlib.h0000644000032200000250000000240312201176156016333 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_stdlib.h - interlude to system header file. */ #ifndef GTM_STDLIBH #define GTM_STDLIBH #include #ifndef __CYGWIN__ #define GETENV getenv #else char *gtm_getenv(char *varname); #define GETENV gtm_getenv #endif #define ATOI atoi #define ATOL atol #define ATOF atof #define PUTENV putenv #define STRTOL strtol #define STRTOLL strtoll #define STRTOUL strtoul #if INT_MAX < LONG_MAX /* like Tru64 */ #define STRTO64L strtol #define STRTOU64L strtoul #elif defined(__hpux) #include #define STRTO64L strtoimax #define STRTOU64L strtoumax #else #define STRTO64L strtoll #define STRTOU64L strtoull #endif #define MKSTEMP(template,mkstemp_res) (mkstemp_res = mkstemp(template)) #ifdef VMS #define SYSTEM system #else #define SYSTEM gtm_system int gtm_system(const char *cmdline); #endif #endif fis-gtm-V6.0-003/sr_port/gtm_string.h0000644000032200000250000000514612201176156016367 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* If this is not the vax, define string.h. This is because the Vax has its own built-in instructions for string manipulation. */ #ifndef GTM_STRINGH #define GTM_STRINGH #include #define STRERROR strerror #define STRCPY(DEST, SOURCE) strcpy((char *)(DEST), (char *)(SOURCE)) #define STRNCPY_LIT(DEST, LITERAL) strncpy((char *)(DEST), (char *)(LITERAL), SIZEOF(LITERAL) - 1) /* BYPASSOK */ #define STRNCPY_STR(DEST, STRING, LEN) strncpy((char *)(DEST), (char *)(STRING), LEN) #define STRCMP(SOURCE, DEST) strcmp((char *)(SOURCE), (char *)(DEST)) #define STRNCMP_LIT(SOURCE, LITERAL) strncmp(SOURCE, LITERAL, SIZEOF(LITERAL) - 1) /* BYPASSOK */ /* Make sure that SIZEOF(SOURCE) > 0 or SOURCE != NULL before running. */ #define STRNCMP_LIT_FULL(SOURCE, LITERAL) strncmp(SOURCE, LITERAL, SIZEOF(LITERAL)) /* BYPASSOK */ #define STRNCMP_STR(SOURCE, STRING, LEN) strncmp(SOURCE, STRING, LEN) /* We need to catch any memcpy() that is used when the source and target strings overlap in any fashion so we can change * them to a memmove. So in debug builds, assert fail if this is the case. */ #if defined(DEBUG) && !defined(BYPASS_MEMCPY_OVERRIDE) # include "gtm_memcpy_validate_and_execute.h" # ifdef memcpy # undef memcpy /* Some platforms like AIX create memcpy as a #define which needs removing before re-define */ # endif # define memcpy(TARGET, SRC, LEN) gtm_memcpy_validate_and_execute((void *)(TARGET), (const void *)(SRC), (LEN)) #endif /* The strnlen() function is POSIX-2008 so not widely avaiable yet so use it or our own critter as appropriate */ #if (defined(__linux__) || defined(AIX)) # define STRNLEN(str, maxlen, rslt) rslt = strnlen(str, maxlen) #else # define STRNLEN(str, maxlen, rslt) \ { \ unsigned char *c, *cend; \ \ for (c = (unsigned char *)str, cend = c + maxlen; c < cend; ++c) \ if ('\0' == *c) \ break; \ rslt = c - (unsigned char *)str; \ } #endif #define STRNDUP(STR, MAXLEN, DST) \ { \ size_t local_len; \ \ STRNLEN(STR, MAXLEN, local_len); \ DST = (char *) malloc(local_len + 1); \ memcpy(DST, STR, local_len); \ DST[local_len] = '\0'; \ } #endif fis-gtm-V6.0-003/sr_port/gtm_strings.h0000644000032200000250000000110612201176156016542 0ustar librarygtc/**************************************************************** * * * Copyright 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_STRINGSH #define GTM_STRINGSH #include #define STRCASECMP strcasecmp #define STRNCASECMP strncasecmp #endif fis-gtm-V6.0-003/sr_port/gtm_tempnam.c0000644000032200000250000000263112201176156016511 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_stdio.h" #include "gtm_tempnam.h" /************************************************************** * gtm_tempnam() * Generates a temporary file name and places it in fullname * Note that fullname should be malloced by the caller * It is assumed to be of proper size (MAX_FN_LEN + 1) * **************************************************************/ void gtm_tempnam(char *dir, char *prefix, char *fullname) { static int temp_file_counter = 0; int len; char *ptr, def_prefix[] = "GTM_TEMP_"; if (NULL == dir) { len = SIZEOF(SCRATCH_DIR) - 1; memcpy(fullname, SCRATCH_DIR, len); } else { len = STRLEN(dir); memcpy(fullname, dir, len); } ptr = fullname + len; if (NULL == prefix) { prefix = def_prefix; len = SIZEOF(def_prefix) - 1; memcpy(ptr, def_prefix, len); } else { len = STRLEN(prefix); memcpy(ptr, prefix, len); } ptr += len; SPRINTF(ptr, "_%d.tmp", temp_file_counter++); } fis-gtm-V6.0-003/sr_port/gtm_tempnam.h0000644000032200000250000000131412201176156016513 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GTM_TEMPNAM_H__ #define __GTM_TEMPNAM_H__ void gtm_tempnam(char *dir, char *prefix, char *fullname); #if defined(UNIX) # define SCRATCH_DIR "/tmp/" #elif defined(VMS) # define SCRATCH_DIR "SYS$SCRATCH:" #else # error Unsupported Platform #endif #endif fis-gtm-V6.0-003/sr_port/gtm_text_alloc.h0000644000032200000250000000641312201176156017215 0ustar librarygtc/**************************************************************** * * * Copyright 2007, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_TEXT_ALLOC_H #define GTM_TEXT_ALLOC_H /* States a storage element may be in (which need to be different from malloc states). */ enum TextState {TextAllocated = 0x43, TextFree = 0x34}; /* Each allocated block (in the mmap build) has the following structure. The actual address returned to the user for allocation and supplied by the user for release is actually the storage beginning at the 'userStorage.userStart' area. This holds true even for storage that is truely mmap'd. */ typedef struct textElemStruct { /* This flavor of header is 16 bytes. This is required on IA64 and we have just adopted it for the other platforms as well as it is a minor expense given the sizes of chunks we are using */ int queueIndex; /* Index into TwoTable for this size of element */ enum TextState state; /* State of this block */ unsigned int realLen; /* Real (total) length of allocation */ int filler; union /* The links are used only when element is free */ { struct /* Free block information */ { struct textElemStruct *fPtr; /* Next storage element on free queue */ struct textElemStruct *bPtr; /* Previous storage element on free queue */ } links; unsigned char userStart; /* First byte of user useable storage */ } userStorage; } textElem; /* The below macros are used to allocate and release areas of storage that will be used to contain executable code. Traditionally, GTM has just used malloc() and free() and placed this code on the heap but some systems now protect against that (noteably Linux). On those platforms (and any others we choose to separate the executable storage pools from the regular heap storage), we use gtm_text_alloc() and gtm_text_free() to allocate and free executable storage. These modules use mmap() and munmap() for this purpose. Note that while use of the mmap() interface for executable storage does have some potential advantages for security (and as noted above, is required for some platforms to even function, because of the page aligned granularity of its requests, storage usage with gtm_text_alloc() is not as efficient as it is with regular heap based storage. For this reason, we only use this method on the required platforms rather than all. Replaceing the algorithms in gtm_text_alloc.c with ones not based on the buddy system could potentially alleviate these efficiency differences. */ #if defined(__linux__) || defined(__osf__) || defined(__MVS__) || defined(__CYGWIN__) # define GTM_TEXT_ALLOC(x) gtm_text_alloc(x) # define GTM_TEXT_FREE(x) gtm_text_free(x) void *gtm_text_alloc(size_t size); void gtm_text_free(void *addr); void printAllocInfo(void); # define COMP_GTA /* Build gtm_text_alloc() module */ # else # define GTM_TEXT_ALLOC(x) gtm_malloc(x) # define GTM_TEXT_FREE(x) gtm_free(x) #endif #endif /* GTM_TEXT_ALLOC_H */ fis-gtm-V6.0-003/sr_port/gtm_threadgbl.h0000644000032200000250000001412212201176156017007 0ustar librarygtc/**************************************************************** * * * Copyright 2010, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_THREADGBL_included #define GTM_THREADGBL_included #ifndef NO_THREADGBL_DEFTYPES # include "gtm_threadgbl_deftypes.h" /* Avoided for gtm_threadgbl_deftypes.c which builds this header file */ #endif /* The following three macros allow access to global variables located in the thread-global array. The ultimate * goal of this array is to permit GTM to become thread-safe. That is not yet true but this framework is the first * step in taming our global variable use. In the future, these macros will change to their thread-safe counterparts * such that we can have different arrays per thread. * * The macros can be classified as declaration (DCL_THREADGBL_ACCESS), definition (SETUP_THREADGBL_ACCESS), and * usage (TADR, TREF, TAREF1, TAREF2, RFPTR, SFPTR, IVFPTR). * * DCL_THREADGBL_ACCESS - simple job is to declare the local variable used as an anchor to the thread global * array. It should be located in the declaration section of an entry point. * * SETUP_THREAD_GBL_ACCESS - Sets the value of the local variable used as an anchor. Today, this is just a * global var de-reference. In the future, it will use thread-logic to access a * thread related base var. This should be placed near the top of the executable * code for the routine - certainly before the first TREF macro. * TADR - Used to obtain the address of the element. * TREF - Used to dereference a global var (see notes at TREF macro for usage). * TAREF1/TAREF2 - Used to access array elements - TAREF1 for vectors, TAREF2 for 2 subscript access. * RFPTR - Used to reference a function pointer in an expression or conditional. * SFPTR - Used to set a new value into a function pointer. * IVFPTR - Used to invoke a function pointer. */ /* Declare local thread global anchor */ #define DCL_THREADGBL_ACCESS void *lcl_gtm_threadgbl /* Setup the local thread global anchor giving a value (and purpose in life) */ #define SETUP_THREADGBL_ACCESS lcl_gtm_threadgbl = gtm_threadgbl /* Reference a given global in the thread global array. There are a couple of different ways this macro can be * used. Note that its first term is a "de-reference" (aka "*"). As an example, say we have a global name defined * as follows: * * somestruct *gblname; * * and we wish to access gblname->subfield. If we code "TREF(gblname)->subfield", that would generate * * *((somestruct **)((char *)lcl_gtm_threadgbl + nnn))->subfield * * Note that the first dereference covers the entire expression instead of just the TREF expression. This is an incorrect * reference that hopefully produces a compiler error instead of a hard-to-find bug. What needs to be coded instead is * (TREF(gblname))->subfield which generates: * * (*((somestruct **)((char *)lcl_gtm_threadgbl + nnn)))->subfield * * This isolates the dereference to the expression it needs to refer to and produces an expression to correctly access the * desired field. However, if the global is not a pointer, but say, a boolean, then you CANNOT surround the TREF macro with * parens if the expression is on the left hand side of the "=" operator because that is not a valid LREF expression. So if * the field were a boolean, you could modify it as "TREF(somebool) = TRUE;". * * The general rule of thumb is if the global is a pointer being used to access a subfield, or if the global is a structure * itself and you are accessing subfields with a "." operator (e.g. (TREF(fnpca)).fnpcs[i].indx = i;) surround the TREF with (). * Otherwise* you can leave it unadorned. * * Note that function pointers present some odd constraints. You can cast something to a function pointer type but only * when you are going to actually invoke it (as the IVFPTR() macro does below). But this means that non-invoking references * (or assignments) cannot use casts to make types match. So we need 2 additional macros for reference in an expression (RFPTR) * or setting a function pointer (SFPTR) so we can control the necessary aspects of the expressions involved. See * $sr_unix/generic_signal_handler.c for uses of most of these macros used with function pointers. */ #define TREF(name) *((ggt_##name *)((char *)lcl_gtm_threadgbl + ggo_##name)) /* For address of item use TADR(name) macro */ #define TADR(name) ((ggt_##name *)((char *)lcl_gtm_threadgbl + ggo_##name)) /* For access to single dimension array (vector), use TAREF1 macro */ #define TAREF1(name, indx1) (TADR(name))[indx1] /* For access to 2 dimension array, use TAREF2 macro */ #define TAREF2(name, indx1, indx2) ((ggt_##name *)((char *)lcl_gtm_threadgbl + ggo_##name + /* Base addr of array */ \ (((indx1) - 1) * SIZEOF(ggt_##name) * ggd_##name)))[indx2] /* Row offset */ /* To set a function pointer, use SFPTR(name) macro - Used to copy an address INTO a function pointer */ #define SFPTR(name, value) *((char **)((char *)lcl_gtm_threadgbl + ggo_##name)) = (char *)(value) /* To reference a function pointer's value, use RFPTR(name) macro. Use only in rvalue RHS expressions. Does not produce * an lvalue suitable for LHS usage. See SFPTR() above if function pointer needs a new value. */ #define RFPTR(name) (ggt_##name (*)gga_##name)(*(char **)((char *)lcl_gtm_threadgbl + ggo_##name)) /* To invoke a function pointer, use IVFPTR(name) macro */ #define IVFPTR(name) ((ggf_##name)(*(char **)((char *)lcl_gtm_threadgbl + ggo_##name))) /* In the main routines for GTM and the utilities that need to initialize the thread global structure all other routines access, * this macro should be used in lieu of SETUP_THREADGBL_ACCESS. */ #define GTM_THREADGBL_INIT \ { \ gtm_threadgbl_init(); \ SETUP_THREADGBL_ACCESS; \ } #endif fis-gtm-V6.0-003/sr_port/gtm_threadgbl_defs.h0000644000032200000250000005320412201176156020014 0ustar librarygtc/**************************************************************** * * * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* Note since this table is included multiple times, it should not have "previously included" protection. * * When adding items to this table, please be aware of alignment issues. * * Notes on where to put added items: * * 1. Make organization defensible. Possible organizations: * a. Group like-types alphabetically. * b. Gorup related items (such as compiler, replication, etc. * 2. Because references will use an offset into this structure and since the "immediate offset" in * compiler generated instructions is usually limited to "smaller" values like less than 16K or * 32K or whatever (platform dependent), items near the top of the table should be reserved used for * the most commonly used items (e.g. cs_addrs, cs_data, gv_target, etc). * 3. Larger arrays/structures should go nearer the end. * 4. There are no other runtime dependencies on this order. The order of fields can be switched around * any way desired with just a rebuild. * 5. It is important for ANY DEBUG_ONLY fields to go at the VERY END. Failure to do this breaks gtmpcat. * 6. If a DEBUG_ONLY array is declared whose dimension is a macro, then it is necessary, for gtmpcat to work, * that the macro shouldn't be defined as DEBUG_ONLY. */ /* Priority access fields - commonly used fields in performance situations */ THREADGBLDEF(grabbing_crit, gd_region *) /* Region currently grabbing crit in (if any) */ /* Compiler */ THREADGBLDEF(boolchain, triple) /* anchor for chain used by bx_boolop */ THREADGBLDEF(boolchain_ptr, triple *) /* pointer to anchor for chain used by bx_boolop */ THREADGBLDEF(bool_targ_anchor, tbp) /* anchor of targ chain for bool relocation */ THREADGBLDEF(bool_targ_ptr, tbp *) /* ptr->anchor of targ chain for bool relocation */ THREADGBLDEF(code_generated, boolean_t) /* flag that the compiler generated an object */ THREADGBLDEF(codegen_padlen, int4) /* used to pad code to section alignment */ THREADGBLDEF(compile_time, boolean_t) /* flag that the compiler's at work */ THREADGBLDEF(curtchain, triple *) /* pointer to anchor of current triple chain */ THREADGBLDEF(director_ident, mstr) /* look-ahead scanner mident from advancewindow */ THREADGBLDEF(director_mval, mval) /* look-ahead scanner mval from advancewindow*/ THREADGBLDEF(director_token, char) /* look-ahead scanner token from advancewindow */ THREADGBLDEF(dollar_zcstatus, int4) /* return status for zcompile and others */ THREADGBLDEF(expr_depth, unsigned int) /* expression nesting level */ THREADGBLDEF(expr_start, triple *) /* chain anchor for side effect early evaluation */ THREADGBLDEF(expr_start_orig, triple *) /* anchor used to test if there's anything hung on * expr_start */ THREADGBLDEF(for_stack_ptr, oprtype **) /* part of FOR compilation nesting mechanism */ THREADGBLDEF(gtm_fullbool, unsigned int) /* controls boolean side-effect behavior defaults * to 0 (GTM_BOOL) */ THREADGBLDEF(ind_result, mval *) /* pointer to indirection return location */ THREADGBLDEF(ind_source, mval *) /* pointer to indirection source location */ THREADGBLDEF(indirection_mval, mval) /* used for parsing subscripted indirection */ THREADGBLDEF(last_source_column, short int) /* parser tracker */ THREADGBLDEF(pos_in_chain, triple) /* anchor used to restart after a parsing error */ THREADGBLDEF(s2n_intlit, boolean_t) /* type info from s2n for advancewindow */ THREADGBLDEF(saw_side_effect, boolean_t) /* need side effect handling other than naked */ THREADGBLDEF(shift_side_effects, int) /* flag shifting of side-effects ahead of boolean * evalation */ THREADGBLDEF(side_effect_base, boolean_t *) /* anchor side effect array: bin ops & func args */ THREADGBLDEF(side_effect_depth, uint4) /* current high water of side effect expr array */ THREADGBLDEF(side_effect_handling, int) /* side effect handling in actuallists, function * args & non-boolean binary operator operands */ THREADGBLDEF(source_error_found, int4) /* flag to partially defer compiler error */ THREADGBLDEF(temp_subs, boolean_t) /* flag temp storing of subscripts to preserve * current evaluation */ THREADGBLDEF(trigger_compile, boolean_t) /* A trigger compilation is active */ THREADGBLDEF(window_ident, mstr) /* current scanner mident from advancewindow */ THREADGBLDEF(window_mval, mval) /* current scanner mval from advancewindow */ THREADGBLDEF(window_token, char) /* current scanner token from advancewindow */ /* Database */ THREADGBLDEF(dbinit_max_hrtbt_delta, uint4) /* max heartbeats before we bail out in db_init */ THREADGBLDEF(dollar_zmaxtptime, int4) /* tp timeout in seconds */ THREADGBLDEF(donot_commit, boolean_t) /* debug-only - see gdsfhead.h for purpose */ THREADGBLDEF(donot_write_inctn_in_wcs_recover, boolean_t) /* TRUE if wcs_recover should NOT write INCTN */ THREADGBLDEF(gd_targ_addr, gd_addr *) /* current global directory reference */ THREADGBLDEF(gtm_custom_errors, mstr) THREADGBLDEF(gtm_gvundef_fatal, boolean_t) /* core and die intended for testing */ THREADGBLDEF(gv_extname_size, int4) /* part op_gvextname working memory mechanism */ THREADGBLDEF(gv_last_subsc_null, boolean_t) /* indicates whether the last subscript of * gv_currkey (aka $reference) is a NULL string */ THREADGBLDEF(gv_mergekey2, gv_key *) /* op_merge working memory */ THREADGBLDEF(gv_reorgkey, gv_key *) /* mu_swap_blk working memory */ THREADGBLDEF(gv_some_subsc_null, boolean_t) /* TRUE if SOME subscript other than the last is * NULL in gv_currkey (aka $REFERENCE). Note that * while "some" in var name might typically include * the last subscript, it does NOT in this case and * allows name to be kept shorter. */ THREADGBLDEF(gv_sparekey, gv_key *) /* gv_xform_key working memory */ THREADGBLDEF(gv_sparekey_mval, mval) /* gv_xform_key working memory */ THREADGBLDEF(gv_sparekey_size, int4) /* part gv_xform_key working memory mechanism */ THREADGBLDEF(gv_tporigkey_ptr, gv_orig_key_array *) /* op_tstart tp nesting anchor */ THREADGBLDEF(in_gvcst_redo_root_search, boolean_t) /* TRUE if gvcst_redo_root_search is in C-stack */ THREADGBLDEF(in_op_gvget, boolean_t) /* TRUE if op_gvget() is a C-stack call ancestor */ THREADGBLDEF(issue_DBROLLEDBACK_anyways, boolean_t) /* currently set by MUPIP LOAD */ THREADGBLDEF(last_fnquery_return_subcnt, int) /* count subscript in last_fnquery_return_sub */ THREADGBLDEF(last_fnquery_return_varname, mval) /* returned varname of last $QUERY() */ #ifdef VMS THREADGBLDEF(new_dbinit_ipc, int4) /* indicates whether shared memory/semaphore is * created by db_init (also used by dbinit_ch) */ #endif THREADGBLDEF(ok_to_call_wcs_recover, boolean_t) /* Set to TRUE before a few wcs_recover callers. * Any call to wcs_recover in the final retry * assert to prevent cache recovery while in a * transaction and confuse things enough to cause * further restarts (which is out-of-design while * in the final retry). */ THREADGBLDEF(in_gvcst_bmp_mark_free, boolean_t) /* May need to skip online rollback cleanup or * gvcst_redo_root_search on a restart */ THREADGBLDEF(prev_gv_target, gv_namehead *) /* saves the last gv_target for debugging */ THREADGBLDEF(ready2signal_gvundef, boolean_t) /* TRUE if GET operation about to signal GVUNDEF */ #ifdef UNIX THREADGBLDEF(redo_rootsrch_ctxt, redo_root_search_context) /* context to be saved and restored during * gvcst_redo_root_search */ #endif THREADGBLDEF(semwait2long, volatile boolean_t) /* Waited too long for a semaphore */ THREADGBLDEF(skip_file_corrupt_check, boolean_t) /* skip file_corrupt check in grab_crit */ THREADGBLDEF(tpnotacidtime, int4) /* limit for long non-ACID ops in transactions */ THREADGBLDEF(tp_restart_count, uint4) /* tp_restart counter */ THREADGBLDEF(tp_restart_dont_counts, int4) /* tp_restart count adjustment; NOTE: DEBUG only */ THREADGBLDEF(tp_restart_entryref, mval) /* tp_restart position for reporting */ THREADGBLDEF(tp_restart_failhist_indx, int4) /* tp_restart dbg restart history index */ THREADGBLDEF(tprestart_syslog_delta, int4) /* defines every n-th restart to be logged */ THREADGBLDEF(tprestart_syslog_limit, int4) /* # of TP restarts logged unconditionally */ THREADGBLDEF(transform, boolean_t) /* flag collation transform eligible */ THREADGBLDEF(wcs_recover_done, boolean_t) /* TRUE if wcs_recover was ever invoked in this * process. */ /* Local variables */ THREADGBLDEF(in_op_fnnext, boolean_t) /* set TRUE by op_fnnext; FALSE by op_fnorder */ THREADGBLDEF(local_collseq, collseq *) /* pointer to collation algorithm for lvns */ THREADGBLDEF(local_collseq_stdnull, boolean_t) /* flag temp controlling empty-string subscript * handling - if true, use standard null subscript * collation for local variables */ THREADGBLDEF(local_coll_nums_as_strings, boolean_t) /* flag controlling whether local variables that * evaluate to numbers are treated like numbers * (collating before strings) or like strings in * local collations */ THREADGBLDEF(lv_null_subs, int) /* UNIX: set in gtm_env_init_sp(), * VMS: set in gtm$startup() */ THREADGBLDEF(max_lcl_coll_xform_bufsiz, int) /* max size of local collation buffer,which extends * from 32K each time the buffer overflows */ /* Replication variables */ THREADGBLDEF(replgbl, replgbl_t) /* set of global variables needed by the source * server */ THREADGBLDEF(tqread_nowait, boolean_t) /* avoid sleeping in t_qread if TRUE */ /* Miscellaneous */ THREADGBLDEF(collseq_list, collseq *) /* list of pointers to currently mapped collation * algorithms - since this seems only used in * collseq.c -seems more like a STATICDEF */ THREADGBLFPTR(create_fatal_error_zshow_dmp_fptr, void, (void)) /* Fptr for gtm_fatal_error* zshow dmp routine */ THREADGBLDEF(disable_sigcont, boolean_t) /* indicates whether the SIGCONT signal * is allowed internally */ THREADGBLDEF(dollar_zcompile, mstr) /* compiler qualifiers */ THREADGBLDEF(dollar_zmode, mval) /* run mode indicator */ THREADGBLDEF(dollar_zonlnrlbk, int) /* ISV (incremented for every online rollback) */ THREADGBLDEF(dollar_zroutines, mstr) /* routine search list */ THREADGBLDEF(error_on_jnl_file_lost, unsigned int) /* controls error handling done by jnl_file_lost. * 0 (default) : Turn off journaling and continue. * 1 : Keep journaling on, throw rts_error. * VMS does not supports this and requires it to * be 0. */ #ifdef UNIX THREADGBLDEF(fnzsearch_lv_vars, lv_val *) /* UNIX op_fnzsearch lv tree anchor */ THREADGBLDEF(fnzsearch_sub_mval, mval) /* UNIX op_fnzsearch subscript constuctor */ THREADGBLDEF(fnzsearch_nullsubs_sav, int) /* UNIX op_fnzsearch temp for null subs control */ #endif THREADGBLDEF(glvn_pool_ptr, glvn_pool *) /* Pointer to the glvn pool */ #if defined(UNIX) && defined(GTMDBGFLAGS_ENABLED) THREADGBLDEF(gtmdbgflags, int) THREADGBLDEF(gtmdbgflags_freq, int) THREADGBLDEF(gtmdbgflags_freq_cntr, int) #endif THREADGBLDEF(gtm_env_init_started, boolean_t) /* gtm_env_init flag envvar processing */ THREADGBLFPTR(gtm_env_xlate_entry, int, ()) /* gtm_env_xlate() function pointer */ THREADGBLDEF(gtm_environment_init, boolean_t) /* indicates GT.M development environment rather * than a production environment */ THREADGBLFPTR(gtm_sigusr1_handler, void, (void)) /* SIGUSR1 signal handler function ptr */ THREADGBLDEF(gtm_trctbl_cur, trctbl_entry *) /* Current gtm trace table entry */ THREADGBLDEF(gtm_trctbl_end, trctbl_entry *) /* End of gtm trace table (last entry + 1) */ THREADGBLDEF(gtm_trctbl_groups, unsigned int) /* Trace group mask (max 31 groups) */ THREADGBLDEF(gtm_trctbl_start, trctbl_entry *) /* Start of gtm trace table */ THREADGBLDEF(gtm_waitstuck_script, mstr) /* Path to the script to be executed during waits*/ THREADGBLDEF(gtmprompt, mstr) /* mstr pointing to prombuf containing the GTM * prompt */ THREADGBLDEF(gtmsecshr_comkey, unsigned int) /* Hashed version key for gtmsecshr communications * eliminates cross-version issues */ THREADGBLDEF(in_zwrite, boolean_t) /* ZWrite is active */ THREADGBLDEF(lab_proxy, lab_tabent_proxy) /* Placeholder storing lab_ln_ptr offset / lnr_adr * pointer and has_parms value, so they are * contiguous in memory */ #ifdef VMS THREADGBLDEF(lbl_tbl_entry_index, int) /* Index of currently compiled label table entry */ THREADGBLAR1DEF(login_time, int4, 2) /* */ #endif THREADGBLDEF(mprof_alloc_reclaim, boolean_t) /* Flag indicating whether the temporarily allocated * memory should be reclaimed */ THREADGBLDEF(mprof_chunk_avail_size, int) /* Number of mprof stack frames that can fit in * the current chunk */ THREADGBLDEF(mprof_env_gbl_name, mval) /* Name of global to use in mprof testing; should * be undefined to not use explicit mprof testing, * and empty or '0' if mprof data should not be * dumped into a global at the end */ THREADGBLDEF(mprof_ptr, mprof_wrapper *) /* Object containing key mprof references */ THREADGBLDEF(mprof_reclaim_addr, char *) /* Address of the memory bucket before * unw_prof_frame temporary allocations in case they * go to new bucket */ THREADGBLDEF(mprof_reclaim_cnt, int) /* Amount of mem to reclaim after unw_prof_frame */ THREADGBLDEF(mprof_stack_curr_frame, mprof_stack_frame *) /* Pointer to the last frame on the mprof stack */ THREADGBLDEF(mprof_stack_next_frame, mprof_stack_frame *) /* Pointer to the next frame to be put on the * mprof stack */ #ifdef UNIX THREADGBLDEF(open_shlib_root, open_shlib *) /* Anchor for open shared library list */ #endif THREADGBLDEF(parm_pool_ptr, parm_pool *) /* Pointer to the parameter pool */ THREADGBLDEF(parms_cnt, unsigned int) /* Parameters count */ #ifdef UNIX THREADGBLAR1DEF(zpeek_regname, char, NAME_ENTRY_SZ) /* Last $ZPEEK() region specified */ THREADGBLDEF(zpeek_regname_len, int) /* Length of zpeekop_regname */ THREADGBLDEF(zpeek_reg_ptr, gd_region *) /* Resolved pointer for zpeekop_regname */ THREADGBLDEF(pipefifo_interrupt, int) /* count of number of times a pipe or fifo device is * interrupted */ #endif THREADGBLDEF(prof_fp, mprof_stack_frame *) /* Stack frame that mprof currently operates on */ THREADGBLDEF(trans_code_pop, mval *) /* trans_code holder for $ZTRAP popping */ THREADGBLDEF(view_ydirt_str, char *) /* op_view working storage for ydir* ops */ THREADGBLDEF(view_ydirt_str_len, int4) /* Part of op_view working storage for ydir* ops */ THREADGBLDEF(zdate_form, int4) /* Control for default $zdate() format */ THREADGBLAR1DEF(zintcmd_active, zintcmd_active_info, ZINTCMD_LAST) /* Interrupted timed commands */ THREADGBLDEF(zro_root, zro_ent *) /* Anchor for zroutines structure entry array */ #ifdef UNIX THREADGBLDEF(zsearch_var, lv_val *) /* UNIX $zsearch() lookup variable */ THREADGBLDEF(zsearch_dir1, lv_val *) /* UNIX $zsearch() directory 1 */ THREADGBLDEF(zsearch_dir2, lv_val *) /* UNIX $zsearch() directory 2 */ #endif /* Larger structures and char strings */ THREADGBLAR1DEF(director_string, char, SIZEOF(mident_fixed)) /* Buffer for director_ident */ THREADGBLDEF(fnpca, fnpc_area) /* $Piece cache structure area */ THREADGBLAR1DEF(for_stack, oprtype *, MAX_FOR_STACK) /* Stacks FOR scope complete (compilation) addrs */ THREADGBLAR1DEF(for_temps, boolean_t, MAX_FOR_STACK) /* Stacked flags of FOR control value temps */ THREADGBLAR1DEF(last_fnquery_return_sub, mval, MAX_LVSUBSCRIPTS)/* Returned subscripts of last $QUERY() */ THREADGBLDEF(lcl_coll_xform_buff, char *) /* This buffer is for local collation * transformations, which must not nest - i.e. * a transformation routine must not call another, * or itself. This kind of nesting would cause * overwriting of the buffer */ #ifdef UNIX THREADGBLAR1DEF(parm_ary, char *, MAX_PARMS) /* Parameter strings buffer */ THREADGBLAR1DEF(parm_ary_len, int, MAX_PARMS) /* Array element allocation length */ THREADGBLAR1DEF(parm_str_len, int, MAX_PARMS) /* Parameter strings lengths */ #endif THREADGBLAR1DEF(prombuf, char, (MAX_MIDENT_LEN + 1)) /* The prompt buffer size (32) would allow at * least 8 Unicode characters, but since most * commonly used Unicode characters only occupy up * to 3 bytes, the buffer would at least * accommodate 10 Unicode characters in a prompt */ THREADGBLDEF(rt_name_tbl, hash_table_mname) /* Routine hash table for finding $TEXT() info */ THREADGBLAR1DEF(tp_restart_failhist_arry, char, FAIL_HIST_ARRAY_SIZE) /* tp_restart dbg storage of restart history */ #ifdef UNIX THREADGBLDEF(user_id, uint4) /* USERID number */ #endif THREADGBLAR1DEF(window_string, char, SIZEOF(mident_fixed)) /* Buffer for window_ident */ /* Utility I/O */ THREADGBLDEF(last_va_list_ptr, va_list) /* Last variable-length argument list used for util * out buffer management */ THREADGBLAR1DEF(util_outbuff, char, OUT_BUFF_SIZE * UTIL_OUTBUFF_STACK_SIZE) /* Util output buffer */ THREADGBLDEF(util_outbuff_ptr, char *) /* Pointer to util output buffer */ THREADGBLDEF(util_outptr, char *) /* Pointer within util output buffer */ /* GTM Call-in related globals */ #ifdef UNIX THREADGBLDEF(callin_hashtab, hash_table_str *) /* Callin hash table */ THREADGBLDEF(ci_table, callin_entry_list *) /* Callin table in the form of a linked list */ #endif THREADGBLDEF(extcall_package_root, struct extcall_package_list *) /* External call table package list */ #ifdef UNIX THREADGBLDEF(gtmci_nested_level, unsigned int) /* Current nested depth of callin environments */ THREADGBLDEF(in_gtmci, boolean_t) /* Indicates if we are in one of the gtm_ci... * functions. */ #endif THREADGBLDEF(want_empty_gvts, boolean_t) /* set to TRUE by MUPIP REORG when it is selecting * globals to be reorged. Need to be able to select * killed globals for effective truncate. */ THREADGBLDEF(in_mu_swap_root_state, unsigned int) /* Three states: * MUSWP_INCR_ROOT_CYCLE: MUPIP REORG moves GVT * root blocks in mu_swap_root. * MUSWP_FREE_BLK: MUPIP REORG frees blocks * MUSWP_NONE */ THREADGBLDEF(prev_t_tries, unsigned int) /* t_tries - 1, before t_retry/tp_restart */ THREADGBLDEF(rlbk_during_redo_root, boolean_t) /* set to TRUE if an online rollback which takes * the db to a different logical state occurs * during gvcst_redo_root_search in t_retry */ THREADGBLDEF(mlk_yield_pid, uint4) /* if non-zero, indicates the process id for which * we yielded a chance to get this lock. We keep * yielding as long as the process-id that is the * first in the wait queue ("d->pending") changes. * If the pid stays the same, we stop yielding. * if -1, indicates we disabled fairness mechanism * in order to avoid livelocks. */ THREADGBLDEF(jnl_extract_nocol, uint4) /* If non-zero, MUPIP JOURNAL EXTRACT will skip * reading the directory tree to find the * collation information for each global. Note * that this might result in garbled subscripts * in the extract if globals do use alternative * collation. */ #ifdef GTM_TRIGGER THREADGBLDEF(gvt_triggers_read_this_tn, boolean_t) /* if non-zero, indicates triggers were read for * at least one gv_target in this transaction. * A complete list of all gv_targets who had * triggers read in this transaction can be found * by going through the gvt_tp_list and checking * if gvt->trig_read_tn matches local_tn. This is * useful to invalidate all those triggers in case * of a transaction restart or rollback. */ THREADGBLDEF(in_op_fntext, boolean_t) /* Denote the trigger was processed in $Text() */ #endif /* Debug values */ #ifdef DEBUG THREADGBLDEF(continue_proc_cnt, int) /* Used by whitebox secshr test to count time * process was continued. */ THREADGBLDEF(gtm_test_fake_enospc, boolean_t) /* DEBUG-only option to enable/disable anticipatory * freeze fake ENOSPC testing */ THREADGBLDEF(gtm_usesecshr, boolean_t) /* Bypass easy methods of dealing with IPCs, files, * wakeups, etc and always use gtmsecshr (testing). */ THREADGBLDEF(rts_error_unusable, boolean_t) /* Denotes the window in which an rts_error is * unusable */ THREADGBLDEF(rts_error_unusable_seen, boolean_t) THREADGBLAR1DEF(trans_restart_hist_array, trans_restart_hist_t, TRANS_RESTART_HIST_ARRAY_SZ) /* See tp.h for usage */ THREADGBLDEF(trans_restart_hist_index, uint4) #endif fis-gtm-V6.0-003/sr_port/gtm_threadgbl_deftypes.c0000644000032200000250000001574312201176176020721 0ustar librarygtc/**************************************************************** * * * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* Since we are about to create gtm_threadgbl_deftypes.h, signal gtm_threadgbl.h to avoid including it */ #define NO_THREADGBL_DEFTYPES #include "mdef.h" #include #include "gtm_inet.h" #include "gtm_iconv.h" #include "gtm_socket.h" #include "gtm_unistd.h" #include "gtm_limits.h" #include #include #ifdef UNIX # include #endif #ifdef VMS # include /* Required for gtmsource.h */ # include # include # include "desblk.h" #endif #include "cache.h" #include "hashtab_addr.h" #include "hashtab_int4.h" #include "hashtab_int8.h" #include "hashtab_mname.h" #include "hashtab_str.h" #include "hashtab_objcode.h" #include "error.h" #include #include "gdsroot.h" #include "gdskill.h" #include "ccp.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gdscc.h" #include "comline.h" #include "compiler.h" #include "cmd_qlf.h" #include "io.h" #include "iosp.h" #include "jnl.h" #include "lv_val.h" #include "collseq.h" #include "mdq.h" #include "mprof.h" #include "mv_stent.h" #include "find_mvstent.h" /* needed for zintcmd_active */ #include "stack_frame.h" #include "stp_parms.h" #include "stringpool.h" #include "buddy_list.h" /* needed for tp.h */ #include "tp.h" #include "tp_frame.h" #include "mlkdef.h" #include "zshow.h" #include "zwrite.h" #include "zbreak.h" #include "fnpc.h" #include "mmseg.h" #ifndef VMS # include "gtmsiginfo.h" #endif #include "gtmimagename.h" #include "iotcpdef.h" #include "gt_timer.h" #include "iosocketdef.h" /* needed for socket_pool and MAX_N_SOCKETS*/ #include "ctrlc_handler_dummy.h" #include "unw_prof_frame_dummy.h" #include "op.h" #include "gtmsecshr.h" #include "error_trap.h" #include "patcode.h" /* for pat_everything and sizeof_pat_everything */ #include "source_file.h" /* for REV_TIME_BUFF_LEN */ #include "mupipbckup.h" #include "dpgbldir.h" #include "mmemory.h" #include "have_crit.h" #include "alias.h" #include "zroutines.h" #include "trace_table.h" #include "parm_pool.h" #include "util.h" /* for util_outbuff manipulations */ #include "nametabtyp.h" /* FOR REPLICATION RELATED GLOBALS */ #include "repl_msg.h" #include "gtmsource.h" #include "gtmrecv.h" #include "replgbl.h" /* FOR MERGE RELATED GLOBALS */ #include "gvname_info.h" #include "op_merge.h" #ifdef UNIX # include "cli.h" # include "invocation_mode.h" # include "fgncal.h" # include "parse_file.h" /* for MAX_FBUFF */ # include "repl_sem.h" # include "gtm_zlib.h" # include "zro_shlibs.h" #endif #include "jnl_typedef.h" #ifdef VMS # include "gtm_logicals.h" /* for GTM_MEMORY_NOACCESS_COUNT */ #endif #include "gds_blk_upgrade.h" /* for UPGRADE_IF_NEEDED flag */ #include "cws_insert.h" /* for CWS_REORG_ARRAYSIZE */ #ifdef UNICODE_SUPPORTED # include "gtm_icu_api.h" # include "gtm_utf8.h" #endif #ifdef GTM_CRYPT # include "gtmcrypt.h" # include "gdsblk.h" # include "muextr.h" #endif #ifdef GTM_TRIGGER # include "gv_trigger.h" # include "gtm_trigger.h" #endif /* This module's purpose is to generate gtm_threadgbl_deftypes.h for a given platform. This header file * contains all the type and offset informatin needed for the TREF macro in gtm_threadgbl.h to access * any field in the global structure without having to have all the types known in every module. Only the * types used need be known. * * This is acomplished by creating the structure in this module with all types and offsets known and outputting * those values in the form of #define statements that can be used by subsequent compiles. */ /* First step, create the structure */ #define THREADGBLDEF(name, type) type name; #define THREADGBLFPTR(name, type, args) type (*name)args; #define THREADGBLAR1DEF(name, type, dim1) type name[dim1]; #define THREADGBLAR2DEF(name, type, dim1, dim2) type name[dim1][dim2]; typedef struct { #include "gtm_threadgbl_defs.h" } gtm_threadgbl_def_t; #undef THREADGBLDEF #undef THREADGBLFPTR #undef THREADGBLAR1DEF #undef THREADGBLAR2DEF /* Note this module uses regular (lower case) printf because using PRINTF calls gtm_printf which is inappropriate * since this module is not part of the GTM runtime but a standalone text generator. */ /* Define macros that will generate the type and offset #defines */ #define PRINT_TYPE_OFFSET(name, type) \ printf("# define ggo_%s %d\n", #name, (int)OFFSETOF(gtm_threadgbl_def_t, name)); \ printf("# define ggt_%s %s\n", #name, #type); /* For function pointers, we need the offset and type (which is a return type in this case since the actual type of * the item is "function pointer") but also need the argument declarations for the function declaration to be complete * Lastly, we need a function pointer typedef to make invocations work correctly. */ #define PRINT_TYPE_OFFSET_FPTR(name, type, args) \ printf("# define ggo_%s %d\n", #name, (int)OFFSETOF(gtm_threadgbl_def_t, name)); \ printf("# define ggt_%s %s\n", #name, #type); /* In this case, return type */ \ printf("# define gga_%s %s\n", #name, #args); \ printf("typedef %s (*ggf_%s)%s;\n", #type, #name, #args); /* For single dimension arrays, include the length of the entire array as it is likely needed, especially * for character types. */ #define PRINT_TYPE_OFFSET_ARY1(name, type, dim1) \ printf("# define ggo_%s %d\n", #name, (int)OFFSETOF(gtm_threadgbl_def_t, name)); \ printf("# define ggt_%s %s\n", #name, #type); \ printf("# define ggl_%s %d\n", #name, (int)SIZEOF(gtd.name)); /* For two dimensional arrays, we need to record the 2nd dimension as it is needed in the address computations */ #define PRINT_TYPE_OFFSET_ARY2(name, type, dim1, dim2) \ printf("# define ggo_%s %d\n", #name, (int)OFFSETOF(gtm_threadgbl_def_t, name)); \ printf("# define ggt_%s %s\n", #name, #type); \ printf("# define ggl_%s %d\n", #name, (int)SIZEOF(gtm_threadgbl_def_t.name)); \ printf("# define ggd_%s %d\n", #name, (int)dim2); int main() { gtm_threadgbl_def_t gtd; /* Now run through each var in the structure generating defines for the type and offset within the structure */ # define THREADGBLDEF(name, type) PRINT_TYPE_OFFSET(name, type) # define THREADGBLFPTR(name, type, args) PRINT_TYPE_OFFSET_FPTR(name, type, args) # define THREADGBLAR1DEF(name, type, dim1) PRINT_TYPE_OFFSET_ARY1(name, type, dim1) # define THREADGBLAR2DEF(name, type, dim1, dim2) PRINT_TYPE_OFFSET_ARY1(name, type, dim1, dim2) # include "gtm_threadgbl_defs.h" # undef THREADGBLDEF # undef THREADGBLFPTR # undef THREADGBLAR1DEF # undef THREADGBLAR2DEF printf("# define size_gtm_threadgbl_struct %d\n", (int)SIZEOF(gtm_threadgbl_def_t)); return 0; } fis-gtm-V6.0-003/sr_port/gtm_threadgbl_init.c0000644000032200000250000001535112201176176020034 0ustar librarygtc/**************************************************************** * * * Copyright 2010, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #define BYPASS_MEMCPY_OVERRIDE /* Signals gtm_string.h to not override memcpy(). When this routine is linked into gtcm_pkdisp, * the assert in the routine called by memcpy macro causes the world to be pulled in. Avoid. */ /* Note that since this routine is called prior to reading environment vars or pretty much any * other initialization, we cannot use gtm_malloc() yet so care is taken to use the real system * malloc. */ #undef malloc #undef free #include #include "gtm_stdio.h" #include "gtm_stdlib.h" #include "gtm_string.h" #include "gtm_inet.h" #include "gtm_iconv.h" #include "gtm_socket.h" #include "gtm_unistd.h" #include "gtm_limits.h" #include #include #ifdef UNIX # include #endif #ifdef VMS # include /* Required for gtmsource.h */ # include # include # include "desblk.h" #endif #include "cache.h" #include "hashtab_addr.h" #include "hashtab_int4.h" #include "hashtab_int8.h" #include "hashtab_mname.h" #include "hashtab_str.h" #include "hashtab_objcode.h" #include "error.h" #include #include "gdsroot.h" #include "gdskill.h" #include "ccp.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gdscc.h" #include "comline.h" #include "compiler.h" #include "cmd_qlf.h" #include "io.h" #include "iosp.h" #include "jnl.h" #include "lv_val.h" #include "collseq.h" #include "mdq.h" #include "mprof.h" #include "mv_stent.h" #include "find_mvstent.h" /* needed for zintcmd_active */ #include "stack_frame.h" #include "stp_parms.h" #include "stringpool.h" #include "buddy_list.h" /* needed for tp.h */ #include "tp.h" #include "tp_frame.h" #include "mlkdef.h" #include "zshow.h" #include "zwrite.h" #include "zbreak.h" #include "fnpc.h" #include "mmseg.h" #ifndef VMS # include "gtmsiginfo.h" #endif #include "gtmimagename.h" #include "iotcpdef.h" #include "gt_timer.h" #include "iosocketdef.h" /* needed for socket_pool and MAX_N_SOCKETS*/ #include "ctrlc_handler_dummy.h" #include "unw_prof_frame_dummy.h" #include "op.h" #include "gtmsecshr.h" #include "error_trap.h" #include "patcode.h" /* for pat_everything and sizeof_pat_everything */ #include "source_file.h" /* for REV_TIME_BUFF_LEN */ #include "mupipbckup.h" #include "dpgbldir.h" #include "mmemory.h" #include "have_crit.h" #include "alias.h" #include "zroutines.h" #include "parm_pool.h" #include "util.h" /* for util_outbuff manipulations */ #include "nametabtyp.h" /* FOR REPLICATION RELATED GLOBALS */ #include "repl_msg.h" #include "gtmsource.h" #include "gtmrecv.h" #include "replgbl.h" #include "trace_table.h" /* FOR MERGE RELATED GLOBALS */ #include "gvname_info.h" #include "op_merge.h" #ifdef UNIX # include "cli.h" # include "invocation_mode.h" # include "fgncal.h" # include "parse_file.h" /* for MAX_FBUFF */ # include "repl_sem.h" # include "gtm_zlib.h" # include "zro_shlibs.h" #endif #include "jnl_typedef.h" #ifdef VMS # include "gtm_logicals.h" /* for GTM_MEMORY_NOACCESS_COUNT */ #endif #include "gds_blk_upgrade.h" /* for UPGRADE_IF_NEEDED flag */ #include "cws_insert.h" /* for CWS_REORG_ARRAYSIZE */ #ifdef UNICODE_SUPPORTED # include "gtm_icu_api.h" # include "gtm_utf8.h" #endif #ifdef GTM_CRYPT # include "gtmcrypt.h" # include "gdsblk.h" # include "muextr.h" #endif #ifdef GTM_TRIGGER # include "gv_trigger.h" # include "gtm_trigger.h" #endif #include "gtm_threadgbl_init.h" #define DEFAULT_PROMPT "GTM>" GBLDEF void *gtm_threadgbl; /* Anchor for thread global for this thread */ /* Since gtm_threadgbl is type-neutral, define a structure mapping just for this routine that *does* * contain the types. This structure can be accessed through the debugger for easier type dumping. * Note we define this structure even in pro since it could be useful even in pro debugging (by gtmpcat). */ #define THREADGBLDEF(name,type) type name; #define THREADGBLFPTR(name, type, args) type (*name)args; #define THREADGBLAR1DEF(name, type, dim1) type name[dim1]; #define THREADGBLAR2DEF(name, type, dim1, dim2) type name[dim1][dim2]; typedef struct { # include "gtm_threadgbl_defs.h" } gtm_threadgbl_true_t; #undef THREADGBLDEF #undef THREADGBLFPTR #undef THREADGBLAR1DEF #undef THREADGBLAR2DEF GBLDEF gtm_threadgbl_true_t *gtm_threadgbl_true; /* This routine allocates the thread global structure and for now, since GTM is not yet threaded, * anchors it in a global variable. This still improves access to global variables even in this * paradym because the 3 step global dereference only need happen once per module. */ error_def(ERR_MEMORY); error_def(ERR_VMSMEMORY); error_def(ERR_GTMASSERT); void gtm_threadgbl_init(void) { void *lcl_gtm_threadgbl; if (SIZEOF(gtm_threadgbl_true_t) != size_gtm_threadgbl_struct) { /* Size mismatch with gtm_threadgbl_deftypes.h - no error handling yet available so do * the best we can. */ FPRINTF(stderr, "GTM-F-GTMASSERT gtm_threadgbl_true_t and gtm_threadgbl_t are different sizes\n"); exit(ERR_GTMASSERT); } if (NULL != gtm_threadgbl) { /* has already been initialized - don't re-init */ FPRINTF(stderr, "GTM-F-GTMASSERT gtm_threadgbl is already initialized\n"); exit(ERR_GTMASSERT); } gtm_threadgbl = lcl_gtm_threadgbl = malloc(size_gtm_threadgbl_struct); if (NULL == gtm_threadgbl) { /* Storage was not allocated for some reason - no error handling yet still */ perror("GTM-F-MEMORY Unable to allocate startup thread structure"); exit(UNIX_ONLY(ERR_MEMORY) VMS_ONLY(ERR_VMSMEMORY)); } memset(gtm_threadgbl, 0, size_gtm_threadgbl_struct); gtm_threadgbl_true = (gtm_threadgbl_true_t *)gtm_threadgbl; /* Add specific initializations if other than 0s here using the TREF() family of macros: */ (TREF(director_ident)).addr = TADR(director_string); TREF(for_stack_ptr) = TADR(for_stack); (TREF(gtmprompt)).addr = TADR(prombuf); (TREF(gtmprompt)).len = SIZEOF(DEFAULT_PROMPT) - 1; TREF(lv_null_subs) = LVNULLSUBS_OK; /* UNIX: set in gtm_env_init_sp(), VMS: set in gtm$startup() - init'd here * in case alternative invocation methods bypass gtm_startup() */ MEMCPY_LIT(TADR(prombuf), DEFAULT_PROMPT); (TREF(replgbl)).jnl_release_timeout = DEFAULT_JNL_RELEASE_TIMEOUT; (TREF(window_ident)).addr = TADR(window_string); TREF(util_outbuff_ptr) = TADR(util_outbuff); /* Point util_outbuff_ptr to the beginning of util_outbuff at first. */ } fis-gtm-V6.0-003/sr_port/gtm_threadgbl_init.h0000644000032200000250000000106012201176156020027 0ustar librarygtc/**************************************************************** * * * Copyright 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTM_THREADGBL_INIT_included #define GTM_THREADGBL_INIT_included void gtm_threadgbl_init(void); #endif fis-gtm-V6.0-003/sr_port/gtm_time.h0000644000032200000250000000536612201176156016023 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_time.h - interlude to system header file. */ #ifndef GTM_TIMEH #define GTM_TIMEH #include #define STRFTIME(dest, maxsize, format, timeptr, res) \ { \ DEFER_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ res = strftime(dest, maxsize, format, timeptr); \ ENABLE_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ } /* To use GET_CUR_TIME macro these definitions are required * now_t now; char *time_ptr; char time_str[CTIME_BEFORE_NL + 2]; */ #if defined(VMS) typedef struct { unsigned int buff1; unsigned int buff2; } now_t; #define CTIME_BEFORE_NL 20 #define GET_CUR_TIME \ { \ uint4 time_status; \ $DESCRIPTOR(atimenow, time_str); \ \ time_status = sys$asctim(0, &atimenow, 0, 0); \ if (0 != (time_status & 1)) \ { \ time_str[CTIME_BEFORE_NL] = '\n'; \ time_str[CTIME_BEFORE_NL + 1] = '\0'; \ time_ptr = time_str; \ } else \ time_ptr = "* sys$asctim failed*\n"; /* keep string len same as CTIME_BEFORE_NL */ \ } #elif defined(UNIX) typedef time_t now_t; #define CTIME_BEFORE_NL 24 #define GET_CUR_TIME \ { \ if ((time_t)-1 == (now = time(NULL))) \ time_ptr = "****** time failed *****\n"; /* keep string len same as CTIME_BEFORE_NL */ \ else \ { \ GTM_CTIME(time_ptr, &now); \ if (NULL == time_ptr) \ time_ptr = "***** ctime failed *****\n"; /* keep string len same as CTIME_BEFORE_NL */ \ else \ { \ memcpy(time_str, time_ptr, CTIME_BEFORE_NL + 2); \ time_ptr = time_str; \ } \ } \ } #define GTM_MKTIME(VAR, TIME) \ { \ DEFER_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ VAR = mktime(TIME); \ ENABLE_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ } #define GTM_GMTIME(VAR, TIME) \ { \ DEFER_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ VAR = gmtime(TIME); \ ENABLE_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ } #endif /* UNIX, VMS */ #define GTM_LOCALTIME(VAR, TIME) \ { \ DEFER_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ VAR = localtime(TIME); \ ENABLE_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ } /* CTIME collides with linux define in termios */ #define GTM_CTIME(VAR, TIME) \ { \ DEFER_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ VAR = ctime(TIME); \ ENABLE_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \ } #endif fis-gtm-V6.0-003/sr_port/gtm_unistd.h0000644000032200000250000000567712201176156016400 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_unistd.h - interlude to system header file. */ #ifndef GTM_UNISTDH #define GTM_UNISTDH #include #define CHDIR chdir #define CHOWN chown #define GETUID getuid #define GETEUID geteuid #define GETGID getgid #define GETEGID getegid #if defined(VMS) #define GTM_MAX_DIR_LEN (PATH_MAX + PATH_MAX) /* DEVICE + DIRECTORY */ #define GTM_VMS_STYLE_CWD 1 #define GTM_UNIX_STYLE_CWD 0 #define GETCWD(buffer, size, getcwd_res) \ (getcwd_res = getcwd(buffer, size, GTM_VMS_STYLE_CWD)) /* force VMS style always 'cos many other parts of GT.M always * do it the VMS way */ #else /* !VMS => UNIX */ #define GTM_MAX_DIR_LEN (PATH_MAX + 1) /* DIRECTORY + terminating '\0' */ #define GETCWD(buffer, size, getcwd_res) \ { \ DEFER_INTERRUPTS(INTRPT_IN_FUNC_WITH_MALLOC); \ getcwd_res = getcwd(buffer, size); \ ENABLE_INTERRUPTS(INTRPT_IN_FUNC_WITH_MALLOC); \ } #endif #ifndef UNICODE_SUPPORTED #define GETHOSTNAME(name,namelen,gethostname_res) \ (gethostname_res = gethostname(name, namelen)) #else #include "gtm_utf8.h" GBLREF boolean_t gtm_utf8_mode; #define GETHOSTNAME(name,namelen,gethostname_res) \ (gethostname_res = gethostname(name, namelen), \ gtm_utf8_mode ? gtm_utf8_trim_invalid_tail((unsigned char *)name, namelen) : 0, \ gethostname_res) #endif #define LINK link #define UNLINK unlink #define TTYNAME ttyname #define ACCESS access #define EXECL execl #define EXECV execv #define EXECVE execve #define TRUNCATE truncate #ifdef GTM_FD_TRACE /* Just like open and close were noted down in gtm_fcntl.h, note down all macros which we are redefining here and could * potentially have been conflictingly defined by the system header file "unistd.h". The system define will be used * in gtm_fd_trace.c within the implementation of the GT.M interlude function. Currently none of these functions (close, * pipe, dup, dup2) are defined by the system so it is not theoretically necessary but they could be defined in the future. */ # undef close /* in case this is already defined by */ # undef pipe /* in case this is already defined by */ # undef dup /* in case this is already defined by */ # undef dup2 /* in case this is already defined by */ # define close gtm_close # define pipe gtm_pipe1 /* gtm_pipe is already used so using pipe1 */ # define dup gtm_dup # define dup2 gtm_dup2 #endif int gtm_close(int fd); int gtm_pipe1(int pipefd[2]); int gtm_dup(int oldfd); int gtm_dup2(int oldfd, int newfd); #endif fis-gtm-V6.0-003/sr_port/gtm_utsname.h0000644000032200000250000000120712201176156016527 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gtm_utsname.h - interlude to system header file. */ #ifndef GTM_UTSNAMEH #define GTM_UTSNAMEH #include #define UNAME(name,uname_res) (uname_res = uname(name)) #endif fis-gtm-V6.0-003/sr_port/gtm_wake.h0000644000032200000250000000103712201176156016003 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GTM_WAKE_H__ #define __GTM_WAKE_H__ void gtm_wake(int4 *pidadr,char *prcnam); #endif fis-gtm-V6.0-003/sr_port/gtmctype.h0000644000032200000250000000075312201176156016045 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #define PRINTABLE(X) ((X) < 127 && (X) > 31) fis-gtm-V6.0-003/sr_port/gtmdbglvl.h0000644000032200000250000000610112201176156016164 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTMDBGLVL_H_INCLUDED #define GTMDBGLVL_H_INCLUDED /* Define GT.M debug levels. These values can be added together to turn on multiple features at the same time. Note that the cumulative value specified in the logical or environment variable must currently be specified in decimal. */ #define GDL_None 0x00000000 /* (000) No debugging is happening today */ #define GDL_Simple 0x00000001 /* (001) Regular assert checking, no special checks */ #define GDL_SmStats 0x00000002 /* (002) Print usage statistics at end of process */ #define GDL_SmTrace 0x00000004 /* (004) Trace each malloc/free (output to stderr) */ #define GDL_SmDumpTrace 0x00000008 /* (008) Dump malloc/free trace information on exit */ #define GDL_SmAllocVerf 0x00000010 /* (016) Perform verification of allocated storage chain for each call */ #define GDL_SmFreeVerf 0x00000020 /* (032) Perform simple verification of free storage chain for each call */ #define GDL_SmBackfill 0x00000040 /* (064) Backfill unused storage (cause exceptions if released storage is used */ #define GDL_SmChkAllocBackfill 0x00000080 /* (128) Verify backfilled storage in GDL_AllocVerf while verifying \ each individual queue entry */ #define GDL_SmChkFreeBackfill 0x00000100 /* (256) Verify backfilled storage in GDL_FreeVerf while verifying \ each individual queue entry */ #define GDL_SmStorHog 0x00000200 /* (512) Each piece of storage allocated is allocated in an element twice \ the desired size to provide glorious amounts of backfill for \ overrun checking. */ #define GDL_DumpOnStackOFlow 0x00000400 /* (1024) When get a stack overflow, generate a core */ #define GDL_ZSHOWDumpOnSignal 0x00000800 /* (2048) Don't supress GTM_FATAL file creation when get a signal */ #define GDL_PrintIndCacheStats 0x00001000 /* (4096) Print indirect cacheing stats */ #define GDL_PrintPieceStats 0x00002000 /* (8192) Print stats on $Piece cacheing (debug only) */ #define GDL_DebugCompiler 0x00004000 /* (16384) Turn on compiler debugging */ #define GDL_SmDump 0x00008000 /* (32768) Do full blown storage dump -- only useful in debug mode */ #define GDL_PrintEntryPoints 0x00010000 /* (65536) Print address of entry points when they are loaded/resolved */ #define GDL_PrintSockIntStats 0x00020000 /* (131072) Print Socket interrupt stats on exit */ #define GDL_SmInitAlloc 0x00040000 /* (262144) Initialize all storage allocated or deallocated with 0xdeadbeef */ #define GDL_PrintPipeIntStats 0x00080000 /* (524288) Print Pipe/Fifo(rm) interrupt stats on exit */ #define GDL_IgnoreAvailSpace 0x00100000 /* (1048576) Allow gdsfilext/mu_cre_file (UNIX) to ignore available space */ #endif fis-gtm-V6.0-003/sr_port/gtmimagename.h0000644000032200000250000000271312201176156016642 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTMIMAGENAME_DEF #define GTMIMAGENAME_DEF typedef struct { char *imageName; int imageNameLen; } gtmImageName; enum gtmImageTypes { #define IMAGE_TABLE_ENTRY(A,B) A, #include "gtmimagetable.h" #undef IMAGE_TABLE_ENTRY n_image_types }; #define GTMIMAGENAMETXT(x) gtmImageNames[x].imageNameLen, gtmImageNames[x].imageName GBLREF enum gtmImageTypes image_type; /* needed by IS_MUMPS_IMAGE and IS_GTM_IMAGE macros */ GBLREF boolean_t run_time; /* needed by IS_MCODE_RUNNING macro */ #define IS_MCODE_RUNNING (run_time) #define IS_DSE_IMAGE (DSE_IMAGE == image_type) #define IS_GTCM_GNP_SERVER_IMAGE (GTCM_GNP_SERVER_IMAGE == image_type) #define IS_GTMSECSHR_IMAGE (GTMSECSHR_IMAGE == image_type) #define IS_GTM_IMAGE IS_MUMPS_IMAGE #define IS_GTM_SVC_DAL_IMAGE (GTM_SVC_DAL_IMAGE == image_type) #define IS_LKE_IMAGE (LKE_IMAGE == image_type) #define IS_MUMPS_IMAGE (GTM_IMAGE == image_type) #define IS_MUPIP_IMAGE (MUPIP_IMAGE == image_type) #define IS_VALID_IMAGE (INVALID_IMAGE != image_type) #endif fis-gtm-V6.0-003/sr_port/gtmimagetable.h0000644000032200000250000000203012201176156017001 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* * IMAGE_TABLE_ENTRY(image_type, image-name) */ IMAGE_TABLE_ENTRY (INVALID_IMAGE, "INVALID_IMAGE") IMAGE_TABLE_ENTRY (GTM_IMAGE, "GT.M") IMAGE_TABLE_ENTRY (MUPIP_IMAGE, "MUPIP") IMAGE_TABLE_ENTRY (DSE_IMAGE, "DSE") IMAGE_TABLE_ENTRY (LKE_IMAGE, "LKE") IMAGE_TABLE_ENTRY (GTMSECSHR_IMAGE, "GTMSECSHR") IMAGE_TABLE_ENTRY (GTCM_SERVER_IMAGE, "GTCM_SERVER") IMAGE_TABLE_ENTRY (GTCM_GNP_SERVER_IMAGE, "GTCM_GNP_SERVER") IMAGE_TABLE_ENTRY (DBCERTIFY_IMAGE, "DBCERTIFY") IMAGE_TABLE_ENTRY (GTM_SVC_DAL_IMAGE, "GTM_SVC_DAL") fis-gtm-V6.0-003/sr_port/gtmmsg.h0000644000032200000250000000303712201176156015505 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTMMSG_H_INCLUDED #define GTMMSG_H_INCLUDED #ifdef VMS void gtm_getmsg(uint4 msgnum, mstr *msgbuf); void gtm_putmsg(int4 msgid, ...); #define gtm_putmsg_csa gtm_putmsg #elif defined(UNIX) void gtm_getmsg(int4 msgnum, mstr *msgbuf); void gtm_putmsg(int argcnt, ...); void gtm_putmsg_csa(void *, int argcnt, ...); /* Use CSA_ARG(CSA) for portability */ void gtm_putmsg_noflush(int argcnt, ...); void gtm_putmsg_noflush_csa(void *, int argcnt, ...); # define GET_MSG_IDX(MSG_ID, CTL, IDX) \ { \ assert(NULL != CTL); \ assert((MSG_ID && FACMASK(CTL->facnum)) && (MSGMASK(MSG_ID, CTL->facnum) <= CTL->msg_cnt)); \ IDX = MSGMASK(MSG_ID, CTL->facnum) - 1; \ } /* Given a pointer to ctl array (merrors_ctl, gdeerrors_ctl, etc.) and a msg_id, get the structure corresponding to that msg_id */ # define GET_MSG_INFO(MSG_ID, CTL, MSG_INFO) \ { \ int idx; \ \ GET_MSG_IDX(MSG_ID, CTL, idx); \ MSG_INFO = CTL->fst_msg + idx; \ } #else # error Unsupported platform #endif #endif /* GTMMSG_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/gtmrecv_ch.c0000644000032200000250000000163112201176156016321 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "error.h" error_def(ERR_ASSERT); error_def(ERR_CTRLC); error_def(ERR_FORCEDHALT); error_def(ERR_GTMASSERT); error_def(ERR_GTMASSERT2); error_def(ERR_GTMCHECK); error_def(ERR_MEMORY); error_def(ERR_OUTOFSPACE); error_def(ERR_STACKOFLOW); error_def(ERR_VMSMEMORY); CONDITION_HANDLER(gtmrecv_ch) { START_CH; if (!(IS_GTM_ERROR(SIGNAL)) || DUMPABLE || SEVERITY == ERROR) { NEXTCH; } /* warning, info, or success */ CONTINUE; } fis-gtm-V6.0-003/sr_port/gtmrecv_changelog.c0000644000032200000250000001142012201176156017653 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_time.h" #include "gtm_string.h" #include "gtm_inet.h" #include #ifdef VMS #include /* Required for gtmrecv.h */ #endif #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gtmrecv.h" #include "repl_dbg.h" #include "repl_shutdcode.h" #include "repl_sem.h" #include "util.h" #include "repl_log.h" #include "gtm_fcntl.h" #include "gtmio.h" #include "repl_sp.h" GBLREF recvpool_addrs recvpool; GBLREF gtmrecv_options_t gtmrecv_options; error_def(ERR_REPLLOGOPN); int gtmrecv_changelog(void) { uint4 changelog_desired = 0, changelog_accepted = 0; int log_fd = 0; /*used to indicate whether the new specified log file is writable*/ int close_status = 0; /*used to indicate if log file is successfully closed*/ char* err_code; int save_errno; /* Grab the recvpool jnlpool option write lock */ if (0 > grab_sem(RECV, RECV_SERV_OPTIONS_SEM)) { util_out_print("Error grabbing recvpool option write lock. Could not initiate change log", TRUE); return (ABNORMAL_SHUTDOWN); } if (0 != recvpool.gtmrecv_local->changelog || 0 != recvpool.upd_proc_local->changelog) { util_out_print("Change log is already in progress. Not initiating change in log file or log interval", TRUE); rel_sem(RECV, RECV_SERV_OPTIONS_SEM); return (ABNORMAL_SHUTDOWN); } if ('\0' != gtmrecv_options.log_file[0]) /* trigger change in log file (for both receiver and update process) */ { changelog_desired |= REPLIC_CHANGE_LOGFILE; if (0 != strcmp(recvpool.gtmrecv_local->log_file, gtmrecv_options.log_file)) { #ifdef UNIX /*check if the new log file is writable*/ OPENFILE3(gtmrecv_options.log_file, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, log_fd); if (log_fd < 0) { save_errno = ERRNO; err_code = STRERROR(save_errno); gtm_putmsg(VARLSTCNT(8) ERR_REPLLOGOPN, 6, LEN_AND_STR(gtmrecv_options.log_file), LEN_AND_STR(err_code), LEN_AND_STR(NULL_DEVICE)); } else { CLOSEFILE_IF_OPEN(log_fd, close_status); assert(close_status==0); changelog_accepted |= REPLIC_CHANGE_LOGFILE; strcpy(recvpool.gtmrecv_local->log_file, gtmrecv_options.log_file); util_out_print("Change log initiated with file !AD", TRUE, LEN_AND_STR(gtmrecv_options.log_file)); } #elif defined(VMS) changelog_accepted |= REPLIC_CHANGE_LOGFILE; strcpy(recvpool.gtmrecv_local->log_file, gtmrecv_options.log_file); util_out_print("Change log initiated with file !AD", TRUE, LEN_AND_STR(gtmrecv_options.log_file)); #endif } else util_out_print("Log file is already !AD. Not initiating change in log file", TRUE, LEN_AND_STR(gtmrecv_options.log_file)); } if (0 != gtmrecv_options.rcvr_log_interval) /* trigger change in receiver log interval */ { changelog_desired |= REPLIC_CHANGE_LOGINTERVAL; if (gtmrecv_options.rcvr_log_interval != recvpool.gtmrecv_local->log_interval) { changelog_accepted |= REPLIC_CHANGE_LOGINTERVAL; recvpool.gtmrecv_local->log_interval = gtmrecv_options.rcvr_log_interval; util_out_print("Change initiated with receiver log interval !UL", TRUE, gtmrecv_options.rcvr_log_interval); } else util_out_print("Receiver log interval is already !UL. Not initiating change in log interval", TRUE, gtmrecv_options.rcvr_log_interval); } if (0 != gtmrecv_options.upd_log_interval) /* trigger change in update process log interval */ { changelog_desired |= REPLIC_CHANGE_UPD_LOGINTERVAL; if (gtmrecv_options.upd_log_interval != recvpool.upd_proc_local->log_interval) { changelog_accepted |= REPLIC_CHANGE_UPD_LOGINTERVAL; recvpool.upd_proc_local->log_interval = gtmrecv_options.upd_log_interval; util_out_print("Change initiated with update process log interval !UL", TRUE, gtmrecv_options.upd_log_interval); } else util_out_print("Update process log interval is already !UL. Not initiating change in log interval", TRUE, gtmrecv_options.upd_log_interval); } if (0 != changelog_accepted) recvpool.gtmrecv_local->changelog = changelog_accepted; else util_out_print("No change to log file or log interval", TRUE); rel_sem(RECV, RECV_SERV_OPTIONS_SEM); return ((0 != changelog_accepted && changelog_accepted == changelog_desired) ? NORMAL_SHUTDOWN : ABNORMAL_SHUTDOWN); } fis-gtm-V6.0-003/sr_port/gtmrecv_checkhealth.c0000644000032200000250000001261112201176156020172 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_time.h" #include #include "gtm_inet.h" #include "gtm_string.h" #ifdef UNIX #include #endif #ifdef VMS #include /* Required for gtmrecv.h */ #endif #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gtmrecv.h" #include "repl_dbg.h" #include "gtm_stdio.h" #include "repl_shutdcode.h" #include "repl_sem.h" #include "repl_sp.h" #include "repl_log.h" #include "is_proc_alive.h" GBLREF recvpool_addrs recvpool; GBLREF gtmrecv_options_t gtmrecv_options; int is_srv_alive(int srv_type) { int status, semval; boolean_t start_wait_logged; uint4 srv_pid; boolean_t srv_alive; srv_pid = (GTMRECV == srv_type) ? recvpool.gtmrecv_local->recv_serv_pid : recvpool.upd_proc_local->upd_proc_pid; if (0 < srv_pid) { if (srv_alive = is_proc_alive(srv_pid, 0)) semval = get_sem_info(RECV, (GTMRECV == srv_type) ? RECV_SERV_COUNT_SEM : UPD_PROC_COUNT_SEM, SEM_INFO_VAL); if (srv_alive && 1 == semval) status = SRV_ALIVE; else if (!srv_alive || 0 == semval) status = SRV_DEAD; else status = SRV_ERR; } else status = SRV_DEAD; return (status); } int is_updproc_alive(void) { return (is_srv_alive(UPDPROC)); } int is_recv_srv_alive(void) { return (is_srv_alive(GTMRECV)); } int gtmrecv_checkhealth(void) { int rcv_status, upd_status, helper_status, save_errno; uint4 gtmrecv_pid, updproc_pid, updproc_pid_prev, helper_pid; boolean_t helper_alive; upd_helper_ctl_ptr_t upd_helper_ctl; upd_helper_entry_ptr_t helper, helper_top; recvpool_user helper_type; /* Grab the recvpool option write lock */ if (0 > grab_sem(RECV, RECV_SERV_OPTIONS_SEM)) { UNIX_ONLY(save_errno = errno); repl_log(stderr, FALSE, TRUE, "Error grabbing recvpool option write lock : %s. Could not check health of Receiver" "Server/Update Process\n", UNIX_ONLY(STRERROR(save_errno)) VMS_ONLY(REPL_SEM_ERROR)); return (((SRV_ERR << 2) | SRV_ERR) + NORMAL_SHUTDOWN); } gtmrecv_pid = recvpool.gtmrecv_local->recv_serv_pid; updproc_pid = recvpool.upd_proc_local->upd_proc_pid; updproc_pid_prev = recvpool.upd_proc_local->upd_proc_pid_prev; REPL_DPRINT1("Checking health of Receiver Server/Update Process\n"); rcv_status = is_recv_srv_alive(); upd_status = is_updproc_alive(); switch(rcv_status) { case SRV_ALIVE: repl_log(stderr, FALSE, TRUE, FORMAT_STR, gtmrecv_pid, "Receiver server", ""); break; case SRV_DEAD: repl_log(stderr, FALSE, TRUE, FORMAT_STR, gtmrecv_pid, "Receiver server", " NOT"); if (0 == gtmrecv_pid) { if (NO_SHUTDOWN == recvpool.gtmrecv_local->shutdown) repl_log(stderr, FALSE, TRUE, "Receiver Server crashed during receive pool initialization\n"); else repl_log(stderr, FALSE, TRUE, "Receiver server crashed during shutdown\n"); } break; case SRV_ERR: repl_log(stderr, FALSE, TRUE, "Error finding health of receiver server\n"); break; } switch(upd_status) { case SRV_ALIVE: repl_log(stderr, FALSE, TRUE, FORMAT_STR, updproc_pid, "Update process", ""); break; case SRV_DEAD: repl_log(stderr, FALSE, TRUE, FORMAT_STR, updproc_pid ? updproc_pid : updproc_pid_prev, "Update process", " NOT"); if (0 == updproc_pid) { if (NO_SHUTDOWN == recvpool.upd_proc_local->upd_proc_shutdown) repl_log(stderr, FALSE, TRUE, "Update Process crashed during initialization\n"); else repl_log(stderr, FALSE, TRUE, "Update Process crashed during shutdown\n"); } break; case SRV_ERR: repl_log(stdout, FALSE, TRUE, "Error in finding health of update process\n"); break; } helper_status = SRV_ALIVE; if (gtmrecv_options.helpers) { upd_helper_ctl = recvpool.upd_helper_ctl; for (helper = upd_helper_ctl->helper_list, helper_top = helper + MAX_UPD_HELPERS; helper < helper_top; helper++) { if (0 != (helper_pid = helper->helper_pid_prev)) { helper_type = (recvpool_user)helper->helper_type; helper_alive = is_proc_alive(helper_pid, 0); if (helper_alive && 0 == helper->helper_pid) /* process has vacated its slot, but the rcvr hasn't */ helper_alive = FALSE; /* salvaged it yet. Unix zombies are alive,* er, half dead */ helper_status = (SRV_ALIVE == helper_status && helper_alive) ? SRV_ALIVE : SRV_DEAD; repl_log(stderr, FALSE, TRUE, FORMAT_STR, helper_pid, (UPD_HELPER_READER == helper_type) ? "Helper reader" : "Helper writer", helper_alive ? "" : " NOT"); } } if (SRV_DEAD == helper_status) { /* indicate to the receiver that it has to reap helpers */ upd_helper_ctl->reap_helpers = HELPER_REAP_NOWAIT; while (HELPER_REAP_NONE != upd_helper_ctl->reap_helpers && SRV_ALIVE == is_recv_srv_alive()) SHORT_SLEEP(GTMRECV_WAIT_FOR_UPD_SHUTDOWN); upd_helper_ctl->reap_helpers = HELPER_REAP_NONE; /* just in case recvr died */ } } rel_sem(RECV, RECV_SERV_OPTIONS_SEM); return ((rcv_status | (upd_status << 2) | (helper_status << 4)) + NORMAL_SHUTDOWN); } fis-gtm-V6.0-003/sr_port/gtmrecv_comm_init.c0000644000032200000250000000713612201176156017713 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_socket.h" #include "gtm_netdb.h" /* for NI_MAXSERV and AI_V4MAPPED */ #include "gtm_ipv6.h" #include "gtm_inet.h" #include "gtm_fcntl.h" #include #include #include "gtm_unistd.h" #ifdef VMS #include /* Required for gtmrecv.h */ #endif #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gtmrecv.h" #include "repl_sp.h" #include "gtmio.h" #include "util.h" #include "repl_log.h" GBLDEF int gtmrecv_listen_sock_fd = FD_INVALID; error_def(ERR_GETADDRINFO); error_def(ERR_REPLCOMM); error_def(ERR_TEXT); /* Initialize communication stuff */ int gtmrecv_comm_init(in_port_t port) { struct addrinfo *ai_ptr = NULL, hints; const int enable_reuseaddr = 1; struct linger disable_linger = {0, 0}; int rc; int errcode; char port_buffer[NI_MAXSERV]; int port_buffer_len; int temp_sock_fd; int af; if (FD_INVALID != gtmrecv_listen_sock_fd) /* Initialization done already */ return (0); /* Create the socket used for communicating with primary */ af = ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET); if (FD_INVALID == (temp_sock_fd = socket(af, SOCK_STREAM, IPPROTO_TCP))) { af = AF_INET; if (FD_INVALID == (temp_sock_fd = socket(af, SOCK_STREAM, IPPROTO_TCP))) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with receiver server socket create"), ERRNO); return (-1); } } /* Make it known to the world that you are ready for a Source Server */ SERVER_HINTS(hints, af); SPRINTF(port_buffer, "%hu", port); if (0 != (errcode = getaddrinfo(NULL, port_buffer, &hints, &ai_ptr))) { CLOSEFILE(temp_sock_fd, rc); RTS_ERROR_ADDRINFO_CTX(NULL, ERR_GETADDRINFO, errcode, "FAILED in obtaining IP address on receiver server."); return -1; } gtmrecv_listen_sock_fd = temp_sock_fd; if (0 > setsockopt(gtmrecv_listen_sock_fd, SOL_SOCKET, SO_LINGER, (const void *)&disable_linger, SIZEOF(disable_linger))) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with receiver server listen socket disable linger"), ERRNO); if (0 > setsockopt(gtmrecv_listen_sock_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&enable_reuseaddr, SIZEOF(enable_reuseaddr))) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with receiver server listen socket enable reuseaddr"), ERRNO); } if (0 > BIND(gtmrecv_listen_sock_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen)) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not bind local address"), ERRNO); CLOSEFILE_RESET(gtmrecv_listen_sock_fd, rc); /* resets "gtmrecv_listen_sock_fd" to FD_INVALID */ return (-1); } if (0 > listen(gtmrecv_listen_sock_fd, 5)) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not listen"), ERRNO); CLOSEFILE_RESET(gtmrecv_listen_sock_fd, rc); /* resets "gtmrecv_listen_sock_fd" to FD_INVALID */ return (-1); } return (0); } fis-gtm-V6.0-003/sr_port/gtmrecv_end_helpers.c0000644000032200000250000000356312201176156020225 0ustar librarygtc/**************************************************************** * * * Copyright 2005 Fidelity Information Services, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #ifdef UNIX #include #elif defined(VMS) #include /* Required for gtmrecv.h */ #endif #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "iosp.h" #include "repl_shutdcode.h" #include "gtmrecv.h" #include "is_proc_alive.h" #include "eintr_wrappers.h" #include "repl_log.h" GBLREF recvpool_addrs recvpool; int gtmrecv_end_helpers(boolean_t is_rcvr_srvr) { /* Set flag in recvpool telling the receiver server to stop all reader and writer helpers. * Wait for receiver server to complete the processs - all processes shut down, or some error occurred */ upd_helper_ctl_ptr_t upd_helper_ctl; upd_helper_entry_ptr_t helper, helper_top; repl_log(stdout, TRUE, TRUE, "Initiating shut down of Helpers\n"); upd_helper_ctl = recvpool.upd_helper_ctl; for (helper = upd_helper_ctl->helper_list, helper_top = helper + MAX_UPD_HELPERS; helper < helper_top; helper++) helper->helper_shutdown = SHUTDOWN; /* indicate to the helper to shut down */ if (is_rcvr_srvr) gtmrecv_reap_helpers(TRUE); else { upd_helper_ctl->reap_helpers = HELPER_REAP_WAIT; while (HELPER_REAP_NONE != upd_helper_ctl->reap_helpers && SRV_ALIVE == is_recv_srv_alive()) SHORT_SLEEP(GTMRECV_WAIT_FOR_UPD_SHUTDOWN); upd_helper_ctl->reap_helpers = HELPER_REAP_NONE; } return NORMAL_SHUTDOWN; } fis-gtm-V6.0-003/sr_port/gtmrecv_exit.c0000644000032200000250000000175712201176156016711 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdlib.h" /* for exit() */ #ifdef VMS #include #include #endif #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "iosp.h" #include "repl_shutdcode.h" #include "gtmrecv.h" #include "repl_log.h" #include "repl_dbg.h" void gtmrecv_exit(int exit_status) { error_def(ERR_REPLEXITERR); #ifdef VMS sys$exit((0 == exit_status) ? SS$_NORMAL : ERR_REPLEXITERR); #else exit(exit_status); #endif } fis-gtm-V6.0-003/sr_port/gtmrecv_get_opt.c0000644000032200000250000002275412201176156017401 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_limits.h" #include "gtm_stdlib.h" #include "gtm_string.h" #include "gtm_unistd.h" #include "gtm_ctype.h" #include "gtm_inet.h" #include #ifdef VMS #include /* Required for gtmrecv.h */ #endif #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gtmrecv.h" #include "cli.h" #include "gtm_stdio.h" #include "util.h" #include "repl_log.h" #ifdef UNIX #include "gtm_zlib.h" #endif GBLREF gtmrecv_options_t gtmrecv_options; int gtmrecv_get_opt(void) { boolean_t log, log_interval_specified; unsigned short log_file_len, filter_cmd_len, instfilename_len, instname_len; boolean_t buffsize_status; boolean_t filter; int status; unsigned short statslog_val_len; char statslog_val[4]; /* "ON" or "OFF" */ uint4 n_readers, n_helpers; boolean_t cmplvl_status, autorollback; gtmrecv_options.start = (CLI_PRESENT == cli_present("START")); gtmrecv_options.shut_down = (CLI_PRESENT == cli_present("SHUTDOWN")); gtmrecv_options.checkhealth = (CLI_PRESENT == cli_present("CHECKHEALTH")); gtmrecv_options.statslog = (CLI_PRESENT == cli_present("STATSLOG")); gtmrecv_options.showbacklog = (CLI_PRESENT == cli_present("SHOWBACKLOG")); gtmrecv_options.changelog = (CLI_PRESENT == cli_present("CHANGELOG")); gtmrecv_options.updateonly = (CLI_PRESENT == cli_present("UPDATEONLY")); gtmrecv_options.updateresync = (CLI_PRESENT == cli_present("UPDATERESYNC")); # ifdef UNIX gtmrecv_options.reuse_specified = (CLI_PRESENT == cli_present("REUSE")); gtmrecv_options.resume_specified = (CLI_PRESENT == cli_present("RESUME")); gtmrecv_options.initialize_specified = (CLI_PRESENT == cli_present("INITIALIZE")); /* -UPDATERESYNC= and optional -REUSE= is supported only in Unix */ if (gtmrecv_options.updateresync) { instfilename_len = SIZEOF(gtmrecv_options.updresync_instfilename) - 1; /* keep 1 byte for trailing NULL */ /* Treat -UPDATERESYNC (with no value) as if -UPDATERESYNC="" was specified */ if (!cli_get_str("UPDATERESYNC", gtmrecv_options.updresync_instfilename, &instfilename_len)) { instfilename_len = 0; if (gtmrecv_options.reuse_specified) { util_out_print("Error: REUSE qualifier not allowed if UPDATERESYNC qualifier has no value", TRUE); return (-1); } } else if (gtmrecv_options.reuse_specified) { instname_len = SIZEOF(gtmrecv_options.reuse_instname) - 1; /* keep 1 byte for trailing NULL */ if (!cli_get_str("REUSE", gtmrecv_options.reuse_instname, &instname_len)) { util_out_print("Error parsing REUSE qualifier", TRUE); return (-1); } else { assert(SIZEOF(gtmrecv_options.reuse_instname) > instname_len); gtmrecv_options.reuse_instname[instname_len] = '\0'; } } assert(SIZEOF(gtmrecv_options.updresync_instfilename) > instfilename_len); gtmrecv_options.updresync_instfilename[instfilename_len] = '\0'; if (gtmrecv_options.resume_specified) { if (!cli_get_int("RESUME", >mrecv_options.resume_strm_num)) { util_out_print("Error parsing RESUME qualifier", TRUE); return (-1); } if ((0 >= gtmrecv_options.resume_strm_num) || (MAX_SUPPL_STRMS <= gtmrecv_options.resume_strm_num)) { util_out_print("RESUME qualifier should specify a stream number between 1 and 15 (both inclusive)", TRUE); return (-1); } } } gtmrecv_options.noresync = (CLI_PRESENT == cli_present("NORESYNC")); # endif gtmrecv_options.helpers = (CLI_PRESENT == cli_present("HELPERS")); gtmrecv_options.listen_port = 0; /* invalid port; indicates listenport not specified */ if (gtmrecv_options.start && CLI_PRESENT == cli_present("LISTENPORT")) { if (!cli_get_int("LISTENPORT", >mrecv_options.listen_port)) { util_out_print("Error parsing LISTENPORT qualifier", TRUE); return (-1); } if (buffsize_status = (CLI_PRESENT == cli_present("BUFFSIZE"))) { if (!cli_get_int("BUFFSIZE", >mrecv_options.buffsize)) { util_out_print("Error parsing BUFFSIZE qualifier", TRUE); return (-1); } if (MIN_RECVPOOL_SIZE > gtmrecv_options.buffsize) gtmrecv_options.buffsize = MIN_RECVPOOL_SIZE; } else gtmrecv_options.buffsize = DEFAULT_RECVPOOL_SIZE; # ifdef UNIX /* Check if -autorollback is specified (default is -noautorollback) */ autorollback = cli_present("AUTOROLLBACK"); gtmrecv_options.autorollback = autorollback ? (CLI_NEGATED != autorollback) : FALSE; if (gtmrecv_options.autorollback) gtmrecv_options.autorollback_verbose = cli_present("AUTOROLLBACK.VERBOSE"); /* Check if compression level is specified */ if (cmplvl_status = (CLI_PRESENT == cli_present("CMPLVL"))) { if (!cli_get_int("CMPLVL", >mrecv_options.cmplvl)) { util_out_print("Error parsing CMPLVL qualifier", TRUE); return(-1); } if (GTM_CMPLVL_OUT_OF_RANGE(gtmrecv_options.cmplvl)) gtmrecv_options.cmplvl = ZLIB_CMPLVL_MIN; /* no compression in this case */ /* CMPLVL qualifier should override any value specified in the environment variable gtm_zlib_cmp_level */ gtm_zlib_cmp_level = gtmrecv_options.cmplvl; } else gtmrecv_options.cmplvl = ZLIB_CMPLVL_MIN; /* no compression in this case */ # endif /* Round up or down buffsize */ if (filter = (CLI_PRESENT == cli_present("FILTER"))) { filter_cmd_len = MAX_FILTER_CMD_LEN; if (!cli_get_str("FILTER", gtmrecv_options.filter_cmd, &filter_cmd_len)) { util_out_print("Error parsing FILTER qualifier", TRUE); return (-1); } } else gtmrecv_options.filter_cmd[0] = '\0'; gtmrecv_options.stopsourcefilter = (CLI_PRESENT == cli_present("STOPSOURCEFILTER")); } if ((gtmrecv_options.start && 0 != gtmrecv_options.listen_port) || gtmrecv_options.statslog || gtmrecv_options.changelog) { log = (CLI_PRESENT == cli_present("LOG")); log_interval_specified = (CLI_PRESENT == cli_present("LOG_INTERVAL")); if (log) { log_file_len = MAX_FN_LEN + 1; if (!cli_get_str("LOG", gtmrecv_options.log_file, &log_file_len)) { util_out_print("Error parsing LOG qualifier", TRUE); return (-1); } } else gtmrecv_options.log_file[0] = '\0'; gtmrecv_options.rcvr_log_interval = gtmrecv_options.upd_log_interval = 0; if (log_interval_specified && 0 == cli_parse_two_numbers("LOG_INTERVAL", GTMRECV_LOGINTERVAL_DELIM, >mrecv_options.rcvr_log_interval, >mrecv_options.upd_log_interval)) return (-1); if (gtmrecv_options.start) { if (0 == gtmrecv_options.rcvr_log_interval) gtmrecv_options.rcvr_log_interval = LOGTRNUM_INTERVAL; if (0 == gtmrecv_options.upd_log_interval) gtmrecv_options.upd_log_interval = LOGTRNUM_INTERVAL; } /* For changelog, interval == 0 implies don't change log interval already established */ /* We ignore interval specification for statslog, Vinaya 2005/02/07 */ } if (gtmrecv_options.shut_down) { if (CLI_PRESENT == (status = cli_present("TIMEOUT"))) { if (!cli_get_int("TIMEOUT", >mrecv_options.shutdown_time)) { util_out_print("Error parsing TIMEOUT qualifier", TRUE); return (-1); } if (DEFAULT_SHUTDOWN_TIMEOUT < gtmrecv_options.shutdown_time || 0 > gtmrecv_options.shutdown_time) { gtmrecv_options.shutdown_time = DEFAULT_SHUTDOWN_TIMEOUT; util_out_print("shutdown TIMEOUT changed to !UL", TRUE, gtmrecv_options.shutdown_time); } } else if (CLI_NEGATED == status) gtmrecv_options.shutdown_time = -1; else /* TIMEOUT not specified */ gtmrecv_options.shutdown_time = DEFAULT_SHUTDOWN_TIMEOUT; } if (gtmrecv_options.statslog) { statslog_val_len = 4; /* max(strlen("ON"), strlen("OFF")) + 1 */ if (!cli_get_str("STATSLOG", statslog_val, &statslog_val_len)) { util_out_print("Error parsing STATSLOG qualifier", TRUE); return (-1); } #ifdef UNIX cli_strupper(statslog_val); #endif if (0 == STRCMP(statslog_val, "ON")) gtmrecv_options.statslog = TRUE; else if (0 == STRCMP(statslog_val, "OFF")) gtmrecv_options.statslog = FALSE; else { util_out_print("Invalid value for STATSLOG qualifier, should be either ON or OFF", TRUE); return (-1); } } gtmrecv_options.n_readers = gtmrecv_options.n_writers = 0; if (gtmrecv_options.helpers && gtmrecv_options.start) { /* parse the helpers qualifier to find out how many readers and writes have to be started */ if (0 == (status = cli_parse_two_numbers("HELPERS", UPD_HELPERS_DELIM, &n_helpers, &n_readers))) return (-1); if (!(status & CLI_2NUM_FIRST_SPECIFIED)) n_helpers = DEFAULT_UPD_HELPERS; if (MIN_UPD_HELPERS > n_helpers || MAX_UPD_HELPERS < n_helpers) { util_out_print("Invalid number of helpers; must be in the range [!UL,!UL]", TRUE, MIN_UPD_HELPERS, MAX_UPD_HELPERS); return (-1); } if (!(status & CLI_2NUM_SECOND_SPECIFIED)) n_readers = (int)(n_helpers * ((float)DEFAULT_UPD_HELP_READERS)/DEFAULT_UPD_HELPERS); /* may round down */ if (n_readers > n_helpers) { n_readers = n_helpers; util_out_print("Number of readers exceeds number of helpers, reducing number of readers to number of " "helpers", TRUE); } gtmrecv_options.n_readers = n_readers; gtmrecv_options.n_writers = n_helpers - n_readers; } return (0); } fis-gtm-V6.0-003/sr_port/gtmrecv_helpers_init.c0000644000032200000250000002036612201176156020422 0ustar librarygtc/**************************************************************** * * * Copyright 2005, 2013 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #ifdef UNIX #include #include "gtm_unistd.h" #include "fork_init.h" #include #elif defined(VMS) #include /* Required for gtmrecv.h */ #endif #include #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "iosp.h" #include "repl_shutdcode.h" #include "gtmrecv.h" #include "repl_dbg.h" #include "repl_errno.h" #include "gtm_stdio.h" #include "repl_sem.h" #include "io.h" #include "is_proc_alive.h" #include "gtmmsg.h" #include "trans_log_name.h" #include "repl_log.h" #include "eintr_wrappers.h" #include "memcoherency.h" #include "getjobnum.h" #define UPDHELPER_CMD_MAXLEN 1024 #define UPDHELPER_CMD "$gtm_dist/mupip" #define UPDHELPER_CMD_FILE "mupip" #define UPDHELPER_CMD_ARG1 "replicate" #define UPDHELPER_CMD_ARG2 "-updhelper" #define UPDHELPER_READER_CMD_ARG3 "-reader" #define UPDHELPER_WRITER_CMD_ARG3 "-writer" #define UPDHELPER_READER_CMD_STR "REPLICATE/UPDHELPER/READER" #define UPDHELPER_WRITER_CMD_STR "REPLICATE/UPDHELPER/WRITER" #define UPDHELPER_MBX_PREFIX "GTMH" /* first three must be GTM, and only character left for uniqueness */ /* U for update process, R for receiver, S for source, H for helper */ GBLREF recvpool_addrs recvpool; GBLREF FILE *gtmrecv_log_fp; GBLREF uint4 process_id; error_def(ERR_LOGTOOLONG); error_def(ERR_RECVPOOLSETUP); error_def(ERR_TEXT); static int helper_init(upd_helper_entry_ptr_t helper, recvpool_user helper_type) { int save_errno, save_shutdown; char helper_cmd[UPDHELPER_CMD_MAXLEN]; int status; int4 i4status; mstr helper_log_cmd, helper_trans_cmd; upd_helper_ctl_ptr_t upd_helper_ctl; #ifdef UNIX pid_t helper_pid, waitpid_res; #elif defined(VMS) uint4 helper_pid, cmd_channel; char mbx_suffix[2 + 1]; /* hex representation of numbers 0 through MAX_UPD_HELPERS-1, +1 for '\0' */ $DESCRIPTOR(cmd_desc_reader, UPDHELPER_READER_CMD_STR); $DESCRIPTOR(cmd_desc_writer, UPDHELPER_WRITER_CMD_STR); #endif upd_helper_ctl = recvpool.upd_helper_ctl; save_shutdown = helper->helper_shutdown; helper->helper_shutdown = NO_SHUTDOWN; #ifdef UNIX FORK(helper_pid); /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */ if (0 > helper_pid) { save_errno = errno; helper->helper_shutdown = save_shutdown; gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, LEN_AND_LIT("Could not fork update process"), save_errno); repl_errno = EREPL_UPDSTART_FORK; return UPDPROC_START_ERR; } if (0 == helper_pid) { /* helper */ getjobnum(); helper->helper_pid_prev = process_id; /* identify owner of slot */ helper_log_cmd.len = STR_LIT_LEN(UPDHELPER_CMD); helper_log_cmd.addr = UPDHELPER_CMD; if (SS_NORMAL != (i4status = TRANS_LOG_NAME(&helper_log_cmd, &helper_trans_cmd, helper_cmd, SIZEOF(helper_cmd), dont_sendmsg_on_log2long))) { helper->helper_shutdown = save_shutdown; gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, LEN_AND_LIT("Could not find path of Helper Process. Check value of $gtm_dist")); if (SS_LOG2LONG == i4status) gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_LOGTOOLONG, 3, LEN_AND_LIT(UPDHELPER_CMD), SIZEOF(helper_cmd) - 1); repl_errno = EREPL_UPDSTART_BADPATH; return UPDPROC_START_ERR; } helper_cmd[helper_trans_cmd.len] = '\0'; if (-1 == EXECL(helper_cmd, helper_cmd, UPDHELPER_CMD_ARG1, UPDHELPER_CMD_ARG2, (UPD_HELPER_READER == helper_type) ? UPDHELPER_READER_CMD_ARG3 : UPDHELPER_WRITER_CMD_ARG3, NULL)) { save_errno = errno; helper->helper_shutdown = save_shutdown; gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, LEN_AND_LIT("Could not exec Helper Process"), save_errno); repl_errno = EREPL_UPDSTART_EXEC; return UPDPROC_START_ERR; } } #elif defined(VMS) /* Create detached server and write startup commands to it */ i2hex(helper - upd_helper_ctl->helper_list, LIT_AND_LEN(mbx_suffix)); mbx_suffix[SIZEOF(mbx_suffix) - 1] = '\0'; /* A mailbox is created per helper, and the mailbox name is assigned to a logical. This logical will persist until the * helper terminates. So, we need to assign a unique logical per helper. Hence the suffix. */ if (SS_NORMAL != (status = repl_create_server((UPD_HELPER_READER == helper_type) ? &cmd_desc_reader : &cmd_desc_writer, UPDHELPER_MBX_PREFIX, mbx_suffix, &cmd_channel, &helper->helper_pid_prev, ERR_RECVPOOLSETUP))) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, LEN_AND_LIT("Unable to spawn Helper process"), status); helper->helper_shutdown = save_shutdown; repl_errno = EREPL_UPDSTART_FORK; return UPDPROC_START_ERR; } helper_pid = helper->helper_pid_prev; #endif /* Wait for helper to startup */ while (helper_pid != helper->helper_pid && is_proc_alive(helper_pid, 0)) { SHORT_SLEEP(GTMRECV_WAIT_FOR_SRV_START); UNIX_ONLY(WAITPID(helper_pid, &status, WNOHANG, waitpid_res);) /* Release defunct helper process if dead */ } /* The helper has now gone far enough in the initialization, or died before initialization. Consider startup completed. */ #if defined(VMS) /* Deassign the send-cmd mailbox channel */ if (SS_NORMAL != (status = sys$dassgn(cmd_channel))) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to close upd-send-cmd mbox channel"), status); helper->helper_shutdown = save_shutdown; repl_errno = EREPL_UPDSTART_BADPATH; /* Just to make an auto-shutdown */ return UPDPROC_START_ERR; } #endif repl_log(gtmrecv_log_fp, TRUE, TRUE, "Helper %s started. PID %d [0x%X]\n", (UPD_HELPER_READER == helper_type) ? "reader" : "writer", helper_pid, helper_pid); return UPDPROC_STARTED; } int gtmrecv_helpers_init(int n_readers, int n_writers) { /* Receiver server interface to start n_readers and n_writers helper processes */ upd_helper_ctl_ptr_t upd_helper_ctl; upd_helper_entry_ptr_t helper, helper_top; int reader_count, writer_count, error_count, avail_slots, status; assert(0 != n_readers || 0 != n_writers); upd_helper_ctl = recvpool.upd_helper_ctl; for (avail_slots = 0, helper = upd_helper_ctl->helper_list, helper_top = helper + MAX_UPD_HELPERS; helper < helper_top; helper++) { if (0 == helper->helper_pid) avail_slots++; } if (n_readers + n_writers > avail_slots) { /* adjust reader/writer count for available slots according to the percentage specified by user */ n_writers = (int)(((float)n_writers/(n_readers + n_writers)) * (float)avail_slots); /* may round down */ n_readers = avail_slots - n_writers; /* preference to readers, writer count may round down */ } /* Start helpers, readers first */ for (helper = upd_helper_ctl->helper_list, helper_top = helper + MAX_UPD_HELPERS, reader_count = 0, writer_count = 0, error_count = 0; (reader_count + writer_count + error_count) < (n_readers + n_writers); ) { for (; 0 != helper->helper_pid && helper < helper_top; helper++) /* find next vacant slot */ ; if (helper == helper_top) GTMASSERT; status = helper_init(helper, ((reader_count + error_count) < n_readers) ? UPD_HELPER_READER : UPD_HELPER_WRITER); if (UPDPROC_STARTED == status) { if ((reader_count + error_count) < n_readers) reader_count++; else writer_count++; } else /* UPDPROC_START_ERR == status */ { if ((EREPL_UPDSTART_BADPATH == repl_errno) /* receiver server lost gtm_dist environment, bad situation */ || (EREPL_UPDSTART_EXEC == repl_errno)) /* in forked child, could not exec, should exit */ gtmrecv_exit(ABNORMAL_SHUTDOWN); error_count++; } } upd_helper_ctl->start_n_readers = reader_count; upd_helper_ctl->start_n_writers = writer_count; SHM_WRITE_MEMORY_BARRIER; upd_helper_ctl->start_helpers = FALSE; return ((0 == error_count) ? NORMAL_SHUTDOWN : ABNORMAL_SHUTDOWN); } fis-gtm-V6.0-003/sr_port/gtmrecv_reap_helpers.c0000644000032200000250000000374012201176156020403 0ustar librarygtc/**************************************************************** * * * Copyright 2005 Fidelity Information Services, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #ifdef UNIX #include #elif defined(VMS) #include /* Required for gtmrecv.h */ #endif #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "iosp.h" #include "repl_shutdcode.h" #include "gtmrecv.h" #include "is_proc_alive.h" #include "eintr_wrappers.h" #include "repl_log.h" GBLREF recvpool_addrs recvpool; void gtmrecv_reap_helpers(boolean_t wait) { upd_helper_ctl_ptr_t upd_helper_ctl; upd_helper_entry_ptr_t helper, helper_top; uint4 helper_pid; int exit_status; UNIX_ONLY(pid_t waitpid_res;) upd_helper_ctl = recvpool.upd_helper_ctl; for (helper = upd_helper_ctl->helper_list, helper_top = helper + MAX_UPD_HELPERS; helper < helper_top; helper++) { while (0 != (helper_pid = helper->helper_pid_prev)) { UNIX_ONLY(WAITPID(helper_pid, &exit_status, WNOHANG, waitpid_res);) /* release defunct helper if dead */ if (UNIX_ONLY(waitpid_res == helper_pid || ) !is_proc_alive(helper_pid, 0)) { helper->helper_pid = 0; /* release entry */ if (NORMAL_SHUTDOWN == helper->helper_shutdown) { /* zombie has been released (on Unix only). Clean-up the slot */ helper->helper_pid_prev = 0; helper->helper_shutdown = NO_SHUTDOWN; } /* else helper shutdown abnormal, continue to report in checkhealth */ break; } if (!wait) break; SHORT_SLEEP(GTMRECV_WAIT_FOR_UPD_SHUTDOWN); } } upd_helper_ctl->reap_helpers = HELPER_REAP_NONE; } fis-gtm-V6.0-003/sr_port/gtmrecv_reinit_logseqno.c0000644000032200000250000000201112201176156021121 0ustar librarygtc/**************************************************************** * * * Copyright 2005 Fidelity Information Services, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_inet.h" #ifdef VMS #include #endif #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gtmrecv.h" GBLREF recvpool_addrs recvpool; GBLREF seq_num lastlog_seqno; GBLREF uint4 log_interval; GBLREF qw_num trans_recvd_cnt, last_log_tr_recvd_cnt; void gtmrecv_reinit_logseqno(void) { lastlog_seqno = recvpool.recvpool_ctl->jnl_seqno - log_interval; trans_recvd_cnt = -(qw_num)(log_interval - 1); last_log_tr_recvd_cnt = 0; } fis-gtm-V6.0-003/sr_port/gtmrecv_showbacklog.c0000644000032200000250000000401412201176156020230 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2008 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #if !defined(__MVS__) && !defined(VMS) #include #endif #include #include #include "gtm_string.h" #include "gtm_inet.h" #ifdef VMS #include /* Required for gtmrecv.h */ #endif #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gtmrecv.h" #include "repl_dbg.h" #include "repl_shutdcode.h" #include "util.h" GBLREF recvpool_addrs recvpool; GBLREF gtmrecv_options_t gtmrecv_options; GBLREF seq_num seq_num_zero; GBLREF seq_num seq_num_one; int gtmrecv_showbacklog(void) { seq_num seq_num, read_jnl_seqno, jnl_seqno; QWASSIGN(jnl_seqno, recvpool.recvpool_ctl->jnl_seqno); if (QWEQ(jnl_seqno, seq_num_zero)) QWASSIGN(jnl_seqno, recvpool.recvpool_ctl->old_jnl_seqno); QWASSIGN(read_jnl_seqno, recvpool.upd_proc_local->read_jnl_seqno); QWSUB(seq_num, jnl_seqno, read_jnl_seqno); util_out_print("!@UQ : number of backlog transactions received by receiver server and yet to be processed " "by update process", TRUE, &seq_num); QWASSIGN(seq_num, jnl_seqno); if (QWNE(seq_num, seq_num_zero)) QWDECRBY(seq_num, seq_num_one); util_out_print("!@UQ : sequence number of last transaction received from Source Server and written to receive pool", TRUE, &seq_num); QWASSIGN(seq_num, read_jnl_seqno); if (QWNE(seq_num, seq_num_zero)) QWDECRBY(seq_num, seq_num_one); util_out_print("!@UQ : sequence number of last transaction processed by update process", TRUE, &seq_num); return (NORMAL_SHUTDOWN); } fis-gtm-V6.0-003/sr_port/gtmrecv_start_helpers.c0000644000032200000250000000735512201176156020617 0ustar librarygtc/**************************************************************** * * * Copyright 2005, 2009 Fidelity Information Services, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #if defined(__MVS__) && !defined(_ISOC99_SOURCE) #define _ISOC99_SOURCE #endif #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #ifdef VMS #include /* Required for gtmrecv.h */ #endif #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "iosp.h" #include "repl_shutdcode.h" #include "gtmrecv.h" #include "gtmmsg.h" #include "is_proc_alive.h" #include "memcoherency.h" GBLREF recvpool_addrs recvpool; int gtmrecv_start_helpers(int n_readers, int n_writers) { /* Set flag in recvpool telling the receiver server to start n_readers and n_writers helper processes. * Wait for receiver server to complete the process - completed successfully, or terminated with error */ upd_helper_ctl_ptr_t upd_helper_ctl; upd_helper_entry_ptr_t helper, helper_top; char err_str[BUFSIZ]; int avail_slots, started_readers, started_writers; error_def(ERR_REPLERR); error_def(ERR_REPLINFO); error_def(ERR_REPLWARN); assert(0 != n_readers || 0 != n_writers); upd_helper_ctl = recvpool.upd_helper_ctl; /* let's clean up dead helpers first so we get an accurate count of available slots */ upd_helper_ctl->reap_helpers = HELPER_REAP_NOWAIT; while (HELPER_REAP_NONE != upd_helper_ctl->reap_helpers && SRV_ALIVE == is_recv_srv_alive()) SHORT_SLEEP(GTMRECV_WAIT_FOR_UPD_SHUTDOWN); upd_helper_ctl->reap_helpers = HELPER_REAP_NONE; /* just in case recvr died */ /* count available slots so receiver doesn't have to */ for (avail_slots = 0, helper = upd_helper_ctl->helper_list, helper_top = helper + MAX_UPD_HELPERS; helper < helper_top; helper++) { if (0 == helper->helper_pid) { avail_slots++; helper->helper_pid_prev = 0; /* force out abnormally terminated helpers as well */ helper->helper_shutdown = NO_SHUTDOWN; /* clean state */ } } if (avail_slots < n_readers + n_writers) { SNPRINTF(err_str, SIZEOF(err_str), "%d helpers will exceed the maximum allowed (%d), limit the helpers to %d\n", n_readers + n_writers, MAX_UPD_HELPERS, avail_slots); gtm_putmsg(VARLSTCNT(4) ERR_REPLERR, 2, LEN_AND_STR(err_str)); return ABNORMAL_SHUTDOWN; } upd_helper_ctl->start_n_readers = n_readers; upd_helper_ctl->start_n_writers = n_writers; SHM_WRITE_MEMORY_BARRIER; upd_helper_ctl->start_helpers = TRUE; /* hey receiver, let's go, start 'em up */ while (upd_helper_ctl->start_helpers && SRV_ALIVE == is_recv_srv_alive()) SHORT_SLEEP(GTMRECV_WAIT_FOR_SRV_START); if (!upd_helper_ctl->start_helpers) { started_readers = upd_helper_ctl->start_n_readers; started_writers = upd_helper_ctl->start_n_writers; SNPRINTF(err_str, SIZEOF(err_str), "%s %d out of %d readers and %d out of %d writers started", ((started_readers + started_writers) == (n_readers + n_writers)) ? "All" : "Only", started_readers, n_readers, started_writers, n_writers); if ((started_readers + started_writers) == (n_readers + n_writers)) { gtm_putmsg(VARLSTCNT(4) ERR_REPLINFO, 2, LEN_AND_STR(err_str)); return NORMAL_SHUTDOWN; } gtm_putmsg(VARLSTCNT(4) ERR_REPLWARN, 2, LEN_AND_STR(err_str)); return ABNORMAL_SHUTDOWN; } gtm_putmsg(VARLSTCNT(4) ERR_REPLERR, 2, LEN_AND_LIT("Receiver server is not alive to start helpers. Start receiver server first")); return ABNORMAL_SHUTDOWN; } fis-gtm-V6.0-003/sr_port/gtmrecv_statslog.c0000644000032200000250000000446512201176156017577 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #if !defined(__MVS__) && !defined(VMS) #include #endif #include #include #include "gtm_string.h" #include "gtm_inet.h" #ifdef UNIX #include #endif #ifdef VMS #include /* Required for gtmrecv.h */ #endif #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gtmrecv.h" #include "repl_dbg.h" #include "repl_shutdcode.h" #include "repl_sem.h" #include "util.h" #include "gtm_fcntl.h" #include "gtmio.h" #include "repl_log.h" #include "repl_sp.h" GBLREF recvpool_addrs recvpool; GBLREF gtmrecv_options_t gtmrecv_options; error_def(ERR_REPLLOGOPN); #ifdef VMS error_def(ERR_UNIMPLOP); error_def(ERR_TEXT); #endif int gtmrecv_statslog(void) { #ifdef VMS rts_error(VARLSTCNT(6) ERR_UNIMPLOP, 0, ERR_TEXT, 2, LEN_AND_LIT("Statistics logging not supported on VMS")); #endif /* Grab the recvpool option write lock */ if (0 > grab_sem(RECV, RECV_SERV_OPTIONS_SEM)) { util_out_print("Error grabbing recvpool option write lock. Could not initiate stats log", TRUE); return (ABNORMAL_SHUTDOWN); } if (gtmrecv_options.statslog == recvpool.gtmrecv_local->statslog) { util_out_print("STATSLOG is already !AD. Not initiating change in stats log", TRUE, gtmrecv_options.statslog ? strlen("ON") : strlen("OFF"), gtmrecv_options.statslog ? "ON" : "OFF"); rel_sem_immediate(RECV, RECV_SERV_OPTIONS_SEM); return (ABNORMAL_SHUTDOWN); } if (!gtmrecv_options.statslog) { recvpool.gtmrecv_local->statslog = FALSE; util_out_print("STATSLOG turned OFF", TRUE); rel_sem_immediate(RECV, RECV_SERV_OPTIONS_SEM); return (NORMAL_SHUTDOWN); } recvpool.gtmrecv_local->statslog = TRUE; util_out_print("Stats log turned on", TRUE); rel_sem_immediate(RECV, RECV_SERV_OPTIONS_SEM); return (NORMAL_SHUTDOWN); } fis-gtm-V6.0-003/sr_port/gtmrecv_upd_proc_init.c0000644000032200000250000001777712201176156020607 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_time.h" #include "gtm_fcntl.h" #include "gtm_unistd.h" #include "gtm_inet.h" #ifdef UNIX #include #include "fork_init.h" #elif defined(VMS) #include #endif #include #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gtmrecv.h" #include "repl_dbg.h" #include "repl_errno.h" #include "iosp.h" #include "gtm_stdio.h" #include "repl_shutdcode.h" #include "repl_sem.h" #include "io.h" #include "is_proc_alive.h" #include "gtmmsg.h" #include "trans_log_name.h" #include "repl_log.h" #include "eintr_wrappers.h" #define UPDPROC_CMD_MAXLEN 1024 #define UPDPROC_CMD "$gtm_dist/mupip" #define UPDPROC_CMD_FILE "mupip" #define UPDPROC_CMD_ARG1 "replicate" #define UPDPROC_CMD_ARG2 "-updateproc" #define UPDPROC_CMD_STR "REPLICATE/UPDATEPROC" GBLREF recvpool_addrs recvpool; GBLREF int recvpool_shmid; GBLREF int gtmrecv_log_fd; GBLREF FILE *gtmrecv_log_fp; GBLREF int updproc_log_fd; error_def(ERR_LOGTOOLONG); error_def(ERR_RECVPOOLSETUP); error_def(ERR_REPLINFO); error_def(ERR_TEXT); int gtmrecv_upd_proc_init(boolean_t fresh_start) { /* Update Process initialization */ mstr upd_proc_log_cmd, upd_proc_trans_cmd; char upd_proc_cmd[UPDPROC_CMD_MAXLEN]; int status, save_errno; int upd_status, save_upd_status; #ifdef UNIX pid_t upd_pid, waitpid_res; #elif defined(VMS) uint4 upd_pid; uint4 cmd_channel; $DESCRIPTOR(cmd_desc, UPDPROC_CMD_STR); #endif /* Check if the update process is alive */ if ((upd_status = is_updproc_alive()) == SRV_ERR) { save_errno = errno; /* errno from get_sem_info() called from is_updproc_alive() */ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Receive pool semctl failure"), UNIX_ONLY(save_errno) VMS_ONLY(REPL_SEM_ERRNO)); repl_errno = EREPL_UPDSTART_SEMCTL; return(UPDPROC_START_ERR); } else if (upd_status == SRV_ALIVE && !fresh_start) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, RTS_ERROR_LITERAL("Update process already exists. Not starting it")); return(UPDPROC_EXISTS); } else if (upd_status == SRV_ALIVE) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Update process already exists. Please kill it before a fresh start")); return(UPDPROC_EXISTS); } save_upd_status = recvpool.upd_proc_local->upd_proc_shutdown; recvpool.upd_proc_local->upd_proc_shutdown = NO_SHUTDOWN; #ifdef UNIX FORK(upd_pid); /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */ if (0 > upd_pid) { recvpool.upd_proc_local->upd_proc_shutdown = save_upd_status; gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not fork update process"), errno); repl_errno = EREPL_UPDSTART_FORK; return(UPDPROC_START_ERR); } if (0 == upd_pid) { /* Update Process */ upd_proc_log_cmd.len = SIZEOF(UPDPROC_CMD) - 1; upd_proc_log_cmd.addr = UPDPROC_CMD; status = TRANS_LOG_NAME(&upd_proc_log_cmd, &upd_proc_trans_cmd, upd_proc_cmd, SIZEOF(upd_proc_cmd), dont_sendmsg_on_log2long); if (status != SS_NORMAL) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not find path of Update Process. Check value of $gtm_dist")); if (SS_LOG2LONG == status) gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_LOGTOOLONG, 3, LEN_AND_LIT(UPDPROC_CMD), SIZEOF(upd_proc_cmd) - 1); repl_errno = EREPL_UPDSTART_BADPATH; return(UPDPROC_START_ERR); } upd_proc_cmd[upd_proc_trans_cmd.len] = '\0'; if (EXECL(upd_proc_cmd, upd_proc_cmd, UPDPROC_CMD_ARG1, UPDPROC_CMD_ARG2, NULL) < 0) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not exec Update Process"), errno); repl_errno = EREPL_UPDSTART_EXEC; return(UPDPROC_START_ERR); } } #elif defined(VMS) /* Create detached server and write startup commands to it */ status = repl_create_server(&cmd_desc, "GTMU", "", &cmd_channel, &upd_pid, ERR_RECVPOOLSETUP); if (SS_NORMAL != status) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to spawn Update process"), status); recvpool.upd_proc_local->upd_proc_shutdown = save_upd_status; repl_errno = EREPL_UPDSTART_FORK; return(UPDPROC_START_ERR); } #endif if (recvpool.upd_proc_local->upd_proc_pid) recvpool.upd_proc_local->upd_proc_pid_prev = recvpool.upd_proc_local->upd_proc_pid; else recvpool.upd_proc_local->upd_proc_pid_prev = upd_pid; recvpool.upd_proc_local->upd_proc_pid = upd_pid; /* Receiver Server; wait for the update process to startup */ REPL_DPRINT2("Waiting for update process %d to startup\n", upd_pid); while (get_sem_info(RECV, UPD_PROC_COUNT_SEM, SEM_INFO_VAL) == 0 && is_proc_alive(upd_pid, 0)) { /* To take care of reassignment of PIDs, the while condition should be && with the * condition (PPID of pid == process_id) */ REPL_DPRINT2("Waiting for update process %d to startup\n", upd_pid); UNIX_ONLY(WAITPID(upd_pid, &status, WNOHANG, waitpid_res);) /* Release defunct update process if dead */ SHORT_SLEEP(GTMRECV_WAIT_FOR_SRV_START); } #ifdef VMS /* Deassign the send-cmd mailbox channel */ if (SS_NORMAL != (status = sys$dassgn(cmd_channel))) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to close upd-send-cmd mbox channel"), status); recvpool.upd_proc_local->upd_proc_shutdown = save_upd_status; repl_errno = EREPL_UPDSTART_BADPATH; /* Just to make an auto-shutdown */ return(UPDPROC_START_ERR); } #endif repl_log(gtmrecv_log_fp, TRUE, FALSE, "Update Process started. PID %d [0x%X]\n", upd_pid, upd_pid); return(UPDPROC_STARTED); } int gtmrecv_start_updonly(void) { int start_status, recvr_status, upd_status; if ((upd_status = is_updproc_alive()) == SRV_ALIVE) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Update Process exists already. New process not started")); return(UPDPROC_START_ERR); } else if (upd_status == SRV_ERR) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error in starting up update process")); return(UPDPROC_START_ERR); } assert(upd_status == SRV_DEAD); #ifdef VMS recvpool.upd_proc_local->changelog |= REPLIC_CHANGE_LOGFILE; #endif recvpool.upd_proc_local->start_upd = UPDPROC_START; while ((start_status = recvpool.upd_proc_local->start_upd) == UPDPROC_START && (recvr_status = is_recv_srv_alive()) == SRV_ALIVE) SHORT_SLEEP(GTMRECV_WAIT_FOR_SRV_START); if (start_status == UPDPROC_STARTED) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_REPLINFO, 2, RTS_ERROR_LITERAL("Update Process started successfully")); return(UPDPROC_STARTED); } #ifdef VMS recvpool.upd_proc_local->changelog &= ~REPLIC_CHANGE_LOGFILE; #endif if (start_status == UPDPROC_START) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Receiver server is not alive to start update process. Please start receiver server")); } else if (start_status == UPDPROC_START_ERR) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error starting update process")); } else if (start_status == UPDPROC_EXISTS) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Update Process exists already. New process not started")); } return(UPDPROC_START_ERR); } fis-gtm-V6.0-003/sr_port/gtmsource_ch.c0000644000032200000250000000420712201176156016664 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "gtm_unistd.h" #include "gtm_fcntl.h" #include "gtm_inet.h" #ifdef UNIX #include "gtm_ipc.h" #include #elif defined(VMS) #include #include /* Required for gtmrecv.h */ #endif #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "iosp.h" #include "repl_shutdcode.h" #include "repl_msg.h" #include "gtmsource.h" #include "error.h" #include "dpgbldir.h" #ifdef UNIX #include "ftok_sems.h" #endif GBLREF gd_addr *gd_header; GBLREF jnlpool_addrs jnlpool; error_def(ERR_ASSERT); error_def(ERR_CTRLC); error_def(ERR_FORCEDHALT); error_def(ERR_GTMASSERT); error_def(ERR_GTMASSERT2); error_def(ERR_GTMCHECK); error_def(ERR_OUTOFSPACE); error_def(ERR_STACKOFLOW); error_def(ERR_MEMORY); error_def(ERR_VMSMEMORY); CONDITION_HANDLER(gtmsource_ch) { gd_addr *addr_ptr; gd_region *reg_local, *reg_top; sgmnt_addrs *csa; START_CH; if (!(IS_GTM_ERROR(SIGNAL)) || DUMPABLE || SEVERITY == ERROR) { for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr)) { for (reg_local = addr_ptr->regions, reg_top = reg_local + addr_ptr->n_regions; reg_local < reg_top; reg_local++) { if (reg_local->open && !reg_local->was_open) { csa = (sgmnt_addrs *)&FILE_INFO(reg_local)->s_addrs; if (csa && (csa->now_crit)) rel_crit(reg_local); } } } if (jnlpool.jnlpool_ctl) { csa = (sgmnt_addrs *)&FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; if (csa && csa->now_crit) rel_lock(jnlpool.jnlpool_dummy_reg); } NEXTCH; } /* warning, info, or success */ CONTINUE; } fis-gtm-V6.0-003/sr_port/gtmsource_comm_init.c0000644000032200000250000000715612201176156020256 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #if defined(__MVS__) && !defined(_ISOC99_SOURCE) #define _ISOC99_SOURCE #endif #include "mdef.h" #include #include #include "gtm_stdio.h" #include "gtm_string.h" #include "gtm_socket.h" #include "gtm_netdb.h" #include "gtm_ipv6.h" #include "gtm_inet.h" #include "gtm_fcntl.h" #include "gtm_unistd.h" #ifdef VMS #include /* Required for gtmsource.h */ #endif #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "repl_msg.h" #include "gtmsource.h" #include "repl_sp.h" #include "repl_comm.h" #include "repl_log.h" GBLDEF int gtmsource_sock_fd = FD_INVALID; GBLREF jnlpool_addrs jnlpool; GBLREF FILE *gtmsource_log_fp; error_def(ERR_REPLCOMM); error_def(ERR_GETADDRINFO); error_def(ERR_TEXT); int gtmsource_comm_init(void) { /* Initialize communication stuff */ struct linger disable_linger = {0, 0}; char error_string[1024]; int err_status; struct addrinfo *ai_ptr = NULL, *ai_head = NULL, hints; gtmsource_local_ptr_t gtmsource_local; char *host; char port_buffer[NI_MAXSERV]; int port_len; int errcode; int tries; if (FD_INVALID != gtmsource_sock_fd) /* Initialization done already */ return(0); gtmsource_local = jnlpool.gtmsource_local; port_len = 0; I2A(port_buffer, port_len, gtmsource_local->secondary_port); port_buffer[port_len] = '\0'; host = gtmsource_local->secondary_host; CLIENT_HINTS(hints); for (tries = 0; tries < MAX_GETHOST_TRIES && EAI_AGAIN == (errcode = getaddrinfo(host, port_buffer, &hints, &ai_head)); tries++); if (0 != errcode) RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode); /* find one address valid for creating socket */ assert(ai_head); for(ai_ptr = ai_head; NULL != ai_ptr; ai_ptr = ai_ptr->ai_next) { if (FD_INVALID == (gtmsource_sock_fd = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol))) err_status = errno; else { err_status = 0; break; } } if (0 != err_status) { freeaddrinfo(ai_head); /* prevent mem-leak */ SNPRINTF(error_string, SIZEOF(error_string), "Error with source server socket create : %s", STRERROR(err_status)); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(error_string)); } assert(NULL != ai_ptr); assert(SIZEOF(gtmsource_local->secondary_inet_addr) >= ai_ptr->ai_addrlen); /* only save the addrinfo and address after the socket is successfuly created */ gtmsource_local->secondary_af = ai_ptr->ai_family; gtmsource_local->secondary_addrlen = ai_ptr->ai_addrlen; memcpy((struct sockaddr*)(>msource_local->secondary_inet_addr), ai_ptr->ai_addr, ai_ptr->ai_addrlen); freeaddrinfo(ai_head); /* prevent mem-leak */ /* A connection breakage should get rid of the socket */ if (-1 == setsockopt(gtmsource_sock_fd, SOL_SOCKET, SO_LINGER, (const void *)&disable_linger, SIZEOF(disable_linger))) { err_status = ERRNO; SNPRINTF(error_string, SIZEOF(error_string), "Error with source server socket disable linger : %s", STRERROR(err_status)); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(error_string)); } return(0); } fis-gtm-V6.0-003/sr_port/gtmsource_ctl_init.c0000644000032200000250000003652312201176156020105 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #ifdef UNIX #include "gtm_stat.h" #elif defined(VMS) #include #include #include #include #include #include /* Required for gtmsource.h */ #include #else #error Unsupported platform #endif #include #include "gtm_fcntl.h" #include "gtm_unistd.h" #include "gtm_inet.h" #include "gtm_stdio.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "repl_msg.h" #include "gtmsource.h" #include "repl_ctl.h" #include "repl_errno.h" #include "repl_dbg.h" #ifdef UNIX #include "gtmio.h" #endif #include "iosp.h" #include "eintr_wrappers.h" #include "repl_sp.h" #include "tp_change_reg.h" #include "is_file_identical.h" #include "get_fs_block_size.h" #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif #ifdef __MVS__ #include "gtm_zos_io.h" #endif GBLDEF repl_ctl_element *repl_ctl_list = NULL; GBLREF jnlpool_addrs jnlpool; GBLREF seq_num seq_num_zero; GBLREF gd_addr *gd_header; GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF int gtmsource_log_fd; GBLREF FILE *gtmsource_log_fp; GBLREF int gtmsource_statslog_fd; GBLREF FILE *gtmsource_statslog_fp; #ifdef UNIX GBLREF gtmsource_state_t gtmsource_state; GBLREF uint4 process_id; #endif error_def(ERR_JNLFILRDOPN); error_def(ERR_JNLNOREPL); repl_buff_t *repl_buff_create(uint4 buffsize, uint4 jnl_fs_block_size); repl_buff_t *repl_buff_create(uint4 buffsize, uint4 jnl_fs_block_size) { repl_buff_t *tmp_rb; int index; unsigned char *buff_ptr; tmp_rb = (repl_buff_t *)malloc(SIZEOF(repl_buff_t)); tmp_rb->buffindex = REPL_MAINBUFF; for (index = REPL_MAINBUFF; REPL_NUMBUFF > index; index++) { tmp_rb->buff[index].reclen = 0; tmp_rb->buff[index].recaddr = JNL_FILE_FIRST_RECORD; tmp_rb->buff[index].readaddr = JNL_FILE_FIRST_RECORD; tmp_rb->buff[index].buffremaining = buffsize; buff_ptr = (unsigned char *)malloc(buffsize + jnl_fs_block_size); tmp_rb->buff[index].base_buff = buff_ptr; tmp_rb->buff[index].base = (unsigned char *)ROUND_UP2((uintszofptr_t)buff_ptr, jnl_fs_block_size); tmp_rb->buff[index].recbuff = tmp_rb->buff[index].base; } tmp_rb->fc = (repl_file_control_t *)malloc(SIZEOF(repl_file_control_t)); return (tmp_rb); } /* Given a journal file name, this function opens that file explicitly without going through "jnl_ensure_open" */ int repl_open_jnl_file_by_name(repl_ctl_element *tmp_ctl, int jnl_fn_len, char *jnl_fn, int *fd_ptr, void *stat_buf_ptr) { int tmp_fd; int status; #ifdef UNIX struct stat stat_buf; #elif defined(VMS) struct FAB fab; struct NAM stat_buf; #else #error Unsupported platform #endif tmp_ctl->jnl_fn_len = jnl_fn_len; memcpy(tmp_ctl->jnl_fn, jnl_fn, jnl_fn_len); tmp_ctl->jnl_fn[jnl_fn_len] = '\0'; status = SS_NORMAL; /* Open Journal File */ # ifdef UNIX OPENFILE(tmp_ctl->jnl_fn, O_RDONLY, tmp_fd); if (0 > tmp_fd) { status = errno; } if (SS_NORMAL == status) { FSTAT_FILE(tmp_fd, &stat_buf, status); if (0 > status) { status = errno; assert(FALSE); } # ifdef __MVS else if (-1 == gtm_zos_tag_to_policy(tmp_fd, TAG_BINARY)) { status = errno; assert(FALSE); } # endif } *((struct stat *)stat_buf_ptr) = stat_buf; # elif defined(VMS) fab = cc$rms_fab; fab.fab$l_fna = tmp_ctl->jnl_fn; fab.fab$b_fns = tmp_ctl->jnl_fn_len; fab.fab$l_fop = FAB$M_UFO; fab.fab$b_fac = FAB$M_GET | FAB$M_PUT | FAB$M_BIO; fab.fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_UPI; stat_buf = cc$rms_nam; fab.fab$l_nam = &stat_buf; fab.fab$l_dna = JNL_EXT_DEF; fab.fab$b_dns = SIZEOF(JNL_EXT_DEF) - 1; status = sys$open(&fab); if (RMS$_NORMAL == status) { status = SS_NORMAL; tmp_fd = fab.fab$l_stv; } assert(SS_NORMAL == status); *((struct NAM *)stat_buf_ptr) = stat_buf; # endif REPL_DPRINT2("CTL INIT : Direct open of file %s\n", tmp_ctl->jnl_fn); *fd_ptr = tmp_fd; return status; } int repl_ctl_create(repl_ctl_element **ctl, gd_region *reg, int jnl_fn_len, char *jnl_fn, boolean_t init) { gd_region *r_save; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; repl_ctl_element *tmp_ctl = NULL; jnl_file_header *tmp_jfh = NULL; jnl_file_header *tmp_jfh_base = NULL; jnl_private_control *jpc; int tmp_fd = NOJNL; int status; int gtmcrypt_errno; uint4 jnl_status; boolean_t did_jnl_ensure_open = FALSE, was_crit; int4 lcl_jnl_fn_len; char lcl_jnl_fn[JNL_NAME_SIZE]; #ifdef UNIX struct stat stat_buf; #elif defined(VMS) struct NAM stat_buf; short iosb[4]; /* needed by the F_READ_BLK_ALIGNED macro */ #else #error Unsupported platform #endif uint4 jnl_fs_block_size; status = SS_NORMAL; jnl_status = 0; tmp_ctl = (repl_ctl_element *)malloc(SIZEOF(repl_ctl_element)); tmp_ctl->reg = reg; csa = &FILE_INFO(reg)->s_addrs; jpc = csa->jnl; if (init) { assert((0 == jnl_fn_len) && ((NULL == jnl_fn) || ('\0' == jnl_fn[0]))); r_save = gv_cur_region; gv_cur_region = reg; tp_change_reg(); assert(csa == cs_addrs); jpc->channel = NOJNL; /* Not to close the prev gener file */ was_crit = csa->now_crit; if (!was_crit) grab_crit(reg); # ifdef UNIX if (csa->onln_rlbk_cycle != csa->nl->onln_rlbk_cycle) { /* Concurrent online rollback. Possible only if we are called from gtmsource_update_zqgblmod_seqno_and_tn * in which case we don't hold the gtmsource_srv_latch. Assert that. */ assert(process_id != jnlpool.gtmsource_local->gtmsource_srv_latch.u.parts.latch_pid); SYNC_ONLN_RLBK_CYCLES; gtmsource_onln_rlbk_clnup(); if (!was_crit) rel_crit(reg); return -1; } # endif /* Although replication may be WAS_ON, it is possible that source server has not yet sent records * that were generated when replication was ON. We have to open and read this journal file to * cover such a case. But in the WAS_ON case, do not ask for a jnl_ensure_open to be done since * it will return an error (it will try to open the latest generation journal file and that will * fail because of a lot of reasons e.g. "jpc->cycle" vs "jpc->jnl_buff->cycle" mismatch or db/jnl * tn mismatch JNLTRANSLSS error etc.). This will even cause a journal file switch which the source * server should never do (it is only supposed to READ from journal files). Open the journal file * stored in the database file header (which will be non-NULL even though journaling is currently OFF) * thereby can send as many seqnos as possible until the repl=WAS_ON/jnl=OFF state was reached. */ csd = csa->hdr; assert(REPL_ALLOWED(csd)); if (!REPL_WAS_ENABLED(csd)) { /* replication is allowed and has not gone into the WAS_ON state so journaling is expected to be ON*/ assert(JNL_ENABLED(csd)); did_jnl_ensure_open = TRUE; jnl_status = jnl_ensure_open(); if (0 != jnl_status) { if (!was_crit) rel_crit(reg); if (SS_NORMAL != jpc->status) rts_error(VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg), jpc->status); else rts_error(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg)); } else { tmp_ctl->jnl_fn_len = csd->jnl_file_len; memcpy(tmp_ctl->jnl_fn, csd->jnl_file_name, tmp_ctl->jnl_fn_len); tmp_ctl->jnl_fn[tmp_ctl->jnl_fn_len] = '\0'; } /* stash the shared fileid into private storage before rel_crit as it is used in JNL_GDID_PVT macro below */ VMS_ONLY (jpc->fileid = csa->nl->jnl_file.jnl_file_id;) UNIX_ONLY(jpc->fileid = csa->nl->jnl_file.u;) REPL_DPRINT2("CTL INIT : Open of file %s thru jnl_ensure_open\n", tmp_ctl->jnl_fn); tmp_fd = jpc->channel; } else { /* Note that we hold crit so it is safe to pass csd->jnl_file_name (no one else will be changing it) */ status = repl_open_jnl_file_by_name(tmp_ctl, csd->jnl_file_len, (char *)csd->jnl_file_name, &tmp_fd, &stat_buf); } if (!was_crit) rel_crit(reg); gv_cur_region = r_save; tp_change_reg(); assert(NOJNL != tmp_fd); } else status = repl_open_jnl_file_by_name(tmp_ctl, jnl_fn_len, jnl_fn, &tmp_fd, &stat_buf); if (status == SS_NORMAL) { jnl_fs_block_size = get_fs_block_size(tmp_fd); /* Because the read below will be to the aligned buffer, and it will read an aligned size, we need * to allocate jnl_file_header + 2 * jnl_fs_block_size. There will be some throw-away before the * buffer to get the alignment in place, and then up to jnl_fs_block_size after the header in order * for the size to be a multiple of jnl_fs_block_size. */ tmp_jfh_base = (jnl_file_header *)malloc(SIZEOF(jnl_file_header) + (2 * jnl_fs_block_size)); tmp_jfh = (jnl_file_header *)(ROUND_UP2((uintszofptr_t)tmp_jfh_base, jnl_fs_block_size)); F_READ_BLK_ALIGNED(tmp_fd, 0, tmp_jfh, ROUND_UP2(REAL_JNL_HDR_LEN, jnl_fs_block_size), status); assert(SS_NORMAL == status); if (SS_NORMAL == status) CHECK_JNL_FILE_IS_USABLE(tmp_jfh, status, FALSE, 0, NULL); /* FALSE => NO gtm_putmsg even if errors */ assert(SS_NORMAL == status); } if ((SS_NORMAL != status) || (!REPL_ALLOWED(tmp_jfh))) { /* We need tmp_ctl->jnl_fn to issue the error but want to free up tmp_ctl before the error. * So copy jnl_fn into local buffer before the error. */ lcl_jnl_fn_len = tmp_ctl->jnl_fn_len; assert(ARRAYSIZE(lcl_jnl_fn) >= ARRAYSIZE(tmp_ctl->jnl_fn)); assert(lcl_jnl_fn_len < ARRAYSIZE(lcl_jnl_fn)); memcpy(lcl_jnl_fn, tmp_ctl->jnl_fn, lcl_jnl_fn_len); lcl_jnl_fn[lcl_jnl_fn_len] = '\0'; assert((NULL == tmp_jfh) || !REPL_ALLOWED(tmp_jfh)); free(tmp_ctl); tmp_ctl = NULL; if (NULL != tmp_jfh_base) free(tmp_jfh_base); tmp_jfh = NULL; tmp_jfh_base = NULL; if (SS_NORMAL != status) rts_error(VARLSTCNT(7) ERR_JNLFILRDOPN, 4, lcl_jnl_fn_len, lcl_jnl_fn, DB_LEN_STR(reg), status); else rts_error(VARLSTCNT(6) ERR_JNLNOREPL, 4, lcl_jnl_fn_len, lcl_jnl_fn, DB_LEN_STR(reg)); } assert(SS_NORMAL == status); /* so jnl_fs_block_size is guaranteed to have been initialized */ tmp_ctl->repl_buff = repl_buff_create(tmp_jfh->alignsize, jnl_fs_block_size); tmp_ctl->repl_buff->backctl = tmp_ctl; tmp_ctl->repl_buff->fc->eof_addr = JNL_FILE_FIRST_RECORD; tmp_ctl->repl_buff->fc->fs_block_size = jnl_fs_block_size; tmp_ctl->repl_buff->fc->jfh_base = tmp_jfh_base; tmp_ctl->repl_buff->fc->jfh = tmp_jfh; tmp_ctl->repl_buff->fc->fd = tmp_fd; # ifdef GTM_CRYPT if (tmp_jfh->is_encrypted) { ASSERT_ENCRYPTION_INITIALIZED; /* should be done in db_init (gtmsource() -> gvcst_init() -> db_init()) */ GTMCRYPT_GETKEY(csa, tmp_jfh->encryption_hash, tmp_ctl->encr_key_handle, gtmcrypt_errno); if (0 != gtmcrypt_errno) GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, rts_error, tmp_ctl->jnl_fn_len, tmp_ctl->jnl_fn); } # endif if (did_jnl_ensure_open) { F_COPY_GDID(tmp_ctl->repl_buff->fc->id, JNL_GDID_PVT(csa)); /* reset jpc->channel (would have been updated by jnl_ensure_open) as that corresponds to an * actively updated journal file and is only for GT.M and never for source server which only * READS from journal files. Source server anyways has a copy of the fd in tmp_ctl->repl_buff->fc->fd. */ jpc->channel = NOJNL; } else { F_COPY_GDID_FROM_STAT(tmp_ctl->repl_buff->fc->id, stat_buf); /* For VMS stat_buf is a NAM structure */ } QWASSIGN(tmp_ctl->min_seqno, seq_num_zero); QWASSIGN(tmp_ctl->max_seqno, seq_num_zero); QWASSIGN(tmp_ctl->seqno, seq_num_zero); tmp_ctl->tn = 1; tmp_ctl->file_state = JNL_FILE_UNREAD; tmp_ctl->lookback = FALSE; tmp_ctl->first_read_done = FALSE; tmp_ctl->eof_addr_final = FALSE; tmp_ctl->max_seqno_final = FALSE; tmp_ctl->read_complete = FALSE; tmp_ctl->min_seqno_dskaddr = 0; tmp_ctl->max_seqno_dskaddr = 0; tmp_ctl->next = tmp_ctl->prev = NULL; *ctl = tmp_ctl; return (SS_NORMAL); } int gtmsource_ctl_init(void) { /* Setup ctl for reading from journal files */ gd_region *region_top, *reg; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; repl_ctl_element *tmp_ctl, *prev_ctl; int jnl_file_len, status; repl_ctl_list = (repl_ctl_element *)malloc(SIZEOF(repl_ctl_element)); memset((char_ptr_t)repl_ctl_list, 0, SIZEOF(*repl_ctl_list)); prev_ctl = repl_ctl_list; UNIX_ONLY(assert(GTMSOURCE_HANDLE_ONLN_RLBK != gtmsource_state)); /* can't come here without handling online rollback */ region_top = gd_header->regions + gd_header->n_regions; for (reg = gd_header->regions; reg < region_top; reg++) { assert(reg->open); csa = &FILE_INFO(reg)->s_addrs; csd = csa->hdr; if (REPL_ALLOWED(csd)) { status = repl_ctl_create(&tmp_ctl, reg, 0, NULL, TRUE); assert((SS_NORMAL == status) UNIX_ONLY(|| (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state))); UNIX_ONLY( if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state) return -1; ) prev_ctl->next = tmp_ctl; tmp_ctl->prev = prev_ctl; tmp_ctl->next = NULL; prev_ctl = tmp_ctl; } } if (NULL == repl_ctl_list->next) /* No replicated region */ GTMASSERT; return (SS_NORMAL); } int repl_ctl_close(repl_ctl_element *ctl) { int index; int status; if (NULL != ctl) { if (NULL != ctl->repl_buff) { for (index = REPL_MAINBUFF; REPL_NUMBUFF > index; index++) if (NULL != ctl->repl_buff->buff[index].base_buff) free(ctl->repl_buff->buff[index].base_buff); if (NULL != ctl->repl_buff->fc) { if (NULL != ctl->repl_buff->fc->jfh_base) free(ctl->repl_buff->fc->jfh_base); if (NOJNL != ctl->repl_buff->fc->fd) F_CLOSE(ctl->repl_buff->fc->fd, status); /* resets "ctl->repl_buff->fc->fd" to FD_INVALID */ free(ctl->repl_buff->fc); } free(ctl->repl_buff); } free(ctl); } return (SS_NORMAL); } int gtmsource_ctl_close(void) { repl_ctl_element *ctl; sgmnt_addrs *csa; int status; UNIX_ONLY(gtmsource_stop_jnl_release_timer();) if (repl_ctl_list) { for (ctl = repl_ctl_list->next; NULL != ctl; ctl = repl_ctl_list->next) { repl_ctl_list->next = ctl->next; /* next element becomes head thereby removing this element, the current head from the list; if there is an error path that returns us to this function before all elements were freed, we won't try to free elements that have been freed already */ # ifdef DEBUG csa = &FILE_INFO(ctl->reg)->s_addrs; /* jpc->channel should never be set to a valid value outside of repl_ctl_create. The only exception is if * we were interrupted in the middle of repl_ctl_create by an external signal in which case the process * better be exiting. Assert that. */ assert(((NULL != csa->jnl) && (NOJNL == csa->jnl->channel)) || process_exiting); # endif repl_ctl_close(ctl); } ctl = repl_ctl_list; repl_ctl_list = NULL; free(ctl); } return (SS_NORMAL); } int gtmsource_set_lookback(void) { /* Scan all the region ctl's and set lookback to TRUE if ctl has to be * repositioned for a transaction read from the past */ repl_ctl_element *ctl; for (ctl = repl_ctl_list->next; NULL != ctl; ctl = ctl->next) { if ((JNL_FILE_OPEN == ctl->file_state || JNL_FILE_CLOSED == ctl->file_state) && QWLE(jnlpool.gtmsource_local->read_jnl_seqno, ctl->seqno)) ctl->lookback = TRUE; else ctl->lookback = FALSE; } return (SS_NORMAL); } fis-gtm-V6.0-003/sr_port/gtmsource_exit.c0000644000032200000250000000202612201176156017240 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" /* for FILE * in repl_comm.h */ #include "gtm_stdlib.h" /* for exit() */ #ifdef VMS #include #include #endif #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "repl_msg.h" #include "gtmsource.h" #include "repl_comm.h" void gtmsource_exit(int exit_status) { error_def(ERR_REPLEXITERR); #ifdef VMS sys$exit((0 == exit_status) ? SS$_NORMAL : ERR_REPLEXITERR); #else exit(exit_status); #endif } fis-gtm-V6.0-003/sr_port/gtmsource_heartbeat.h0000644000032200000250000000230512201176156020233 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GTMSOURCE_HEARTBEAT_H #define GTMSOURCE_HEARTBEAT_H #define gtmsource_is_heartbeat_stalled (heartbeat_stalled) #ifndef REPL_DISABLE_HEARTBEAT #define GTMSOURCE_IS_HEARTBEAT_DUE(NOW) \ (0 != last_sent_time \ && difftime(*(NOW), last_sent_time) >= (double)jnlpool.gtmsource_local->connect_parms[GTMSOURCE_CONN_HEARTBEAT_PERIOD]) #else #define GTMSOURCE_IS_HEARTBEAT_DUE(NOW) FALSE #endif GBLREF boolean_t heartbeat_stalled; GBLREF repl_heartbeat_que_entry_t *repl_heartbeat_que_head; GBLREF repl_heartbeat_que_entry_t *repl_heartbeat_free_head; GBLREF time_t last_sent_time; GBLREF time_t earliest_sent_time; void gtmsource_heartbeat_timer(TID tid, int4 interval_len, int *interval_ptr); #endif /* GTMSOURCE_HEARTBEAT_H */ fis-gtm-V6.0-003/sr_port/gtmsource_poll_actions.c0000644000032200000250000001571612201176156020767 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc.* * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_time.h" #include "gtm_string.h" #include "gtm_unistd.h" #include "gtm_inet.h" #ifdef VMS #include /* Required for gtmsource.h */ #endif #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "repl_msg.h" #include "gtmsource.h" #include "repl_dbg.h" #include "repl_log.h" #include "iosp.h" #include "repl_shutdcode.h" #include "gt_timer.h" #include "gtmsource_heartbeat.h" #include "jnl.h" #include "repl_filter.h" #include "util.h" #include "repl_comm.h" #include "eintr_wrappers.h" #include "gtmio.h" #include "sgtm_putmsg.h" #include "copy.h" GBLREF jnlpool_addrs jnlpool; GBLREF int gtmsource_sock_fd; GBLREF gtmsource_state_t gtmsource_state; GBLREF boolean_t gtmsource_logstats; GBLREF int gtmsource_log_fd; GBLREF FILE *gtmsource_log_fp; GBLREF int gtmsource_filter; GBLREF volatile time_t gtmsource_now; GBLREF uint4 log_interval; #ifdef UNIX GBLREF boolean_t last_seen_freeze_flag; #endif error_def(ERR_REPLWARN); #ifdef UNIX error_def(ERR_REPLINSTFREEZECOMMENT); error_def(ERR_REPLINSTFROZEN); error_def(ERR_REPLINSTUNFROZEN); #endif int gtmsource_poll_actions(boolean_t poll_secondary) { /* This function should be called only in active mode, but cannot assert for it */ gtmsource_local_ptr_t gtmsource_local; time_t now; repl_heartbeat_msg_t overdue_heartbeat; char *time_ptr; char time_str[CTIME_BEFORE_NL + 1]; char print_msg[1024], msg_str[1024]; boolean_t log_switched = FALSE; int status; time_t temp_time; gtm_time4_t time4; gtmsource_local = jnlpool.gtmsource_local; if (SHUTDOWN == gtmsource_local->shutdown) { repl_log(gtmsource_log_fp, TRUE, TRUE, "Shutdown signalled\n"); gtmsource_end(); /* Won't return */ } # ifdef UNIX if (jnlpool.jnlpool_ctl->freeze != last_seen_freeze_flag) { last_seen_freeze_flag = jnlpool.jnlpool_ctl->freeze; if (last_seen_freeze_flag) { sgtm_putmsg(print_msg, VARLSTCNT(3) ERR_REPLINSTFROZEN, 1, jnlpool.repl_inst_filehdr->inst_info.this_instname); repl_log(gtmsource_log_fp, TRUE, FALSE, print_msg); sgtm_putmsg(print_msg, VARLSTCNT(3) ERR_REPLINSTFREEZECOMMENT, 1, jnlpool.jnlpool_ctl->freeze_comment); repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg); } else { sgtm_putmsg(print_msg, VARLSTCNT(3) ERR_REPLINSTUNFROZEN, 1, jnlpool.repl_inst_filehdr->inst_info.this_instname); repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg); } } # endif if (GTMSOURCE_START == gtmsource_state) return (SS_NORMAL); if (GTMSOURCE_CHANGING_MODE != gtmsource_state && GTMSOURCE_MODE_PASSIVE_REQUESTED == gtmsource_local->mode) { repl_log(gtmsource_log_fp, TRUE, TRUE, "Changing mode from ACTIVE to PASSIVE\n"); gtmsource_state = GTMSOURCE_CHANGING_MODE; gtmsource_local->mode = GTMSOURCE_MODE_PASSIVE; UNIX_ONLY(gtmsource_local->gtmsource_state = gtmsource_state;) return (SS_NORMAL); } if (poll_secondary && GTMSOURCE_CHANGING_MODE != gtmsource_state && GTMSOURCE_WAITING_FOR_CONNECTION != gtmsource_state) { now = gtmsource_now; if (gtmsource_is_heartbeat_overdue(&now, &overdue_heartbeat)) { /* Few platforms don't allow unaligned memory access. Passing ack_time to GTM_CTIME(ctime) may * cause sig. time4 and temp_time are used as temporary variable for converting time to string.*/ GET_LONG(time4, &overdue_heartbeat.ack_time[0]); temp_time = time4; GTM_CTIME(time_ptr, &temp_time); memcpy(time_str, time_ptr, CTIME_BEFORE_NL); time_str[CTIME_BEFORE_NL] = '\0'; VMS_ONLY(SPRINTF(msg_str, "No response received for heartbeat sent at %s with SEQNO %llu in %0.f seconds. " "Closing connection\n", time_str, *(seq_num *)&overdue_heartbeat.ack_seqno[0], difftime(now, temp_time))); NON_GTM64_ONLY(SPRINTF(msg_str, "No response received for heartbeat sent at %s with SEQNO %llu in %0.f seconds. " "Closing connection\n", time_str, *(seq_num *)&overdue_heartbeat.ack_seqno[0], difftime(now, temp_time))); GTM64_ONLY(SPRINTF(msg_str, "No response received for heartbeat sent at %s with SEQNO %lu in %0.f seconds. " "Closing connection\n", time_str, *(seq_num *)&overdue_heartbeat.ack_seqno[0], difftime(now, temp_time))); sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLWARN, 2, LEN_AND_STR(msg_str)); repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg); repl_close(>msource_sock_fd); SHORT_SLEEP(GTMSOURCE_WAIT_FOR_RECEIVER_CLOSE_CONN); gtmsource_state = GTMSOURCE_WAITING_FOR_CONNECTION; UNIX_ONLY(gtmsource_local->gtmsource_state = gtmsource_state;) return (SS_NORMAL); } if (GTMSOURCE_IS_HEARTBEAT_DUE(&now) && !heartbeat_stalled) { gtmsource_send_heartbeat(&now); if (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state || GTMSOURCE_CHANGING_MODE == gtmsource_state) return (SS_NORMAL); } } if (0 != gtmsource_local->changelog) { if (gtmsource_local->changelog & REPLIC_CHANGE_LOGINTERVAL) { repl_log(gtmsource_log_fp, TRUE, TRUE, "Changing log interval from %u to %u\n", log_interval, gtmsource_local->log_interval); log_interval = gtmsource_local->log_interval; gtmsource_reinit_logseqno(); /* will force a LOG on the first send following the interval change */ } if (gtmsource_local->changelog & REPLIC_CHANGE_LOGFILE) { log_switched = TRUE; repl_log(gtmsource_log_fp, TRUE, TRUE, "Changing log file to %s\n", gtmsource_local->log_file); #ifdef UNIX repl_log_init(REPL_GENERAL_LOG, >msource_log_fd, gtmsource_local->log_file); repl_log_fd2fp(>msource_log_fp, gtmsource_log_fd); #elif defined(VMS) util_log_open(STR_AND_LEN(gtmsource_local->log_file)); #else #error unsupported platform #endif } if ( log_switched == TRUE ) repl_log(gtmsource_log_fp, TRUE, TRUE, "Change log to %s successful\n", gtmsource_local->log_file); gtmsource_local->changelog = 0; } if (!gtmsource_logstats && gtmsource_local->statslog) { #ifdef UNIX gtmsource_logstats = TRUE; repl_log(gtmsource_log_fp, TRUE, TRUE, "Begin statistics logging\n"); #else repl_log(gtmsource_log_fp, TRUE, TRUE, "Stats logging not supported on VMS\n"); #endif } else if (gtmsource_logstats && !gtmsource_local->statslog) { gtmsource_logstats = FALSE; repl_log(gtmsource_log_fp, TRUE, TRUE, "End statistics logging\n"); } if ((gtmsource_filter & EXTERNAL_FILTER) && ('\0' == gtmsource_local->filter_cmd[0])) { repl_log(gtmsource_log_fp, TRUE, TRUE, "Stopping filter\n"); repl_stop_filter(); gtmsource_filter &= ~EXTERNAL_FILTER; } return (SS_NORMAL); } fis-gtm-V6.0-003/sr_port/gtmsource_reinit_logseqno.c0000644000032200000250000000204412201176156021470 0ustar librarygtc/**************************************************************** * * * Copyright 2005 Fidelity Information Services, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_inet.h" #ifdef VMS #include #endif #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "repl_msg.h" #include "gtmsource.h" GBLREF jnlpool_addrs jnlpool; GBLREF seq_num lastlog_seqno; GBLREF uint4 log_interval; GBLREF qw_num trans_sent_cnt, last_log_tr_sent_cnt; void gtmsource_reinit_logseqno(void) { lastlog_seqno = jnlpool.gtmsource_local->read_jnl_seqno - log_interval; trans_sent_cnt = -(qw_num)(log_interval - 1); last_log_tr_sent_cnt = 0; } fis-gtm-V6.0-003/sr_port/gv_bind_name.c0000644000032200000250000001132012201176156016604 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "gtm_string.h" #include "gdsroot.h" #include "gdskill.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "collseq.h" #include "gdsfhead.h" #include "gdscc.h" #include "copy.h" #include "filestruct.h" #include "jnl.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_mname.h" #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "change_reg.h" #include "targ_alloc.h" #include "gvcst_protos.h" /* for gvcst_root_search prototype */ #include "min_max.h" GBLREF gv_namehead *gv_target; GBLREF gv_key *gv_currkey; GBLREF gd_region *gv_cur_region; GBLREF gd_binding *gd_map, *gd_map_top; error_def(ERR_KEY2BIG); error_def(ERR_GVIS); void gv_bind_name(gd_addr *addr, mstr *targ) { gd_binding *map; ht_ent_mname *tabent; mname_entry gvent; int res; boolean_t added; enum db_acc_method acc_meth; gd_region *reg; gvnh_reg_t *gvnh_reg; int keylen; char format_key[MAX_MIDENT_LEN + 1]; /* max key length + 1 byte for '^' */ gv_namehead *tmp_gvt; sgmnt_addrs *csa; gd_map = addr->maps; gd_map_top = gd_map + addr->n_maps; gvent.var_name.addr = targ->addr; gvent.var_name.len = MIN(targ->len, MAX_MIDENT_LEN); COMPUTE_HASH_MNAME(&gvent); if ((NULL != (tabent = lookup_hashtab_mname((hash_table_mname *)addr->tab_ptr, &gvent))) && (NULL != (gvnh_reg = (gvnh_reg_t *)tabent->value))) { reg = gvnh_reg->gd_reg; if (!reg->open) { gv_init_reg(reg); /* could modify gvnh_reg->gvt if multiple regions map to same db file */ assert(0 == gvnh_reg->gvt->clue.end); } gv_target = gvnh_reg->gvt; gv_cur_region = reg; acc_meth = gv_cur_region->dyn.addr->acc_meth; } else { map = gd_map + 1; /* get past local locks */ for (; (res = memcmp(gvent.var_name.addr, &(map->name[0]), gvent.var_name.len)) >= 0; map++) { assert(map < gd_map_top); if (0 == res && 0 != map->name[gvent.var_name.len]) break; } if (!map->reg.addr->open) gv_init_reg(map->reg.addr); gv_cur_region = map->reg.addr; acc_meth = gv_cur_region->dyn.addr->acc_meth; if ((dba_cm == acc_meth) || (dba_usr == acc_meth)) { tmp_gvt = malloc(SIZEOF(gv_namehead) + gvent.var_name.len); memset(tmp_gvt, 0, SIZEOF(gv_namehead) + gvent.var_name.len); tmp_gvt->gvname.var_name.addr = (char *)tmp_gvt + SIZEOF(gv_namehead); tmp_gvt->nct = 0; tmp_gvt->collseq = NULL; tmp_gvt->regcnt = 1; memcpy(tmp_gvt->gvname.var_name.addr, gvent.var_name.addr, gvent.var_name.len); tmp_gvt->gvname.var_name.len = gvent.var_name.len; tmp_gvt->gvname.hash_code = gvent.hash_code; } else { assert(gv_cur_region->max_key_size <= MAX_KEY_SZ); tmp_gvt = (gv_namehead *)targ_alloc(gv_cur_region->max_key_size, &gvent, gv_cur_region); } gvnh_reg = (gvnh_reg_t *)malloc(SIZEOF(gvnh_reg_t)); gvnh_reg->gvt = tmp_gvt; gvnh_reg->gd_reg = gv_cur_region; if (NULL != tabent) { /* Since the global name was found but gv_target was null and now we created a new gv_target, * the hash table key must point to the newly created gv_target->gvname. */ tabent->key = tmp_gvt->gvname; tabent->value = (char *)gvnh_reg; } else { added = add_hashtab_mname((hash_table_mname *)addr->tab_ptr, &tmp_gvt->gvname, gvnh_reg, &tabent); assert(added); } gv_target = tmp_gvt; /* now that any error possibilities (out-of-memory issues in malloc/add_hashtab_mname) * are all done, it is safe to set gv_target. Setting it before could casue gv_target * and gv_currkey to get out of sync in case of an error condition. */ } if ((keylen = gvent.var_name.len + 2) > gv_cur_region->max_key_size) /* caution: embedded assignment of "keylen" */ { assert(ARRAYSIZE(format_key) >= (1 + gvent.var_name.len)); format_key[0] = '^'; memcpy(&format_key[1], gvent.var_name.addr, gvent.var_name.len); csa = &FILE_INFO(gv_cur_region)->s_addrs; rts_error_csa(CSA_ARG(csa) VARLSTCNT(10) ERR_KEY2BIG, 4, keylen, (int4)gv_cur_region->max_key_size, REG_LEN_STR(gv_cur_region), ERR_GVIS, 2, 1 + gvent.var_name.len, format_key); } memcpy(gv_currkey->base, gvent.var_name.addr, gvent.var_name.len); gv_currkey->base[gvent.var_name.len] = 0; gvent.var_name.len++; gv_currkey->base[gvent.var_name.len] = 0; gv_currkey->end = gvent.var_name.len; gv_currkey->prev = 0; change_reg(); return; } fis-gtm-V6.0-003/sr_port/gv_init_reg.c0000644000032200000250000000262112201176156016474 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "iosp.h" #include "gdsbt.h" #include "gdsfhead.h" #include "cryptdef.h" #include "filestruct.h" #include "targ_alloc.h" #include "gvusr.h" #include "gvcst_protos.h" /* for gvcst_init prototype */ GBLREF int4 lkid; GBLREF bool licensed ; GBLREF gv_key *gv_currkey; GBLREF gv_key *gv_altkey; GBLREF gd_region *gv_cur_region; void gv_init_reg (gd_region *reg) { # ifdef NOLICENSE licensed = TRUE; # else CRYPT_CHKSYSTEM; # endif switch (reg->dyn.addr->acc_meth) { case dba_usr: gvusr_init (reg, &gv_cur_region, &gv_currkey, &gv_altkey); break; /* we may be left in dba_cm state for gt_cm, if we have rundown the db and again accessed the db without quitting out of gtm */ case dba_cm: case dba_mm: case dba_bg: if (!reg->open) gvcst_init(reg); break; default: GTMASSERT; } assert(reg->open); return; } fis-gtm-V6.0-003/sr_port/gv_match.c0000644000032200000250000000253712201176157015777 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2008 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "dpgbldir.h" #include "gv_match.h" /* Multiple regions from across multiple global directories might correspond to the same physical file. * This routine detects if a given input region's database file matches with the corresponding file of an already open region. * If yes it returns the FIRST matching region else it returns NULL. */ gd_region *gv_match(gd_region *reg) { gd_region *r_top, *gv_region; gd_addr *addr_ptr; for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr)) { for (gv_region = addr_ptr->regions, r_top = gv_region + addr_ptr->n_regions; gv_region < r_top; gv_region++) { if (!gv_region->open) continue; if (REG_EQUAL(FILE_INFO(reg), gv_region)) return gv_region; } } return NULL; } fis-gtm-V6.0-003/sr_port/gv_match.h0000644000032200000250000000107012201176157015773 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GV_MATCH_INCLUDED #define GV_MATCH_INCLUDED gd_region *gv_match(gd_region *reg); #endif /* GV_MATCH_INCLUDED */ fis-gtm-V6.0-003/sr_port/gv_rundown.c0000644000032200000250000001764512201176157016405 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #ifdef VMS #include /* Required for gtmsource.h */ #include /* Required for the nam$l_esa members */ #endif #include "gtm_inet.h" /* Required for gtmsource.h */ #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "gdskill.h" #include "gdscc.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "filestruct.h" #include "jnl.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "ast.h" #include "repl_msg.h" #include "gtmsource.h" #include "gtmrecv.h" #include "error.h" #ifdef UNIX #include "io.h" #include "gtmsecshr.h" #include "mutex.h" #include "ftok_sems.h" #endif #include "tp_change_reg.h" #include "gds_rundown.h" #include "dpgbldir.h" #include "gvcmy_rundown.h" #include "rc_cpt_ops.h" #include "gv_rundown.h" #include "targ_alloc.h" #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif #if defined(DEBUG) && defined(UNIX) #include "anticipatory_freeze.h" #endif GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF boolean_t pool_init; GBLREF jnlpool_addrs jnlpool; GBLREF recvpool_addrs recvpool; GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; GBLREF gd_region *ftok_sem_reg; #if defined(DEBUG) && defined(UNIX) GBLREF boolean_t is_jnlpool_creator; error_def(ERR_TEXT); #endif error_def(ERR_NOTALLDBRNDWN); void gv_rundown(void) { gd_region *r_top, *r_save, *r_local; gd_addr *addr_ptr; sgm_info *si; int4 rundown_status = EXIT_NRM; /* if gds_rundown went smoothly */ # ifdef VMS vms_gds_info *gds_info; # elif UNIX unix_db_info *udi; # endif #if defined(DEBUG) && defined(UNIX) sgmnt_addrs *csa; # endif DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; r_save = gv_cur_region; /* Save for possible core dump */ gvcmy_rundown(); ENABLE_AST if (pool_init) rel_lock(jnlpool.jnlpool_dummy_reg); for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr)) { for (r_local = addr_ptr->regions, r_top = r_local + addr_ptr->n_regions; r_local < r_top; r_local++) { if (r_local->open && !r_local->was_open && dba_cm != r_local->dyn.addr->acc_meth) { /* Rundown has already occurred for GT.CM client regions through gvcmy_rundown() above. * Hence the (dba_cm != ...) check in the if above. Note that for GT.CM client regions, * region->open is TRUE although cs_addrs is NULL. */ # if defined(DEBUG) && defined(UNIX) if (is_jnlpool_creator && ANTICIPATORY_FREEZE_AVAILABLE && TREF(gtm_test_fake_enospc)) { /* Clear ENOSPC faking now that we are running down */ csa = REG2CSA(r_local); if (csa->nl->fake_db_enospc || csa->nl->fake_jnl_enospc) { send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_TEXT, 2, DB_LEN_STR(r_local), ERR_TEXT, 2, LEN_AND_LIT("Resetting fake_db_enospc and fake_jnl_enospc")); csa->nl->fake_db_enospc = FALSE; csa->nl->fake_jnl_enospc = FALSE; } } # endif gv_cur_region = r_local; tp_change_reg(); UNIX_ONLY(rundown_status |=) gds_rundown(); /* Now that gds_rundown is done, free up the memory associated with the region. * Ideally the following memory freeing code should go to gds_rundown, but * GT.CM calls gds_rundown() and we want to reuse memory for GT.CM. */ if (NULL != cs_addrs) { if (NULL != cs_addrs->dir_tree) FREE_CSA_DIR_TREE(cs_addrs); if (cs_addrs->sgm_info_ptr) { si = cs_addrs->sgm_info_ptr; /* It is possible we got interrupted before initializing all fields of "si" * completely so account for NULL values while freeing/releasing those fields. */ assert((si->tp_csa == cs_addrs) || (NULL == si->tp_csa)); if (si->jnl_tail) { CAREFUL_FREEUP_BUDDY_LIST(si->format_buff_list); CAREFUL_FREEUP_BUDDY_LIST(si->jnl_list); } CAREFUL_FREEUP_BUDDY_LIST(si->recompute_list); CAREFUL_FREEUP_BUDDY_LIST(si->new_buff_list); CAREFUL_FREEUP_BUDDY_LIST(si->tlvl_info_list); CAREFUL_FREEUP_BUDDY_LIST(si->tlvl_cw_set_list); CAREFUL_FREEUP_BUDDY_LIST(si->cw_set_list); if (NULL != si->blks_in_use) { free_hashtab_int4(si->blks_in_use); free(si->blks_in_use); si->blks_in_use = NULL; } if (si->cr_array_size) { assert(NULL != si->cr_array); if (NULL != si->cr_array) free(si->cr_array); } if (NULL != si->first_tp_hist) free(si->first_tp_hist); free(si); } if (cs_addrs->jnl) { assert(&FILE_INFO(cs_addrs->jnl->region)->s_addrs == cs_addrs); if (cs_addrs->jnl->jnllsb) { UNIX_ONLY(assert(FALSE)); free(cs_addrs->jnl->jnllsb); } free(cs_addrs->jnl); } GTMCRYPT_ONLY( if (cs_addrs->encrypted_blk_contents) free(cs_addrs->encrypted_blk_contents); ) } assert(gv_cur_region->dyn.addr->file_cntl->file_info); VMS_ONLY( gds_info = (vms_gds_info *)gv_cur_region->dyn.addr->file_cntl->file_info; if (gds_info->xabpro) free(gds_info->xabpro); if (gds_info->xabfhc) free(gds_info->xabfhc); if (gds_info->nam) { free(gds_info->nam->nam$l_esa); free(gds_info->nam); } if (gds_info->fab) free(gds_info->fab); ) free(gv_cur_region->dyn.addr->file_cntl->file_info); free(gv_cur_region->dyn.addr->file_cntl); } r_local->open = r_local->was_open = FALSE; } } rc_close_section(); gv_cur_region = r_save; /* Restore value for dumps but this region is now closed and is otherwise defunct */ cs_addrs = NULL; GTMCRYPT_ONLY(GTMCRYPT_CLOSE;) #ifdef UNIX gtmsecshr_sock_cleanup(CLIENT); #ifndef MUTEX_MSEM_WAKE mutex_sock_cleanup(); #endif #endif jnlpool_detach(); # ifdef UNIX /* Clean up any left-over ftok semaphores. This part of the code can be reached by almost all of the exit handling routines. * If the ftok semaphore is grabbed, but not released, ftok_sem_reg will have a non-null value and grabbed_ftok_sem will be * TRUE. We cannot rely on gv_cur_region always as it is used in so many places in so many ways. * Note: Typically, it should suffice to check for ftok_sem_reg being non-null and pass that to ftok_sem_release. But, there * are some cases where ftok_sem_reg can be NULL and yet jnlpool.jnlpool_dummy_reg is non-null and the process holds an ftok * semaphore. For instance, if GT.M opened a particular region and then did a jnlpool_init which ended up with an rts_error * (after obtaining the ftok semaphore on jnlpool_dummy_reg), gds_rundown done above (to rundown the database) sets * ftok_sem_reg to NULL (as part of ftok_sem_release). But, jnlpool_dummy_reg is still non-null and the lingering ftok * should be released. So, even though a subset of the below conditions should be enough, we check for all there cases just * to be safe. */ if (ftok_sem_reg) { udi = FILE_INFO(ftok_sem_reg); assert(udi->grabbed_ftok_sem); ftok_sem_release(ftok_sem_reg, TRUE, TRUE); } if (NULL != jnlpool.jnlpool_dummy_reg) { udi = FILE_INFO(jnlpool.jnlpool_dummy_reg); if (udi->grabbed_ftok_sem) ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE); } if (NULL != recvpool.recvpool_dummy_reg) { udi = FILE_INFO(recvpool.recvpool_dummy_reg); if (udi->grabbed_ftok_sem) ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE); } # endif if (EXIT_NRM != rundown_status) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTALLDBRNDWN); } fis-gtm-V6.0-003/sr_port/gv_rundown.h0000644000032200000250000000106012201176157016372 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GV_RUNDOWN_INCLUDED #define GV_RUNDOWN_INCLUDED void gv_rundown(void); #endif /* GV_RUNDOWN_INCLUDED */ fis-gtm-V6.0-003/sr_port/gv_select.c0000644000032200000250000002350612201176157016161 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" /* needed for WCSFLU_* macros */ #include "muextr.h" #include "iosp.h" #include "cli.h" #include "util.h" #include "op.h" #include "gt_timer.h" #include "mupip_exit.h" #include "gv_select.h" #include "global_map.h" #include "gtmmsg.h" #include "wcs_flu.h" #include "min_max.h" #include "hashtab.h" /* needed for HT_VALUE_DUMMY */ #ifdef GTM64 #include "hashtab_int8.h" #endif /* GTM64 */ #include "error.h" #include "gdscc.h" #include "gdskill.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #define MAX_GMAP_ENTRIES_PER_ITER 2 /* maximum increase (could even be negative) in gmap array size per call to global_map */ error_def(ERR_DBRDONLY); error_def(ERR_FREEZE); error_def(ERR_FREEZECTRL); error_def(ERR_MUNOACTION); error_def(ERR_MUNOFINISH); error_def(ERR_SELECTSYNTAX); GBLREF bool mu_ctrlc_occurred; GBLREF bool mu_ctrly_occurred; GBLREF gd_region *gv_cur_region; GBLREF sgmnt_data_ptr_t cs_data; GBLREF sgmnt_addrs *cs_addrs; GBLREF tp_region *grlist; static readonly unsigned char percent_lit = '%'; static readonly unsigned char tilde_lit = '~'; void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist *gl_head, int *reg_max_rec, int *reg_max_key, int *reg_max_blk, boolean_t restrict_reg) { boolean_t stashed = FALSE, append_gbl; int num_quote, len, gmap_size, new_gmap_size, estimated_entries, count, rslt; char *ptr, *ptr1, *c; mstr gmap[512], *gmap_ptr, *gmap_ptr_base, gmap_beg, gmap_end; mval val, curr_gbl_name; glist *gl_tail, *gl_ptr; tp_region *rptr; #ifdef GTM64 hash_table_int8 ext_hash; ht_ent_int8 *tabent; #else hash_table_int4 ext_hash; ht_ent_int4 *tabent; #endif /* GTM64 */ memset(gmap, 0, SIZEOF(gmap)); gmap_size = SIZEOF(gmap) / SIZEOF(gmap[0]); gmap_ptr_base = &gmap[0]; /* "estimated_entries" is a conservative estimate of the # of entries that could be used up in the gmap array */ estimated_entries = 1; /* take into account the NULL gmap entry at the end of the array */ for (ptr = cli_buff; *ptr; ptr = ptr1) { for (ptr1 = ptr; ; ptr1++) { if (',' == *ptr1) { len = (int)(ptr1 - ptr); ptr1++; break; } else if (!*ptr1) { len = (int)(ptr1 - ptr); break; } } gmap_beg.addr = ptr; c = gmap_beg.addr + len - 1; num_quote = 0; while ('"' == *c) { len--; c--; num_quote++; } if (0 >= len) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname)); mupip_exit(ERR_MUNOACTION); } c = gmap_beg.addr; while (0 < num_quote) { if ('"' == *c) { c++; len--; } else { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname)); mupip_exit(ERR_MUNOACTION); } num_quote--; } gmap_beg.addr = c; if ('^' == *c) { gmap_beg.addr++; len--; } gmap_beg.len = len; c = mu_extr_ident(&gmap_beg); len -= INTCAST(c - gmap_beg.addr); assert(len >= 0); if (0 == len) gmap_end = gmap_beg; else if (gmap_beg.len == 1 && '*' == *c) { gmap_beg.addr = (char*)&percent_lit; gmap_beg.len = SIZEOF(percent_lit); gmap_end.addr = (char*)&tilde_lit; gmap_end.len = SIZEOF(tilde_lit); } else if (1 == len && '*' == *c) { gmap_end = gmap_beg; gmap_beg.len--; *c = '~'; } else if (':' != *c) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname)); mupip_exit(ERR_MUNOACTION); } else { gmap_beg.len = INTCAST(c - gmap_beg.addr); c++; gmap_end.addr = c; gmap_end.len = len - 1; if ('^' == *c) { gmap_end.addr++; gmap_end.len--; } c = mu_extr_ident(&gmap_end); MSTR_CMP(gmap_beg, gmap_end, rslt); if (((c - gmap_end.addr) != gmap_end.len) || (0 < rslt)) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname)); mupip_exit(ERR_MUNOACTION); } } /* "estimated_entries" is the maximum number of entries that could be used up in the gmap array including the * next global_map call. The actual number of used entries could be much lower than this. * But since determining the actual number would mean scanning the gmap array for the first NULL pointer (a * performance overhead), we do an approximate check instead. */ estimated_entries += MAX_GMAP_ENTRIES_PER_ITER; if (estimated_entries >= gmap_size) { /* Current gmap array does not have enough space. Double size before calling global_map */ new_gmap_size = gmap_size * 2; /* double size of gmap array */ gmap_ptr = (mstr *)malloc(SIZEOF(mstr) * new_gmap_size); memcpy(gmap_ptr, gmap_ptr_base, SIZEOF(mstr) * gmap_size); if (gmap_ptr_base != &gmap[0]) free(gmap_ptr_base); gmap_size = new_gmap_size; gmap_ptr_base = gmap_ptr; } global_map(gmap_ptr_base, &gmap_beg, &gmap_end); DEBUG_ONLY( count = 1; for (gmap_ptr = gmap_ptr_base; gmap_ptr->addr; gmap_ptr++) count++; assert(count < gmap_size); ) } if (freeze) { GTM64_ONLY(init_hashtab_int8(&ext_hash, 0, HASHTAB_COMPACT, HASHTAB_SPARE_TABLE);) NON_GTM64_ONLY(init_hashtab_int4(&ext_hash, 0, HASHTAB_COMPACT, HASHTAB_SPARE_TABLE);) } gl_head->next = NULL; gl_tail = gl_head; *reg_max_rec = 0; *reg_max_key = 0; *reg_max_blk = 0; for (gmap_ptr = gmap_ptr_base; gmap_ptr->addr ; gmap_ptr++) { curr_gbl_name.mvtype = MV_STR; curr_gbl_name.str = *gmap_ptr++; op_gvname(VARLSTCNT(1) &curr_gbl_name); append_gbl = TRUE; if (dba_cm == gv_cur_region->dyn.addr->acc_meth) { util_out_print("Can not select globals from region !AD across network",TRUE,gv_cur_region->rname_len, gv_cur_region->rname); mupip_exit(ERR_MUNOFINISH); } if (dba_bg != gv_cur_region->dyn.addr->acc_meth && dba_mm != gv_cur_region->dyn.addr->acc_meth) { assert(gv_cur_region->dyn.addr->acc_meth == dba_usr); util_out_print("Can not select globals from non-GDS format region !AD",TRUE,gv_cur_region->rname_len, gv_cur_region->rname); mupip_exit(ERR_MUNOFINISH); } op_gvdata(&val); if (0 == val.m[1]) { op_gvname(VARLSTCNT(1) &curr_gbl_name); op_gvorder(&curr_gbl_name); if (!curr_gbl_name.str.len) break; assert('^' == *curr_gbl_name.str.addr); curr_gbl_name.str.addr++; curr_gbl_name.str.len--; } for (;;) { MSTRP_CMP(&curr_gbl_name.str, gmap_ptr, rslt); if (0 < rslt) break; if (freeze) { /* Note: We cannot use int4 hash when we will have 64-bit address. * In that case we may choose to hash the region name or use int8 hash */ GTM64_ONLY(if(add_hashtab_int8(&ext_hash,(gtm_uint64_t *)&gv_cur_region, HT_VALUE_DUMMY, &tabent))) NON_GTM64_ONLY(if (add_hashtab_int4(&ext_hash, (uint4 *)&gv_cur_region, HT_VALUE_DUMMY, &tabent))) { if (cs_addrs->hdr->freeze) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_FREEZE, 2, gv_cur_region->rname_len, gv_cur_region->rname); mupip_exit(ERR_MUNOFINISH); } /* Cannot proceed for read-only data files */ if (gv_cur_region->read_only) { util_out_print("Cannot freeze the database",TRUE); gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region)); mupip_exit(ERR_MUNOFINISH); } while (REG_ALREADY_FROZEN == region_freeze(gv_cur_region, TRUE, FALSE, FALSE)) { hiber_start(1000); if (mu_ctrly_occurred || mu_ctrlc_occurred) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_FREEZECTRL); mupip_exit(ERR_MUNOFINISH); } } wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SYNC_EPOCH); } } assert(0 < curr_gbl_name.str.len); gl_ptr = (glist*)malloc(SIZEOF(glist) - 1 + curr_gbl_name.str.len); gl_ptr->name.mvtype = MV_STR; gl_ptr->name.str.addr = (char*)gl_ptr->nbuf; gl_ptr->name.str.len = MIN(curr_gbl_name.str.len, MAX_MIDENT_LEN); memcpy(gl_ptr->nbuf, curr_gbl_name.str.addr, curr_gbl_name.str.len); gl_ptr->next = 0; if (append_gbl) { if (*reg_max_rec < cs_data->max_rec_size) *reg_max_rec = cs_data->max_rec_size; if (*reg_max_key < cs_data->max_key_size) *reg_max_key = cs_data->max_key_size; if (*reg_max_blk < cs_data->blk_size) *reg_max_blk = cs_data->blk_size; } op_gvname(VARLSTCNT(1) &gl_ptr->name); if (restrict_reg) { /* Only select globals in specified regions */ append_gbl = FALSE; for (rptr = grlist; NULL != rptr; rptr = rptr->fPtr) { if (gv_cur_region == rptr->reg) { append_gbl = TRUE; break; } } } if (append_gbl) { gl_tail->next = gl_ptr; gl_tail = gl_ptr; } else free(gl_ptr); op_gvorder(&curr_gbl_name); if (0 == curr_gbl_name.str.len) { (gmap_ptr + 1)->addr = 0; break; } assert('^' == *curr_gbl_name.str.addr); curr_gbl_name.str.addr++; curr_gbl_name.str.len--; } } if (gmap_ptr_base != &gmap[0]) free(gmap_ptr_base); } fis-gtm-V6.0-003/sr_port/gv_select.h0000644000032200000250000000131012201176157016153 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GV_SELECT_INCLUDED #define GV_SELECT_INCLUDED void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist *gl_head, int *reg_max_rec, int *reg_max_key, int *reg_max_blk, boolean_t restrict_reg); #endif /* GV_SELECT_INCLUDED */ fis-gtm-V6.0-003/sr_port/gv_trigger_common.h0000644000032200000250000000611512201176157017717 0ustar librarygtc/**************************************************************** * * * Copyright 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef _GV_TRIGGER_COMMON_INCLUDED #define _GV_TRIGGER_COMMON_INCLUDED /* Following macros, though related to trigger global (^#t), are needed in trigger non-supported platforms. * While gv_trigger.h lives placed in sr_unix, VMS needs the following macros. */ #define HASHT_GBL_CHAR1 '#' #define HASHT_GBL_CHAR2 't' #define HASHT_GBLNAME "#t" #define HASHT_FULL_GBLNAME "^#t" #define HASHT_GBLNAME_LEN STR_LIT_LEN(HASHT_GBLNAME) #define HASHT_FULL_GBLNM_LEN STR_LIT_LEN(HASHT_FULL_GBLNAME) #define HASHT_GBLNAME_FULL_LEN STR_LIT_LEN(HASHT_GBLNAME) + 1 /* including terminating '\0' subscript */ /* This macro assumes addr points to a gv_currkey like subscript representation (with potential subscripts) */ #define IS_GVKEY_HASHT_GBLNAME(LEN, ADDR) ((HASHT_GBLNAME_LEN <= LEN) \ && (KEY_DELIMITER == ADDR[HASHT_GBLNAME_LEN]) \ && (HASHT_GBL_CHAR1 == ADDR[0]) \ && (HASHT_GBL_CHAR2 == ADDR[1])) /* This macro assumes addr points to an mname (i.e. unsubscripted) */ #define IS_MNAME_HASHT_GBLNAME(MNAME) ((HASHT_GBLNAME_LEN == MNAME.len) && !MEMCMP_LIT(MNAME.addr, HASHT_GBLNAME)) /* Similar to IS_GVKEY_HASHT_GBLNAME but used in places where ADDR points to ZWR formatted KEY (includes '^') */ #define IS_GVKEY_HASHT_FULL_GBLNAME(LEN, ADDR) ((HASHT_FULL_GBLNM_LEN <= LEN) \ && ('^' == ADDR[0]) \ && (HASHT_GBL_CHAR1 == ADDR[1]) \ && (HASHT_GBL_CHAR2 == ADDR[2])) #define HASHT_GBL_CURLABEL "2" /* Currently supported ^#t global format */ /* HASHT_GBL_CURLABEL values of prior trigger versions */ #define V19_HASHT_GBL_LABEL "1" /* V5.4-000 to V5.4-001 */ #define LITERAL_HASHLABEL "#LABEL" #define LITERAL_HASHCYCLE "#CYCLE" #define LITERAL_HASHCOUNT "#COUNT" #define LITERAL_CMD "CMD" #define LITERAL_GVSUBS "GVSUBS" #define LITERAL_OPTIONS "OPTIONS" #define LITERAL_DELIM "DELIM" #define LITERAL_ZDELIM "ZDELIM" #define LITERAL_PIECES "PIECES" #define LITERAL_TRIGNAME "TRIGNAME" #define LITERAL_XECUTE "XECUTE" #define LITERAL_CHSET "CHSET" #define LITERAL_HASHLABEL_LEN STR_LIT_LEN(LITERAL_HASHLABEL) #define LITERAL_HASHCYCLE_LEN STR_LIT_LEN(LITERAL_HASHCYCLE) #define LITERAL_HASHCOUNT_LEN STR_LIT_LEN(LITERAL_HASHCOUNT) #define LITERAL_CMD_LEN STR_LIT_LEN(LITERAL_CMD) #define LITERAL_GVSUBS_LEN STR_LIT_LEN(LITERAL_GVSUBS) #define LITERAL_OPTIONS_LEN STR_LIT_LEN(LITERAL_OPTIONS) #define LITERAL_DELIM_LEN STR_LIT_LEN(LITERAL_DELIM) #define LITERAL_ZDELIM_LEN STR_LIT_LEN(LITERAL_ZDELIM) #define LITERAL_PIECES_LEN STR_LIT_LEN(LITERAL_PIECES) #define LITERAL_XECUTE_LEN STR_LIT_LEN(LITERAL_XECUTE) #define LITERAL_TRIGNAME_LEN STR_LIT_LEN(LITERAL_TRIGNAME) #define LITERAL_CHSET_LEN STR_LIT_LEN(LITERAL_CHSET) #endif fis-gtm-V6.0-003/sr_port/gv_xform_key.c0000644000032200000250000000456612201176157016712 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gvsub2str.h" #include "mvalconv.h" #include "gv_xform_key.h" GBLREF int4 gv_keysize; GBLREF gv_namehead *gv_target; /* transform gv_currkey or gv_altkey based on collation sequence * if XBACK is true then convert from internal to external format. * if XBACK is false, convert from external to internal format */ void gv_xform_key(gv_key *keyp, boolean_t xback) { unsigned char *c0, *c1, *ctop; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (TREF(gv_sparekey_size) < gv_keysize) { if (TREF(gv_sparekey)) free(TREF(gv_sparekey)); else { (TREF(gv_sparekey_mval)).str.addr = (char *)malloc(MAX_ZWR_KEY_SZ); (TREF(gv_sparekey_mval)).mvtype = MV_STR; } TREF(gv_sparekey) = (gv_key *)malloc(SIZEOF(gv_key) - 1 + gv_keysize); TREF(gv_sparekey_size) = gv_keysize; } assert(keyp->top == gv_keysize); assert(keyp->end < keyp->top); memcpy(TREF(gv_sparekey), keyp, SIZEOF(gv_key) + keyp->end); c1 = keyp->base; while (*c1++) ; c0 = (TREF(gv_sparekey))->base + (c1 - keyp->base); ctop = &((TREF(gv_sparekey))->base[(TREF(gv_sparekey))->end]); if (!*c0) /* no subscipts */ { assert(c0 == ctop); return; } assert(c0 < ctop); keyp->prev = 0; keyp->end = c1 - keyp->base; for (; c0 < ctop; ) { if (STR_SUB_PREFIX != *c0) { assert(!gv_target->nct); while (*c1++ = *c0++) ; keyp->prev = keyp->end; keyp->end = c1 - keyp->base; } else { TREF(transform) = xback; (TREF(gv_sparekey_mval)).str.len = gvsub2str(c0, (unsigned char *)((TREF(gv_sparekey_mval)).str.addr), FALSE) - (unsigned char *)(TREF(gv_sparekey_mval)).str.addr; TREF(transform) = !xback; mval2subsc(TADR(gv_sparekey_mval), keyp); c1 = &keyp->base[keyp->end]; while (*c0++) ; } assert(keyp->end < keyp->top); } return; } fis-gtm-V6.0-003/sr_port/gv_xform_key.h0000644000032200000250000000106612201176157016707 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GV_XFORM_KEY_H__ #define __GV_XFORM_KEY_H__ void gv_xform_key(gv_key *keyp, boolean_t xback); #endif fis-gtm-V6.0-003/sr_port/gvcmx.h0000644000032200000250000000177112201176157015337 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2004 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GVCMX_INCLUDED #define GVCMX_INCLUDED mint gvcmx_data(void); bool gvcmx_get(mval *v); bool gvcmx_order(void); bool gvcmx_query(mval *val); bool gvcmx_reqremlk(unsigned char laflag, int4 time); bool gvcmx_resremlk(unsigned char c); bool gvcmx_zprevious(void); void gvcmx_canremlk(void); void gvcmx_kill(bool so_subtree); void gvcmx_put(mval *v); void gvcmx_increment(mval *increment, mval *result); void gvcmx_susremlk(unsigned char rmv_locks); void gvcmx_unlock(unsigned char rmv_locks, bool specific, char incr); #endif /* GVCMX_INCLUDED */ fis-gtm-V6.0-003/sr_port/gvcmy_close.h0000644000032200000250000000104512201176157016517 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GVCMY_CLOSE_H_INCLUDED #define GVCMY_CLOSE_H_INCLUDED void gvcmy_close(struct CLB *); #endif fis-gtm-V6.0-003/sr_port/gvcmy_rundown.h0000644000032200000250000000103112201176157017101 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GVCMY_RUNDOWN_H__ #define __GVCMY_RUNDOWN_H__ void gvcmy_rundown(void); #endif fis-gtm-V6.0-003/sr_port/gvcst_blk_build.c0000644000032200000250000002272612201176157017346 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gdsblk.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdscc.h" #include "gdskill.h" #include "filestruct.h" #include "copy.h" #include "jnl.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "gvcst_blk_build.h" #include "gtmimagename.h" #ifdef DEBUG GBLREF boolean_t skip_block_chain_tail_check; #endif GBLREF unsigned char cw_set_depth; GBLREF uint4 dollar_tlevel; GBLREF sgm_info *sgm_info_ptr; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF boolean_t write_after_image; GBLREF unsigned int t_tries; #ifdef UNIX GBLREF jnl_gbls_t jgbl; #endif void gvcst_blk_build(cw_set_element *cse, sm_uc_ptr_t base_addr, trans_num ctn) { blk_segment *seg, *stop_ptr, *array; off_chain chain; sm_uc_ptr_t ptr, ptrtop; sm_ulong_t n; int4 offset; trans_num blktn; # ifdef DEBUG boolean_t integ_error_found; rec_hdr_ptr_t rp; sm_uc_ptr_t chainptr, input_base_addr; unsigned short nRecLen; # endif DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; /* For a TP transaction we should reach here with crit as the only function that invokes this is bg_update_phase2 * which operates outside crit. The exceptions to this are DSE (write_after_image is TRUE) or ONLINE ROLLBACK * which holds crit for the entire duration */ assert((dba_bg != cs_data->acc_meth) || dollar_tlevel || !cs_addrs->now_crit || write_after_image UNIX_ONLY(|| jgbl.onlnrlbk)); assert((dba_mm != cs_data->acc_meth) || dollar_tlevel || cs_addrs->now_crit); assert(cse->mode != gds_t_writemap); array = (blk_segment *)cse->upd_addr; assert(array->len >= SIZEOF(blk_hdr)); assert(array->len <= cs_data->blk_size); assert((cse->ins_off + SIZEOF(block_id)) <= array->len); assert((short)cse->index >= 0); assert(!cse->undo_next_off[0] && !cse->undo_offset[0]); assert(!cse->undo_next_off[1] && !cse->undo_offset[1]); DEBUG_ONLY(input_base_addr = base_addr;) if (base_addr == NULL) { /* it's the first private TP build */ assert(dollar_tlevel); assert(cse->blk_target); base_addr = cse->new_buff = (unsigned char *)get_new_free_element(sgm_info_ptr->new_buff_list); cse->first_copy = TRUE; } else assert(0 == ((sm_ulong_t)base_addr & 3)); /* word aligned at least */ /* The block-transaction-number is modified before the contents of the block are modified. This is * done so as to allow a cdb_sc_blkmod check (done in t_qread, gvcst_search, gvcst_put and tp_hist) * to be done out-of-crit by just checking for the transaction numbers. If the contents of the block * were modified first, there is a possibility that the block-transaction number didn't get updated * although the contents of the block may have changed and basing the decision of block-modified on * just the transaction numbers may not always be correct. * Note that in mm_update and bg_update there is an else block where instead of gvcst_blk_build(), * a memcpy is done. To effect the above change, we also need to switch the order of memcpy and * block-transaction-number-updation in those places. * Note that a similar change is not needed in gvcst_map_build() because that will never be in the * search history for any key. */ if (!ctn && dollar_tlevel) { /* Subtract one so will pass concurrency control for mm databases. * This block is guaranteed to be in an earlier history from when it was first read, * so this history is superfluous for concurrency control. * The correct tn is put in the block in mm_update or bg_update when the block is copied to the database. */ ctn = cs_addrs->ti->curr_tn - 1; } /* Assert that the block's transaction number is LESS than the transaction number corresponding to the blk build. * i.e. no one else should have touched the block contents in shared memory from the time we locked this in phase1 * to the time we build it in phase2. * There are a few exceptions. * a) With DSE, it is possible to change the block transaction number and then a DSE or MUPIP command can run * on the above block with the above condition not true. * b) tp_tend calls gvcst_blk_build for cse's with mode kill_t_write/kill_t_create. For them we build a private * copy of the block for later use in phase2 of the M-kill. In this case, blktn could be * uninitialized so cannot do any checks using this value. * c) For MM, we dont have two phase commits so dont do any checks in that case. * d) For acquired blocks, it is possible that some process had read in the uninitialized block from disk * outside of crit (due to concurrency issues). Therefore the buffer could contain garbage. So we cannot * rely on the buffer contents to determine the block's transaction number. * e) For VMS, if a twin is created, we explicitly set its buffer tn to be equal to ctn in phase1. * But since we are not passed the "cr" in this routine, it is not easily possible to check that. * Hence in case of VMS, we relax the check so buffertn == ctn is allowed. */ DEBUG_ONLY(blktn = ((blk_hdr_ptr_t)base_addr)->tn); assert(!IS_MCODE_RUNNING || !cs_addrs->t_commit_crit || (dba_bg != cs_data->acc_meth) || (n_gds_t_op < cse->mode) || (cse->mode == gds_t_acquired) || (blktn UNIX_ONLY(<) VMS_ONLY(<=) ctn)); assert((ctn < cs_addrs->ti->early_tn) || write_after_image); ((blk_hdr_ptr_t)base_addr)->bver = GDSVCURR; ((blk_hdr_ptr_t)base_addr)->tn = ctn; ((blk_hdr_ptr_t)base_addr)->bsiz = UINTCAST(array->len); ((blk_hdr_ptr_t)base_addr)->levl = cse->level; if (cse->forward_process) { stop_ptr = (blk_segment *)array->addr; seg = cse->first_copy ? array + 1: array + 2; ptr = base_addr + SIZEOF(blk_hdr); if (!cse->first_copy) ptr += ((blk_segment *)(array + 1))->len; for ( ; seg <= stop_ptr; ) { assert(0L <= ((INTPTR_T)seg->len)); DBG_BG_PHASE2_CHECK_CR_IS_PINNED(cs_addrs, seg); memmove(ptr, seg->addr, seg->len); ptr += seg->len; seg++; } } else { stop_ptr = cse->first_copy ? array : array + 1; seg = (blk_segment *)array->addr; ptr = base_addr + array->len; while (seg != stop_ptr) { assert(0L <= ((INTPTR_T)seg->len)); DBG_BG_PHASE2_CHECK_CR_IS_PINNED(cs_addrs, seg); ptr -= (n = seg->len); memmove(ptr, seg->addr, n); seg--; } } if (dollar_tlevel) { if (cse->ins_off) { /* if the cw set has a reference to resolve, move it to the block */ assert(cse->index < sgm_info_ptr->cw_set_depth); assert((int)cse->ins_off >= (int)(SIZEOF(blk_hdr) + SIZEOF(rec_hdr))); assert((int)(cse->next_off + cse->ins_off + SIZEOF(block_id)) <= array->len); if (cse->first_off == 0) cse->first_off = cse->ins_off; chain.flag = 1; chain.cw_index = cse->index; chain.next_off = cse->next_off; ptr = base_addr + cse->ins_off; GET_LONGP(ptr, &chain); cse->index = 0; cse->ins_off = 0; cse->next_off = 0; } # ifdef DEBUG if (offset = cse->first_off) { /* Verify the integrity of the TP chains within a newly created block. * If it is the first TP private build, the update array could have referenced * shared memory global buffers which could have been concurrently updated. * So the integrity of the chain cannot be easily verified. If ever we find * an integ error in the chain, we check if this is the first private TP build * and if so allow it but set a debug flag donot_commit so we never ever commit * this transaction. The hope is that it will instead restart after validation. */ ptr = base_addr; ptrtop = ptr + ((blk_hdr_ptr_t)ptr)->bsiz; chainptr = ptr + offset; ptr += SIZEOF(blk_hdr); integ_error_found = FALSE; for ( ; ptr < ptrtop; ) { do { GET_USHORT(nRecLen, &((rec_hdr_ptr_t)ptr)->rsiz); if (0 == nRecLen) { assert(NULL == input_base_addr); integ_error_found = TRUE; break; } ptr += nRecLen; if (ptr - SIZEOF(off_chain) == chainptr) break; if ((ptr - SIZEOF(off_chain)) > chainptr) { assert(NULL == input_base_addr); integ_error_found = TRUE; break; } GET_LONGP(&chain, ptr - SIZEOF(off_chain)); if (chain.flag) { assert(NULL == input_base_addr); integ_error_found = TRUE; break; } } while (ptr < ptrtop); if (integ_error_found) break; if (chainptr < ptrtop) { GET_LONGP(&chain, chainptr); assert(1 == chain.flag || (skip_block_chain_tail_check && (0 == chain.next_off))); assert(chain.cw_index < sgm_info_ptr->cw_set_depth); offset = chain.next_off; if (0 == offset) chainptr = ptrtop; else { chainptr = chainptr + offset; assert(chainptr < ptrtop); /* ensure we have not overrun the buffer */ } } } if (integ_error_found) TREF(donot_commit) |= DONOTCOMMIT_GVCST_BLK_BUILD_TPCHAIN; else assert(0 == offset); /* ensure the chain is NULL terminated */ } # endif } else assert(dollar_tlevel || (cse->index < (int)cw_set_depth)); } fis-gtm-V6.0-003/sr_port/gvcst_blk_build.h0000644000032200000250000000117112201176157017342 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GVCST_BLK_BUILD_INCLUDED #define GVCST_BLK_BUILD_INCLUDED void gvcst_blk_build(cw_set_element *cse, sm_uc_ptr_t base_addr, trans_num ctn); #endif /* GVCST_BLK_BUILD_INCLUDED */ fis-gtm-V6.0-003/sr_port/gvcst_blk_search.c0000644000032200000250000003142112201176157017504 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* * NOTE: See also GVCST_BLK_SEARCH.MAR for the VAX platform. * * ------------------------------------------------------------------- * Search a single gvcst block * * function definition * enum cdb_sc gvcst_search_blk(pKey,pStat) * gv_key *pKey; - target key * srch_blk_status *pStat; - status block for this buffer * * function returns cdb_sc_normal if successful; otherwise, * one of the failure codes cdb_sc_badoffset or cdb_sc_blklenerr. * * function definition * enum cdb_sc gvcst_search_tail(pKey,pStat,pOldKey) * gv_key *pKey; - target key * srch_blk_status *pStat; - status block for this buffer * gv_key *pOldKey; - key for status block * * gvcst_search_tail is identical to gvcst_search_blk, * except instead of starting with the beginning * of the block, it starts where the previous gvcst_search_blk * left off, using the srch_blk_status to set-up. * * if successful, fills in srch_blk_status as follows: * * --------------------------------- * | Block number (untouched) | * --------------------------------- * | Buffer address (input param) | * --------------------------------- * | Transaction number (untouched)| * --------------------------------- * | match | offset | previous record * --------------------------------- * | match | offset | current record * --------------------------------- * * if the match is not found, or is found at the top or bottom of the * block, then the values of the return fields are as follows: * * PREVIOUS REC CURRENT REC * CONDITION MATCH OFFSET MATCH OFFSET * --------- ---- ------ ----- ------ * Buffer empty 0 0 0 7 * Hit first key in block 0 0 a 7 * Hit star key b c 0 x * Hit last key (leaf) b c a x * Went past last key (leaf) b x 0 y * * where: * a = size of target key * b = number of characters which match on the previous * key (including those which have been compressed away) * c = offset of previous record * x = offset for last record in the block * y = top of buffer (same as block bsize) * * * Block structure * block : * blk_hdr : * blk_data : record...record * record : [rec_data] * rec_hdr : * rec_data : [byte...byte] * ------------------------------------------------------------------- */ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "copy.h" #include "cdb_sc.h" #include "gvcst_protos.h" /* for gvcst_search_tail,gvcst_search_blk prototype */ #include "send_msg.h" GBLREF unsigned int t_tries; GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; error_def(ERR_TEXT); #ifdef DEBUG #include "gdscc.h" #define DBG_CHECK_SRCH_HIST_AND_CSE_BUFFER_MATCH(pStat) \ { \ GBLREF uint4 dollar_tlevel; \ \ srch_blk_status *tp_srch_status; \ cw_set_element *cse; \ \ if (dollar_tlevel) \ { \ tp_srch_status = pStat->first_tp_srch_status; \ if (NULL != tp_srch_status) \ { \ cse = tp_srch_status->cse; \ if (NULL != cse) \ assert(cse->new_buff == pStat->buffaddr); \ } \ } \ } #else #define DBG_CHECK_SRCH_HIST_AND_CSE_BUFFER_MATCH(pStat) #endif #define INVOKE_GVCST_SEARCH_FAIL_IF_NEEDED(pStat) if (CDB_STAGNATE <= t_tries) gvcst_search_fail(pStat); static void gvcst_search_fail(srch_blk_status *pStat) { char buff[1024], crbuff[256], regbuff[512]; assert(CDB_STAGNATE <= t_tries); assert((NULL != pStat) && ((NULL != pStat->cr) || (dba_mm == gv_cur_region->dyn.addr->acc_meth)) && (NULL != cs_addrs)); if (NULL != pStat) { if (NULL != pStat->cr) SPRINTF(crbuff, ": crbuff = 0x%lX", pStat->cr->buffaddr); else crbuff[0] = '\0'; memcpy(regbuff, gv_cur_region->rname, gv_cur_region->rname_len); regbuff[gv_cur_region->rname_len] = '\0'; SPRINTF(buff, "Possible data corruption in region %s : blk = 0x%X : buff = 0x%lX : cr = 0x%lX %s : " "csa = 0x%lX : csalock = 0x%lX", regbuff, pStat->blk_num, (long unsigned int) pStat->buffaddr, (long unsigned int) pStat->cr, crbuff, (long unsigned int) cs_addrs, (long unsigned int) cs_addrs->lock_addrs[0]); send_msg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_STR(buff)); } } /* * -------------------------------------------------- * Search for a key in the block * * Return: * cdb_sc_normal - success * cdb_sc_badoffset - record with 0 length encountered, * possibly a corrupt block * cdb_sc_blklenerr - end of block reached without match * -------------------------------------------------- */ enum cdb_sc gvcst_search_blk (gv_key *pKey, srch_blk_status *pStat) { /* register variables named in perceived order of declining impact */ register int nFlg, nTargLen, nMatchCnt, nTmp; sm_uc_ptr_t pBlkBase, pRecBase, pTop, pRec, pPrevRec; unsigned char *pCurrTarg, *pTargKeyBase; unsigned short nRecLen; int tmp_cmpc; /* the following load code (and code in a few other places) is coded in a "assember" style * in an attempt to encourage the compiler to get it efficient; * if instance, memory and non-memory instructions are interlaced to encourge pipelining. * of course a great compiler doesn't need help, but this is portable code and ... */ DBG_CHECK_SRCH_HIST_AND_CSE_BUFFER_MATCH(pStat); pBlkBase = pStat->buffaddr; pRecBase = pBlkBase; pTop = pBlkBase + ((blk_hdr_ptr_t)pBlkBase)->bsiz; nRecLen = SIZEOF(blk_hdr); pCurrTarg = pKey->base; nMatchCnt = 0; nTargLen = (int)pKey->end; pTargKeyBase = pCurrTarg; nTargLen++; /* for the terminating NUL on the key */ for (;;) { pRec = pRecBase + nRecLen; if (pRec >= pTop) { /* Terminated at end of block */ if (pRec > pTop) /* If record goes off the end, then block must be bad */ { INVOKE_GVCST_SEARCH_FAIL_IF_NEEDED(pStat); assert(CDB_STAGNATE > t_tries); return cdb_sc_blklenerr; } nTargLen = 0; if (((blk_hdr_ptr_t)pBlkBase)->levl == 0) { /* data block */ pPrevRec = pRecBase; pRecBase = pRec; } else nMatchCnt = 0; /* star key */ break; } GET_USHORT(nRecLen, &((rec_hdr_ptr_t)pRec)->rsiz); if (nRecLen == 0) /* If record length is 0, then block must be bad */ { INVOKE_GVCST_SEARCH_FAIL_IF_NEEDED(pStat); assert(CDB_STAGNATE > t_tries); return cdb_sc_badoffset; } pPrevRec = pRecBase; pRecBase = pRec; /* If current compression count > last match, then this record also matches on 'last match' characters; keep looping */ EVAL_CMPC2((rec_hdr_ptr_t)pRec, nTmp) if (nTmp > nMatchCnt) continue; if (nTmp < nMatchCnt) { /* Terminate on compression count < previous match, this key is after the target */ if (nRecLen == BSTAR_REC_SIZE && ((blk_hdr_ptr_t)pBlkBase)->levl != 0) /* Star key has size of SIZEOF(rec_hdr) + SIZEOF(block_id), make match = 0 */ nTargLen = 0; else /* Data block, make match = current compression count */ nTargLen = nTmp; break; } /* Compression count == match count; Compare current target with current record */ pRec += SIZEOF(rec_hdr); do { if ((nFlg = *pCurrTarg - *pRec++) != 0) break; pCurrTarg++; } while ( --nTargLen); if (nFlg > 0) nMatchCnt =(int)(pCurrTarg - pTargKeyBase); else { /* Key is after target*/ if (nRecLen == BSTAR_REC_SIZE && (((blk_hdr_ptr_t)pBlkBase)->levl != 0)) /* Star key has size of SIZEOF(rec_hdr) + SIZEOF(block_id), make match = 0 */ nTargLen = 0; else nTargLen = (int)(pCurrTarg - pTargKeyBase); break; } } pStat->prev_rec.offset = (short)(pPrevRec - pBlkBase); pStat->prev_rec.match = (short)nMatchCnt; pStat->curr_rec.offset = (short)(pRecBase - pBlkBase); pStat->curr_rec.match = (short)nTargLen; return cdb_sc_normal; } /* search_tail is the "start anywhere" version of search_blk getting started is a bit awkward, so excuse the gotos */ enum cdb_sc gvcst_search_tail (gv_key *pKey, srch_blk_status *pStat, gv_key *pOldKey) { /* register variables named in perceived order of declining impact */ register int nFlg, nTargLen, nMatchCnt, nTmp; sm_uc_ptr_t pBlkBase, pRecBase, pRec, pTop, pPrevRec; unsigned char *pCurrTarg, *pTargKeyBase, *pOldKeyBase, *pCurrTargPos; unsigned short nRecLen; int tmp_cmpc; /* see comment in gvcst_search_blk above on coding style */ if (pStat->prev_rec.offset == 0) return gvcst_search_blk(pKey, pStat); /* nice clean start at the begining of a block */ DBG_CHECK_SRCH_HIST_AND_CSE_BUFFER_MATCH(pStat); pBlkBase = pStat->buffaddr; pRecBase = pBlkBase + pStat->curr_rec.offset; pRec = pRecBase; pTop = pBlkBase + ((blk_hdr_ptr_t)pBlkBase)->bsiz; nMatchCnt = pStat->prev_rec.match; pCurrTarg = pKey->base; pTargKeyBase = pCurrTarg; pOldKeyBase = pOldKey->base; pPrevRec = pBlkBase + pStat->prev_rec.offset; nTargLen = pKey->end; nTargLen++; /* for the NUL that terminates the key */ if (pRec >= pTop) { /* Terminated at end of block */ /* eob_tail: */ if (pRec > pTop) { INVOKE_GVCST_SEARCH_FAIL_IF_NEEDED(pStat); assert(CDB_STAGNATE > t_tries); return cdb_sc_blklenerr; } if ((nTargLen = nMatchCnt) != 0) { do { if (*pCurrTarg++ != *pOldKeyBase++) break; } while (--nTargLen); } if (((blk_hdr_ptr_t)pBlkBase)->levl != 0) nMatchCnt = 0; /* star key */ else nMatchCnt -= nTargLen; nTargLen = 0; } else { GET_USHORT(nRecLen, &((rec_hdr_ptr_t)pRec)->rsiz); EVAL_CMPC2((rec_hdr_ptr_t)pRec, nTmp); nFlg = nTmp; if (nFlg != 0) { do { if ((nFlg = *pCurrTarg - *pOldKeyBase++) != 0) break; pCurrTarg++; } while (--nTmp); if (nFlg > 0) { nMatchCnt = (int)(pCurrTarg - pTargKeyBase); nTargLen -= nMatchCnt; } if (nFlg < 0) { nTargLen += (int)(pTargKeyBase - pCurrTarg); goto match_term; } } if (nFlg == 0) { nTmp = nMatchCnt; nMatchCnt = (int)(pCurrTarg - pTargKeyBase); nTargLen -= nMatchCnt; nTmp -= nMatchCnt; if (nTmp > 0) { pCurrTargPos = pCurrTarg; do { if (*pCurrTargPos++ != *pOldKeyBase++) break; nMatchCnt++; } while (--nTmp); } goto alt_loop_entry; } for (;;) { pRec = pRecBase + nRecLen; if (pRec >= pTop) { /* Terminated at end of block */ if (pRec > pTop) /* If record goes off the end, then block must be bad */ { INVOKE_GVCST_SEARCH_FAIL_IF_NEEDED(pStat); assert(CDB_STAGNATE > t_tries); return cdb_sc_blklenerr; } nTargLen = 0; if (((blk_hdr_ptr_t)pBlkBase)->levl == 0) { /* data block */ pPrevRec = pRecBase; pRecBase = pRec; } else nMatchCnt = 0; /* star key */ break; } GET_USHORT(nRecLen, &((rec_hdr_ptr_t)pRec)->rsiz); if (nRecLen == 0) /* If record length is 0, then block must be bad */ { INVOKE_GVCST_SEARCH_FAIL_IF_NEEDED(pStat); assert(CDB_STAGNATE > t_tries); return cdb_sc_badoffset; } pPrevRec = pRecBase; pRecBase = pRec; /* If current compression count > last match, then this record also matches on 'last match' characters; keep looping */ EVAL_CMPC2((rec_hdr_ptr_t)pRec, nTmp); if (nTmp > nMatchCnt) continue; if (nTmp < nMatchCnt) /* cc_term: */ { /* Terminated on compression count < previous match, this key is after the target */ if (nRecLen == BSTAR_REC_SIZE && ((blk_hdr_ptr_t)pBlkBase)->levl != 0) /* Star key has size of SIZEOF(rec_hdr) + SIZEOF(block_id), make match = 0 */ nTargLen = 0; else /* Data block, make match = current compression count */ nTargLen = nTmp; break; } alt_loop_entry: /* Compression count == match count; Compare current target with current record */ pRec += SIZEOF(rec_hdr); do { if ((nFlg = *pCurrTarg - *pRec++) != 0) break; pCurrTarg++; } while (--nTargLen); if (nFlg > 0) nMatchCnt = (int)(pCurrTarg - pTargKeyBase); else match_term: { /* Key is after target*/ if (nRecLen == BSTAR_REC_SIZE && (((blk_hdr_ptr_t)pBlkBase)->levl != 0)) /* Star key has size of SIZEOF(rec_hdr) + SIZEOF(block_id), make match = 0 */ nTargLen = 0; else nTargLen = (int)(pCurrTarg - pTargKeyBase); break; } } } /* clean_up: */ pStat->prev_rec.offset = (short)(pPrevRec - pBlkBase); pStat->prev_rec.match = (short)nMatchCnt; pStat->curr_rec.offset = (short)(pRecBase - pBlkBase); pStat->curr_rec.match = (short)nTargLen; return cdb_sc_normal; } fis-gtm-V6.0-003/sr_port/gvcst_bmp_mark_free.c0000644000032200000250000003674412201176157020215 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gvcst_bmp_mark_free.c This marks all the blocks in kill set list to be marked free. Note ks must be already sorted */ #include "mdef.h" #include "gtm_string.h" #include "cdb_sc.h" #include "gdsroot.h" #include "gdskill.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gdscc.h" #include "jnl.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "memcoherency.h" #include "gdsblkops.h" /* for CHECK_AND_RESET_UPDATE_ARRAY macro */ /* Include prototypes */ #include "t_qread.h" #include "t_end.h" #include "t_retry.h" #include "t_begin.h" #include "t_write_map.h" #include "mm_read.h" #include "add_inter.h" #include "gvcst_bmp_mark_free.h" #include "t_busy2free.h" #include "t_abort.h" #ifdef UNIX #include "db_snapshot.h" #endif #include "muextr.h" #include "mupip_reorg.h" GBLREF char *update_array, *update_array_ptr; GBLREF cw_set_element cw_set[]; GBLREF unsigned char cw_set_depth; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF unsigned char rdfail_detail; GBLREF sgm_info *sgm_info_ptr; GBLREF boolean_t mu_reorg_process; GBLREF inctn_opcode_t inctn_opcode; GBLREF inctn_detail_t inctn_detail; /* holds detail to fill in to inctn jnl record */ GBLREF uint4 dollar_tlevel; #ifdef UNIX GBLREF unsigned int t_tries; GBLREF unsigned char t_fail_hist[CDB_MAX_TRIES]; #endif GBLREF gd_region *gv_cur_region; error_def(ERR_GVKILLFAIL); error_def(ERR_IGNBMPMRKFREE); trans_num gvcst_bmp_mark_free(kill_set *ks) { block_id bit_map, next_bm, *updptr; blk_ident *blk, *blk_top, *nextblk; trans_num ctn, start_db_fmt_tn; unsigned int len; # if defined(UNIX) && defined(DEBUG) unsigned int lcl_t_tries; # endif int4 blk_prev_version; srch_hist alt_hist; trans_num ret_tn = 0; boolean_t visit_blks; srch_blk_status bmphist; cache_rec_ptr_t cr; enum db_ver ondsk_blkver; enum cdb_sc status; boolean_t mark_level_as_special; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; TREF(in_gvcst_bmp_mark_free) = TRUE; assert(inctn_bmp_mark_free_gtm == inctn_opcode || inctn_bmp_mark_free_mu_reorg == inctn_opcode); /* Note down the desired_db_format_tn before you start relying on cs_data->fully_upgraded. * If the db is fully_upgraded, take the optimal path that does not need to read each block being freed. * But in order to detect concurrent desired_db_format changes, note down the tn (when the last format change occurred) * before the fully_upgraded check and after having noted down the database current_tn. * If they are the same, then we are guaranteed no concurrent desired_db_format change occurred. * If they are not, then fall through to the non-optimal path where each to-be-killed block has to be visited. * The reason we need to visit every block in case desired_db_format changes is to take care of the case where * MUPIP REORG DOWNGRADE concurrently changes a block that we are about to free. */ start_db_fmt_tn = cs_data->desired_db_format_tn; visit_blks = (!cs_data->fully_upgraded); /* Local evaluation */ assert(!visit_blks || (visit_blks && dba_bg == cs_addrs->hdr->acc_meth)); /* must have blks_to_upgrd == 0 for non-BG */ assert(!dollar_tlevel); /* Should NOT be in TP now */ blk = &ks->blk[0]; blk_top = &ks->blk[ks->used]; if (!visit_blks) { /* Database has been completely upgraded. Free all blocks in one bitmap as part of one transaction. */ assert(cs_data->db_got_to_v5_once); /* assert all V4 fmt blocks (including RECYCLED) have space for V5 upgrade */ inctn_detail.blknum_struct.blknum = 0; /* to indicate no adjustment to "blks_to_upgrd" necessary */ /* If any of the mini transaction below restarts because of an online rollback, we don't want the application * refresh to happen (like $ZONLNRLBK++ or rts_error(DBROLLEDBACK). This is because, although we are currently in {BYPASSOK} * non-tp (dollar_tleve = 0), we could actually be in a TP transaction and have actually faked dollar_tlevel. In * such a case, we should NOT * be issuing a DBROLLEDBACK error as TP transactions are supposed to just restart in * case of an online rollback. So, set the global variable that gtm_onln_rlbk_clnup can check and skip doing the * application refresh, but will reset the clues. The next update will see the cycle mismatch and will accordingly * take the right action. */ for ( ; blk < blk_top; blk = nextblk) { if (0 != blk->flag) { nextblk = blk + 1; continue; } assert(0 < blk->block); assert((int4)blk->block < cs_addrs->ti->total_blks); bit_map = ROUND_DOWN2((int)blk->block, BLKS_PER_LMAP); next_bm = bit_map + BLKS_PER_LMAP; CHECK_AND_RESET_UPDATE_ARRAY; /* reset update_array_ptr to update_array */ /* Scan for the next local bitmap */ updptr = (block_id *)update_array_ptr; for (nextblk = blk; (0 == nextblk->flag) && (nextblk < blk_top) && ((block_id)nextblk->block < next_bm); ++nextblk) { assert((block_id)nextblk->block - bit_map); *updptr++ = (block_id)nextblk->block - bit_map; } len = (unsigned int)((char *)nextblk - (char *)blk); update_array_ptr = (char *)updptr; alt_hist.h[0].blk_num = 0; /* need for calls to T_END for bitmaps */ alt_hist.h[0].blk_target = NULL; /* need to initialize for calls to T_END */ /* the following assumes SIZEOF(blk_ident) == SIZEOF(int) */ assert(SIZEOF(blk_ident) == SIZEOF(int)); *(int *)update_array_ptr = 0; t_begin(ERR_GVKILLFAIL, UPDTRNS_DB_UPDATED_MASK); for (;;) { ctn = cs_addrs->ti->curr_tn; /* Need a read fence before reading fields from cs_data as we are reading outside * of crit and relying on this value to detect desired db format state change. */ SHM_READ_MEMORY_BARRIER; if (start_db_fmt_tn != cs_data->desired_db_format_tn) { /* Concurrent db format change has occurred. Need to visit every block to be killed * to determine its block format. Fall through to the non-optimal path below */ ret_tn = 0; break; } # ifdef GTM_SNAPSHOT /* if this is freeing a level-0 directory tree block, we need to transition the block to free * right away and write its before-image thereby enabling fast integ to avoid writing level-0 * block before-images altogether. It is possible the fast integ hasn't started at this stage, * so we cannot use FASTINTEG_IN_PROG in the if condition, but fast integ may already start later * at bg/mm update stage, so we always need to prepare cw_set element */ if ((MUSWP_FREE_BLK == TREF(in_mu_swap_root_state)) && blk->level) { /* blk->level was set as 1 for level-0 DIR tree block in mu_swap_root */ /* for mu_swap_root, only one block is freed during bmp_mark_free */ assert(1 == ks->used); ctn = cs_addrs->ti->curr_tn; alt_hist.h[0].cse = NULL; alt_hist.h[0].tn = ctn; alt_hist.h[0].blk_num = blk->block; alt_hist.h[1].blk_num = 0; /* this is to terminate history reading in t_end */ if (NULL == (alt_hist.h[0].buffaddr = t_qread(alt_hist.h[0].blk_num, (sm_int_ptr_t)&alt_hist.h[0].cycle, &alt_hist.h[0].cr))) { t_retry((enum cdb_sc)rdfail_detail); continue; } t_busy2free(&alt_hist.h[0]); /* The special level value will be used later in t_end to indicate * before_image of this block will be written to snapshot file */ cw_set[cw_set_depth-1].level = CSE_LEVEL_DRT_LVL0_FREE; mark_level_as_special = TRUE; } else mark_level_as_special = FALSE; # endif bmphist.blk_num = bit_map; if (NULL == (bmphist.buffaddr = t_qread(bmphist.blk_num, (sm_int_ptr_t)&bmphist.cycle, &bmphist.cr))) { t_retry((enum cdb_sc)rdfail_detail); continue; } t_write_map(&bmphist, (uchar_ptr_t)update_array, ctn, -(int4)(nextblk - blk)); # ifdef GTM_SNAPSHOT if (mark_level_as_special) { /* The special level value will be used later in gvcst_map_build to set the block to be * freed as free rather than recycled */ cw_set[cw_set_depth-1].level = CSE_LEVEL_DRT_LVL0_FREE; } # endif UNIX_ONLY(DEBUG_ONLY(lcl_t_tries = t_tries)); if ((trans_num)0 == (ret_tn = t_end(&alt_hist, NULL, TN_NOT_SPECIFIED))) { # ifdef UNIX assert((CDB_STAGNATE == t_tries) || (lcl_t_tries == t_tries - 1)); status = LAST_RESTART_CODE; if ((cdb_sc_onln_rlbk1 == status) || (cdb_sc_onln_rlbk2 == status) || TREF(rlbk_during_redo_root)) { /* t_end restarted due to online rollback. Discard bitmap free-up and return control * to the application. But, before that reset only_reset_clues_if_onln_rlbk to FALSE */ TREF(in_gvcst_bmp_mark_free) = FALSE; send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_IGNBMPMRKFREE, 4, REG_LEN_STR(gv_cur_region), DB_LEN_STR(gv_cur_region)); t_abort(gv_cur_region, cs_addrs); return ret_tn; /* actually 0 */ } # endif continue; } break; } if (0 == ret_tn) /* db format change occurred. Fall through to below for loop to visit each block */ { /* Abort any active transaction to get rid of lingering Non-TP artifacts */ t_abort(gv_cur_region, cs_addrs); break; } } } /* for all blocks in the kill_set */ for ( ; blk < blk_top; blk++) { /* Database has NOT been completely upgraded. Have to read every block that is going to be freed * and determine whether it has been upgraded or not. Every block will be freed as part of one * separate update to the bitmap. This will cause as many transactions as the blocks are being freed. * But this overhead will be present only as long as the database is not completely upgraded. * The reason why every block is updated separately is in order to accurately maintain the "blks_to_upgrd" * counter in the database file-header when the block-freeup phase (2nd phase) of the M-kill proceeds * concurrently with a MUPIP REORG UPGRADE/DOWNGRADE. If the bitmap is not updated for every block freeup * then MUPIP REORG UPGRADE/DOWNGRADE should also upgrade/downgrade all blocks in one bitmap as part of * one transaction (only then will we avoid double-decrement of "blks_to_upgrd" counter by the M-kill as * well as the MUPIP REORG UPGRADE/DOWNGRADE). That is a non-trivial task as potentially 512 blocks need * to be modified as part of one non-TP transaction which is unnecessarily making it heavyweight. Compared * to that, incurring a per-block bitmap update overhead in the M-kill is considered acceptable since this * will be the case only as long as we are in compatibility mode which should be hopefully not for long. */ if (0 != blk->flag) continue; assert(0 < blk->block); assert((int4)blk->block < cs_addrs->ti->total_blks); assert(!IS_BITMAP_BLK(blk->block)); bit_map = ROUND_DOWN2((int)blk->block, BLKS_PER_LMAP); assert(dba_bg == cs_addrs->hdr->acc_meth); /* We need to check each block we are deleting to see if it is in the format of a previous version. * If it is, then "csd->blks_to_upgrd" needs to be correspondingly adjusted. */ alt_hist.h[0].level = 0; /* Initialize for loop below */ alt_hist.h[1].blk_num = 0; alt_hist.h[0].blk_target = NULL; /* need to initialize for calls to T_END */ CHECK_AND_RESET_UPDATE_ARRAY; /* reset update_array_ptr to update_array */ assert((block_id)blk->block - bit_map); assert(SIZEOF(block_id) == SIZEOF(blk_ident)); *((block_id *)update_array_ptr) = ((block_id)blk->block - bit_map); update_array_ptr += SIZEOF(blk_ident); /* the following assumes SIZEOF(blk_ident) == SIZEOF(int) */ assert(SIZEOF(blk_ident) == SIZEOF(int)); *(int *)update_array_ptr = 0; t_begin(ERR_GVKILLFAIL, UPDTRNS_DB_UPDATED_MASK); for (;;) { ctn = cs_addrs->ti->curr_tn; alt_hist.h[0].cse = NULL; alt_hist.h[0].tn = ctn; alt_hist.h[0].blk_num = blk->block; if (NULL == (alt_hist.h[0].buffaddr = t_qread(alt_hist.h[0].blk_num, (sm_int_ptr_t)&alt_hist.h[0].cycle, &alt_hist.h[0].cr))) { t_retry((enum cdb_sc)rdfail_detail); continue; } /* IF csd->db_got_to_v5_once is FALSE * a) mark the block as FREE (not RECYCLED to avoid confusing MUPIP REORG UPGRADE with a * block that was RECYCLED right at the time of MUPIP UPGRADE from a V4 to V5 version). * MUPIP REORG UPGRADE will mark all existing RECYCLED blocks as FREE. * b) need to write PBLK * ELSE * a) mark this block as RECYCLED * b) no need to write PBLK (it will be written when the block later gets reused). * ENDIF * * Create a cw-set-element with mode gds_t_busy2free that will cause a PBLK to be written in t_end * (the value csd->db_got_to_v5_once will be checked while holding crit) only in the IF case above. * At the same time bg_update will NOT be invoked for this cw-set-element so this block will not be * touched. But the corresponding bitmap block will be updated as part of the same transaction (see * t_write_map below) to mark this block as FREE or RECYCLED depending on whether csd->db_got_to_v5_once * is FALSE or TRUE (actual check done in gvcst_map_build and sec_shr_map_build). */ t_busy2free(&alt_hist.h[0]); cr = alt_hist.h[0].cr; ondsk_blkver = cr->ondsk_blkver; /* Get local copy in case cr->ondsk_blkver changes between * first and second part of the || */ assert((GDSV6 == ondsk_blkver) || (GDSV4 == ondsk_blkver)); if (GDSVCURR != ondsk_blkver) inctn_detail.blknum_struct.blknum = blk->block; else inctn_detail.blknum_struct.blknum = 0; /* i.e. no adjustment to "blks_to_upgrd" necessary */ bmphist.blk_num = bit_map; if (NULL == (bmphist.buffaddr = t_qread(bmphist.blk_num, (sm_int_ptr_t)&bmphist.cycle, &bmphist.cr))) { t_retry((enum cdb_sc)rdfail_detail); continue; } t_write_map(&bmphist, (uchar_ptr_t)update_array, ctn, -1); # ifdef GTM_SNAPSHOT if ((MUSWP_FREE_BLK == TREF(in_mu_swap_root_state)) && blk->level) { assert(1 == ks->used); cw_set[cw_set_depth-1].level = CSE_LEVEL_DRT_LVL0_FREE; /* special level for gvcst_map_build */ cw_set[cw_set_depth-2].level = CSE_LEVEL_DRT_LVL0_FREE; /* special level for t_end */ /* Here we do not need to do BIT_SET_DIR_TREE because later the block will be always written to * snapshot file without checking whether it belongs to DIR or GV tree */ } # endif UNIX_ONLY(DEBUG_ONLY(lcl_t_tries = t_tries)); if ((trans_num)0 == (ret_tn = t_end(&alt_hist, NULL, TN_NOT_SPECIFIED))) { # ifdef UNIX assert((CDB_STAGNATE == t_tries) || (lcl_t_tries == t_tries - 1)); assert(0 < t_tries); DEBUG_ONLY(status = LAST_RESTART_CODE); /* get the recent restart code */ /* We don't expect online rollback related retries because we are here with the database NOT fully * upgraded. This means, online rollback cannot even start (it issues ORLBKNOV4BLK). Assert that. */ assert((cdb_sc_onln_rlbk1 != status) && (cdb_sc_onln_rlbk2 != status)); # endif continue; } break; } } /* for all blocks in the kill_set */ TREF(in_gvcst_bmp_mark_free) = FALSE; return ret_tn; } fis-gtm-V6.0-003/sr_port/gvcst_bmp_mark_free.h0000644000032200000250000000317712201176157020214 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GVCST_BMP_MARK_FREE_INCLUDED #define GVCST_BMP_MARK_FREE_INCLUDED trans_num gvcst_bmp_mark_free(kill_set *ks); #define GVCST_BMP_MARK_FREE(ks, ret_tn, cur_inctn_opcode, new_inctn_opcode, inctn_opcode, cs_addrs) \ { /* inctn_opcode is set already by callers (TP/non-TP/reorg) and is not expected to change. save it \ * before modifying it. actually, the following save and reset of inctn_opcode (done before and after the \ * call to gvcst_bmp_mark_free()) needs to be done only if JNL_ENABLED(cs_addrs), but since it is not \ * easy to re-execute the save and reset of inctn_opcode in case t_end() detects a cdb_sc_jnlstatemod \ * retry code, we choose the easier approach of doing the save and reset unconditionally even though this \ * approach has an overhead of doing a few assignments even though inctn_opcode might not be used in t_end \ * (in case JNL_ENABLED is not TRUE at t_end() time). \ */ \ assert(inctn_opcode == cur_inctn_opcode); \ inctn_opcode = new_inctn_opcode; \ ret_tn = gvcst_bmp_mark_free(ks); \ inctn_opcode = cur_inctn_opcode; /* restore inctn_opcode */ \ } #endif /* GVCST_BMP_MARK_FREE_INCLUDED */ fis-gtm-V6.0-003/sr_port/gvcst_data.c0000644000032200000250000001400612201176157016320 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "cdb_sc.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "copy.h" #include "filestruct.h" /* needed for jnl.h */ #include "gdscc.h" /* needed for tp.h */ #include "jnl.h" /* needed for tp.h */ #include "gdskill.h" /* needed for tp.h */ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* needed for T_BEGIN_READ_NONTP_OR_TP macro */ #ifdef UNIX /* needed for frame_pointer in GVCST_ROOT_SEARCH_AND_PREP macro */ # include "repl_msg.h" # include "gtmsource.h" # include "rtnhdr.h" # include "stack_frame.h" # include "wbox_test_init.h" #endif #include "t_end.h" /* prototypes */ #include "t_retry.h" #include "t_begin.h" #include "gvcst_protos.h" /* for gvcst_rtsib,gvcst_search,gvcst_search_blk,gvcst_data prototype */ /* needed for spanning nodes */ #include "op.h" #include "op_tcommit.h" #include "error.h" #include "tp_frame.h" #include "tp_restart.h" #include "gtmimagename.h" LITREF mval literal_batch; GBLREF gv_key *gv_currkey, *gv_altkey; GBLREF gv_namehead *gv_target; GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF uint4 dollar_tlevel; GBLREF unsigned int t_tries; error_def(ERR_DBROLLEDBACK); error_def(ERR_GVDATAFAIL); error_def(ERR_TPRETRY); DEFINE_NSB_CONDITION_HANDLER(gvcst_data_ch) mint gvcst_data(void) { bool found, sn_tpwrapped; boolean_t est_first_pass; int oldend; mint val; int save_dollar_tlevel; DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); val = gvcst_data2(); # ifdef UNIX if (-1 != val) { assert(save_dollar_tlevel == dollar_tlevel); return val; } oldend = gv_currkey->end; if (!dollar_tlevel) { sn_tpwrapped = TRUE; op_tstart((IMPLICIT_TSTART), TRUE, &literal_batch, 0); ESTABLISH_NORET(gvcst_data_ch, est_first_pass); GVCST_ROOT_SEARCH_AND_PREP(est_first_pass); } else sn_tpwrapped = FALSE; /* fix up since it should only be externally counted as one $data */ INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_data, (gtm_uint64_t) -1); val = gvcst_data2(); if (-1 == val) { /* -1 implies node exists. Need to see if a proper descendant exists */ val = 1; /* 0 1 0 0 <-- append that to gv_currkey */ gv_currkey->end = oldend + 2; gv_currkey->base[oldend + 0] = 1; gv_currkey->base[oldend + 1] = 0; gv_currkey->base[oldend + 2] = 0; found = gvcst_query(); /* want to save gv_altkey? */ if (found && (0 == memcmp(gv_currkey->base, gv_altkey->base, oldend))) val += 10; } if (sn_tpwrapped) { op_tcommit(); REVERT; /* remove our condition handler */ } RESTORE_CURRKEY(gv_currkey, oldend); assert(save_dollar_tlevel == dollar_tlevel); # endif return val; } mint gvcst_data2(void) { blk_hdr_ptr_t bp; boolean_t do_rtsib, is_dummy; enum cdb_sc status; mint val; rec_hdr_ptr_t rp; unsigned short match, rsiz; srch_blk_status *bh; srch_hist *rt_history; sm_uc_ptr_t b_top; int tmp_cmpc; int data_len, cur_val_offset, realval = 0; VMS_ONLY(assert((gv_target->root < cs_addrs->ti->total_blks) || dollar_tlevel)); T_BEGIN_READ_NONTP_OR_TP(ERR_GVDATAFAIL); assert(t_tries < CDB_STAGNATE || cs_addrs->now_crit); /* we better hold crit in the final retry (TP & non-TP) */ for (;;) { /* The following code is duplicated in gvcst_dataget. Any changes here might need to be reflected there as well */ rt_history = gv_target->alt_hist; rt_history->h[0].blk_num = 0; #if defined(DEBUG) && defined(UNIX) if (gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_GVDATAFAIL == gtm_white_box_test_case_number)) { t_retry(cdb_sc_blknumerr); continue; } #endif if (cdb_sc_normal != (status = gvcst_search(gv_currkey, NULL))) { t_retry(status); continue; } bh = gv_target->hist.h; bp = (blk_hdr_ptr_t)bh->buffaddr; rp = (rec_hdr_ptr_t)(bh->buffaddr + bh->curr_rec.offset); b_top = bh->buffaddr + bp->bsiz; match = bh->curr_rec.match; do_rtsib = FALSE; realval = 0; if (gv_currkey->end + 1 == match) { val = 1; GET_USHORT(rsiz, &rp->rsiz); # ifdef UNIX /* check for spanning node dummy value: a single zero byte */ cur_val_offset = SIZEOF(rec_hdr) + match - EVAL_CMPC((rec_hdr_ptr_t)rp); data_len = rsiz - cur_val_offset; is_dummy = IS_SN_DUMMY(data_len, (sm_uc_ptr_t)rp + cur_val_offset); if (is_dummy) { realval = -1; IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(realval = 0); /* resume since this is not a spanning node */ } # endif rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)rp + rsiz); if ((sm_uc_ptr_t)rp > b_top) { t_retry(cdb_sc_rmisalign); continue; } else if ((sm_uc_ptr_t)rp == b_top) do_rtsib = TRUE; else if (EVAL_CMPC(rp) >= gv_currkey->end) val += 10; } else if (match >= gv_currkey->end) val = 10; else { val = 0; if (rp == (rec_hdr_ptr_t)b_top) do_rtsib = TRUE; } if (do_rtsib && (cdb_sc_endtree != (status = gvcst_rtsib(rt_history, 0)))) { if ((cdb_sc_normal != status) || (cdb_sc_normal != (status = gvcst_search_blk(gv_currkey, rt_history->h)))) { t_retry(status); continue; } if (rt_history->h[0].curr_rec.match >= gv_currkey->end) { assert(1 >= val); val += 10; } } if (!dollar_tlevel) { if ((trans_num)0 == t_end(&gv_target->hist, 0 == rt_history->h[0].blk_num ? NULL : rt_history, TN_NOT_SPECIFIED)) continue; } else { status = tp_hist(0 == rt_history->h[0].blk_num ? NULL : rt_history); if (cdb_sc_normal != status) { t_retry(status); continue; } } INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_data, 1); return (0 != realval) ? realval : val; } } fis-gtm-V6.0-003/sr_port/gvcst_dataget.c0000644000032200000250000002353012201176157017022 0ustar librarygtc/**************************************************************** * * * Copyright 2010, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "stringpool.h" #include "cdb_sc.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "copy.h" #include "filestruct.h" /* needed for jnl.h */ #include "gdscc.h" /* needed for tp.h */ #include "jnl.h" /* needed for tp.h */ #include "gdskill.h" /* needed for tp.h */ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* needed for T_BEGIN_READ_NONTP_OR_TP macro */ #include "t_end.h" /* prototypes */ #include "t_retry.h" #include "t_begin.h" #include "gvcst_protos.h" /* for gvcst_rtsib,gvcst_search,gvcst_search_blk,gvcst_data prototype */ /* needed for spanning nodes */ #include "op.h" #include "op_tcommit.h" #include "error.h" #include "tp_frame.h" #include "tp_restart.h" #include "gtmimagename.h" LITREF mstr nsb_dummy; GBLREF gv_key *gv_currkey; GBLREF gv_namehead *gv_target; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF gd_region *gv_cur_region; GBLREF uint4 dollar_tlevel; GBLREF unsigned int t_tries; GBLREF uint4 t_err; error_def(ERR_GVDATAGETFAIL); error_def(ERR_GVKILLFAIL); error_def(ERR_GVPUTFAIL); enum cdb_sc gvcst_dataget(mint *dollar_data, mval *val) { boolean_t gotit, gotspan, gotpiece, gotdummy, sn_tpwrapped, check_rtsib; mint dollar_data_ctrl, dollar_data_piece, dollar_data_null, dg_info; mval val_ctrl, val_piece; int gblsize, chunk_size, i, total_len, oldend, tmp_numsubs; unsigned short numsubs; sm_uc_ptr_t sn_ptr; enum cdb_sc status; int save_dollar_tlevel; dg_info = *dollar_data; assert((DG_GETONLY == dg_info) || (DG_DATAGET == dg_info)); DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); assert(dollar_tlevel); if (cdb_sc_normal != (status = gvcst_dataget2(dollar_data, val, NULL))) { assert(save_dollar_tlevel == dollar_tlevel); return status; } # ifdef UNIX gotit = *dollar_data % 10; if (gotit && IS_SN_DUMMY(val->str.len, val->str.addr)) { /* We just found a dummy nodelet. Need to look for chunks of spanning node */ IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(return status); oldend = gv_currkey->end; APPEND_HIDDEN_SUB(gv_currkey); /* Search for control subscript */ dollar_data_ctrl = dg_info; if (cdb_sc_normal != (status = gvcst_dataget2(&dollar_data_ctrl, &val_ctrl, NULL))) { RESTORE_CURRKEY(gv_currkey, oldend); assert(save_dollar_tlevel == dollar_tlevel); return status; } gotspan = dollar_data_ctrl % 10; if (gotspan) { /* Spanning node indeed, as expected. Piece it together. Recompute dollar_data. */ if (val_ctrl.str.len == 6) { GET_NSBCTRL(val_ctrl.str.addr, numsubs, gblsize); } else { SSCANF(val_ctrl.str.addr, "%d,%d", &tmp_numsubs, &gblsize); numsubs = tmp_numsubs; } ENSURE_STP_FREE_SPACE(gblsize + cs_addrs->hdr->blk_size); /* give leeway.. think about more */ DBG_MARK_STRINGPOOL_UNUSABLE; sn_ptr = stringpool.free; total_len = 0; val->str.addr = (char *)sn_ptr; for (i = 0; i < numsubs; i++) { NEXT_HIDDEN_SUB(gv_currkey, i); /* We only need to do a rtsib on the last chunk. Only there can we check for descendants */ check_rtsib = (((i + 1) == numsubs) && (DG_DATAGET == dg_info)); dollar_data_piece = (check_rtsib) ? DG_GETSNDATA : DG_GETONLY; if (cdb_sc_normal != (status = gvcst_dataget2(&dollar_data_piece, &val_piece, sn_ptr))) { RESTORE_CURRKEY(gv_currkey, oldend); DBG_MARK_STRINGPOOL_USABLE; assert(save_dollar_tlevel == dollar_tlevel); return status; } gotpiece = dollar_data_piece % 10; if (gotpiece) { sn_ptr += val_piece.str.len; total_len += val_piece.str.len; } assert(total_len < (gblsize + cs_addrs->hdr->blk_size)); if (!gotpiece || (total_len > gblsize)) break; } if ((total_len != gblsize) || (i != numsubs)) { /* Fetched value either too small or too big compared to what control subscript says */ RESTORE_CURRKEY(gv_currkey, oldend); DBG_MARK_STRINGPOOL_USABLE; assert(save_dollar_tlevel == dollar_tlevel); return cdb_sc_spansize; } assert(val->mvtype == MV_STR); val->str.len = gblsize; stringpool.free += gblsize; DBG_MARK_STRINGPOOL_USABLE; if (check_rtsib) { *dollar_data = dollar_data_piece; if ((11 != dollar_data_piece) && cs_data->std_null_coll) { /* Check for a null-subscripted descendant. Append null sub to gv_currkey and check $data */ RESTORE_CURRKEY(gv_currkey, oldend); gv_currkey->end = oldend + 2; gv_currkey->base[oldend + 0] = 1; gv_currkey->base[oldend + 1] = 0; gv_currkey->base[oldend + 2] = 0; dollar_data_null = DG_DATAONLY; gvcst_dataget2(&dollar_data_null, &val_piece, NULL); if (dollar_data_null) *dollar_data = 11; /* Child found */ RESTORE_CURRKEY(gv_currkey, oldend); } } } RESTORE_CURRKEY(gv_currkey, oldend); } if (DG_GETONLY == dg_info) *dollar_data = (mint)gotit; /* Just return 1 if it exists and 0 if it doesn't */ assert(save_dollar_tlevel == dollar_tlevel); # endif return status; } /* This function is the equivalent of invoking gvcst_data & gvcst_get at the same time. * One crucial difference is that this function does NOT handle restarts by automatically invoking t_retry. * Instead, it returns the restart code to the caller so that it can handle the restart accordingly. * This is important in the case of triggers because we do NOT want to call t_retry in case of a implicit tstart * wrapped gvcst_put or gvcst_kill trigger-invoking update transaction. Additionally, this function assumes * that it is called always inside of TP (i.e. dollar_tlevel is non-zero). */ enum cdb_sc gvcst_dataget2(mint *dollar_data, mval *val, unsigned char *sn_ptr) { blk_hdr_ptr_t bp; boolean_t do_rtsib; enum cdb_sc status; mint dlr_data, dg2_info; rec_hdr_ptr_t rp; unsigned short match, rsiz; srch_blk_status *bh; srch_hist *rt_history; sm_uc_ptr_t b_top; int key_size, data_len, delta; uint4 save_t_err; /* The following code is lifted from gvcst_data. Any changes here might need to be reflected there as well */ assert(dollar_tlevel); assert((CDB_STAGNATE > t_tries) || cs_addrs->now_crit); /* we better hold crit in the final retry (TP & non-TP) */ save_t_err = t_err; assert((ERR_GVKILLFAIL == save_t_err) || (ERR_GVPUTFAIL == save_t_err)); /* called only from gvcst_kill and gvcst_put */ t_err = ERR_GVDATAGETFAIL; /* switch t_err to reflect dataget sub-operation (under the KILL operation) */ /* In case of a failure return, it is ok to return with t_err set to ERR_GVDATAGETFAIL as that gives a better * picture of exactly where in the transaction the failure occurred. */ dg2_info = *dollar_data; assert((DG_GETONLY == dg2_info) || (DG_DATAGET == dg2_info) || (DG_DATAONLY == dg2_info) || (DG_GETSNDATA == dg2_info)); delta = (DG_GETSNDATA == dg2_info) ? 4 : 0; /* next key doesn't need to match hidden subscript */ rt_history = gv_target->alt_hist; rt_history->h[0].blk_num = 0; if (cdb_sc_normal != (status = gvcst_search(gv_currkey, NULL))) return status; bh = gv_target->hist.h; bp = (blk_hdr_ptr_t)bh->buffaddr; rp = (rec_hdr_ptr_t)(bh->buffaddr + bh->curr_rec.offset); b_top = bh->buffaddr + bp->bsiz; match = bh->curr_rec.match; key_size = gv_currkey->end + 1; do_rtsib = FALSE; /* Even if key does not exist, return null string in "val". Caller can use dollar_data to distinguish * whether the key is undefined or defined and set to the null string. */ val->mvtype = MV_STR; val->str.len = 0; if (key_size == match) { dlr_data = 1; /* the following code is lifted from gvcst_get. any changes here might need to be reflected there as well */ GET_USHORT(rsiz, &rp->rsiz); data_len = rsiz + EVAL_CMPC(rp) - SIZEOF(rec_hdr) - key_size; if ((0 > data_len) || ((sm_uc_ptr_t)rp + rsiz > b_top)) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_rmisalign1; return status; } else if (DG_DATAONLY != dg2_info) { val->str.len = data_len; if (!sn_ptr) { ENSURE_STP_FREE_SPACE(data_len); memcpy(stringpool.free, (sm_uc_ptr_t)rp + rsiz - data_len, data_len); val->str.addr = (char *)stringpool.free; stringpool.free += data_len; } else { memcpy(sn_ptr, (sm_uc_ptr_t)rp + rsiz - data_len, data_len); val->str.addr = (char *)sn_ptr; } } /* --------------------- end code lifted from gvcst_get ---------------------------- */ rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)rp + rsiz); if ((sm_uc_ptr_t)rp > b_top) { status = cdb_sc_rmisalign; return status; } else if ((sm_uc_ptr_t)rp == b_top) do_rtsib = TRUE; else if (EVAL_CMPC(rp) + delta >= gv_currkey->end) dlr_data += 10; } else if (match + delta >= gv_currkey->end) dlr_data = 10; else { dlr_data = 0; if (rp == (rec_hdr_ptr_t)b_top) do_rtsib = TRUE; } if ((DG_GETONLY != dg2_info) && do_rtsib && (cdb_sc_endtree != (status = gvcst_rtsib(rt_history, 0)))) { /* only do rtsib and search_blk if full data information is desired */ if ((cdb_sc_normal != status) || (cdb_sc_normal != (status = gvcst_search_blk(gv_currkey, rt_history->h)))) return status; if (rt_history->h[0].curr_rec.match + delta >= gv_currkey->end) { assert(1 >= dlr_data); dlr_data += 10; } } status = tp_hist(0 == rt_history->h[0].blk_num ? NULL : rt_history); if (cdb_sc_normal != status) return status; *dollar_data = (DG_GETONLY != dg2_info) ? dlr_data : (dlr_data % 10); t_err = save_t_err; /* restore t_err to what it was at function entry */ return status; } fis-gtm-V6.0-003/sr_port/gvcst_delete_blk.c0000644000032200000250000001327512201176157017510 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gdskill.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdscc.h" #include "copy.h" #include "filestruct.h" #include "jnl.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "gvcst_blk_build.h" #include "gvcst_delete_blk.h" GBLREF kill_set *kill_set_tail; GBLREF sgm_info *sgm_info_ptr; GBLREF uint4 dollar_tlevel; GBLREF gv_namehead *gv_target; GBLREF boolean_t horiz_growth; GBLREF sgmnt_addrs *cs_addrs; GBLREF unsigned int t_tries; #ifdef VMS GBLREF boolean_t tp_has_kill_t_cse; /* cse->mode of kill_t_write or kill_t_create got created in this transaction */ #endif void gvcst_delete_blk(block_id blk, int level, boolean_t committed) { cw_set_element *cse, *old_cse; kill_set *ks; off_chain chain; srch_blk_status *tp_srch_status; uint4 iter; ht_ent_int4 *tabent; DEBUG_ONLY( boolean_t block_already_in_hist = FALSE; ) DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; horiz_growth = FALSE; if (!dollar_tlevel) ks = kill_set_tail; else { PUT_LONG(&chain, blk); tp_srch_status = NULL; if (chain.flag == 1) tp_get_cw(sgm_info_ptr->first_cw_set, (int)chain.cw_index, &cse); else { if (NULL != (tabent = lookup_hashtab_int4(sgm_info_ptr->blks_in_use, (uint4 *)&blk))) tp_srch_status = (srch_blk_status *)tabent->value; cse = tp_srch_status ? tp_srch_status->cse : NULL; } if (cse) { if (!committed) { assert(dollar_tlevel >= cse->t_level); if (NULL != cse->high_tlevel) { /* this is possible only if this block is already part of either of the tree paths * in gv_target->hist or alt_hist (see gvcst_kill.c) and got a newer cse created as * part of a gvcst_kill_blk on this block in gvcst_kill.c a little before the call * to gvcst_kill_blk of a parent block which in turn decided to delete this block * as part of its records that are getting removed. this is a guaranteed restartable * situation. since gvcst_delete_blk does not return any status, proceed with the * newer cse and return. the restart will be later detected by tp_hist. */ cse = cse->high_tlevel; DEBUG_ONLY(TREF(donot_commit) |= DONOTCOMMIT_GVCST_DELETE_BLK_CSE_TLEVEL;) DEBUG_ONLY(block_already_in_hist = TRUE;) } assert(!cse->high_tlevel); if (cse->t_level != dollar_tlevel) { /* this part of the code is almost similar to that in t_write(), * any changes in one should be reflected in the other */ horiz_growth = TRUE; old_cse = cse; cse = (cw_set_element *)get_new_free_element(sgm_info_ptr->tlvl_cw_set_list); memcpy(cse, old_cse, SIZEOF(cw_set_element)); cse->low_tlevel = old_cse; cse->high_tlevel = NULL; old_cse->high_tlevel = cse; cse->t_level = dollar_tlevel; assert(2 == (SIZEOF(cse->undo_offset) / SIZEOF(cse->undo_offset[0]))); assert(2 == (SIZEOF(cse->undo_next_off) / SIZEOF(cse->undo_next_off[0]))); for (iter = 0; iter < 2; iter++) cse->undo_next_off[iter] = cse->undo_offset[iter] = 0; if (old_cse->done) { assert(NULL != old_cse->new_buff); cse->new_buff = (unsigned char *)get_new_free_element(sgm_info_ptr->new_buff_list); memcpy(cse->new_buff, old_cse->new_buff, ((blk_hdr_ptr_t)old_cse->new_buff)->bsiz); } else cse->new_buff = NULL; assert(!block_already_in_hist); /* tp_hist (called from gvcst_kill) updates "->cse" fields for all blocks that are * part of the left or right histories of the M-kill. But this block is not one of * those. Hence tp_srch_status->cse has to be updated here explicitly. */ if (tp_srch_status) tp_srch_status->cse = (void *)cse; } switch (cse->mode) { case gds_t_create: cse->mode = kill_t_create; VMS_ONLY(tp_has_kill_t_cse = TRUE;) if (level == 0) return; break; case gds_t_write: cse->mode = kill_t_write; VMS_ONLY(tp_has_kill_t_cse = TRUE;) break; default: ; } } else { switch(cse->mode) { case kill_t_create: VMS_ONLY(assert(tp_has_kill_t_cse)); if (level == 0) return; break; default: if (chain.flag) { chain.flag = 0; blk = cse->blk; } break; } } } ks = sgm_info_ptr->kill_set_tail; if (NULL == ks) /* Allocate first kill set to sgm_info_ptr block */ { ks = sgm_info_ptr->kill_set_tail = sgm_info_ptr->kill_set_head = (kill_set *)malloc(SIZEOF(kill_set)); ks->used = 0; ks->next_kill_set = NULL; } } while (ks->used >= BLKS_IN_KILL_SET) { if (ks->next_kill_set == NULL) { ks->next_kill_set = (kill_set *)malloc(SIZEOF(kill_set)); ks->next_kill_set->used = 0; ks->next_kill_set->next_kill_set = NULL; } ks = kill_set_tail = ks->next_kill_set; } ks->blk[ks->used].level = (level) ? 1 : 0; if (!dollar_tlevel || !chain.flag) { assert((CDB_STAGNATE > t_tries) || (blk < cs_addrs->ti->total_blks)); ks->blk[ks->used].block = blk; ks->blk[ks->used].flag = 0; } else { ks->blk[ks->used].block = chain.cw_index; ks->blk[ks->used].flag = chain.flag; } ++ks->used; assert(ks->used <= BLKS_IN_KILL_SET); } fis-gtm-V6.0-003/sr_port/gvcst_delete_blk.h0000644000032200000250000000116012201176157017503 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GVCST_DELETE_BLK_INCLUDED #define GVCST_DELETE_BLK_INCLUDED void gvcst_delete_blk(block_id blk, int level, boolean_t committed); #endif /* GVCST_DELETE_BLK_INCLUDED */ fis-gtm-V6.0-003/sr_port/gvcst_expand_any_key.c0000644000032200000250000001220112201176157020400 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* ------------------------------------------------------------------------- gvcst_expand_any_key.c Expands key in a block. It can expands a *-key too. Given block base and record top of the key to be expanded, this will expand the key. Result is placed in expanded_key. Can expand *=key too. ------------------------------------------------------------------------- */ #include "mdef.h" #include "gtm_string.h" #include "cdb_sc.h" #include "gdsroot.h" #include "gdskill.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "copy.h" #include "mu_reorg.h" #include "filestruct.h" /* for struct RAB type recognition by C compiler before prototype usage in muextr.h */ #include "muextr.h" /* Include prototypes */ #include "t_qread.h" #include "mupip_reorg.h" GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF gv_namehead *gv_target; GBLREF unsigned int t_tries; GBLREF unsigned char rdfail_detail; /******************************************************************************************* Input Parameter: blk_base = Block's base which has the key rec_top = record top of the record which will be expanded Output Parameter: expanded_key = expanded key rec_size = last record size whic has the key keylen = key size keycmpc = key compression cound hist_ptr = history of blocks read, while expanding a *-key History excludes the working block from which key is expanded and includes the blocks read below the current block to expand a *-key NOTE: hist_ptr.depth will be unchanged Return: cdb_sc_normal on success failure code on concurrency failure *******************************************************************************************/ enum cdb_sc gvcst_expand_any_key (sm_uc_ptr_t blk_base, sm_uc_ptr_t rec_top, sm_uc_ptr_t expanded_key, int *rec_size, int *keylen, int *keycmpc, srch_hist *hist_ptr) { enum cdb_sc status; unsigned char expanded_star_key[MAX_KEY_SZ]; unsigned short temp_ushort; int cur_level; int star_keycmpc; int star_keylen; int star_rec_size; int tblk_size; block_id tblk_num; sm_uc_ptr_t rPtr1, rPtr2, curptr; cur_level = ((blk_hdr_ptr_t)blk_base)->levl; curptr = blk_base + SIZEOF(blk_hdr); *rec_size = *keycmpc = *keylen = 0; while (curptr < rec_top) { GET_RSIZ(*rec_size, curptr); if (0 == cur_level || BSTAR_REC_SIZE != *rec_size) { READ_RECORD(status, rec_size, keycmpc, keylen, expanded_key, cur_level, blk_base, curptr); if (cdb_sc_normal != status) { assert(t_tries < CDB_STAGNATE); return status; } else { curptr += *rec_size; if (curptr >= rec_top) break; } } else /* a star record in index block */ { if (curptr + *rec_size != rec_top || NULL == hist_ptr) { assert(t_tries < CDB_STAGNATE); return cdb_sc_rmisalign; } while (0 != cur_level) { tblk_size = ((blk_hdr_ptr_t)blk_base)->bsiz; GET_LONG(tblk_num, blk_base + tblk_size - SIZEOF(block_id)); if (0 == tblk_num || cs_data->trans_hist.total_blks - 1 < tblk_num) { assert(t_tries < CDB_STAGNATE); return cdb_sc_badlvl; } cur_level--; hist_ptr->h[cur_level].tn = cs_addrs->ti->curr_tn; if (!(blk_base = t_qread(tblk_num, (sm_int_ptr_t)(&(hist_ptr->h[cur_level].cycle)), &(hist_ptr->h[cur_level].cr) ))) { assert(t_tries < CDB_STAGNATE); return (enum cdb_sc)rdfail_detail; } if (((blk_hdr_ptr_t)blk_base)->levl != cur_level) { assert(t_tries < CDB_STAGNATE); return cdb_sc_badlvl; } hist_ptr->h[cur_level].buffaddr = blk_base; hist_ptr->h[cur_level].blk_num = tblk_num; hist_ptr->h[cur_level].prev_rec.match = 0; hist_ptr->h[cur_level].prev_rec.offset = 0; hist_ptr->h[cur_level].curr_rec.match = 0; hist_ptr->h[cur_level].curr_rec.offset = 0; } tblk_size = ((blk_hdr_ptr_t)blk_base)->bsiz; /* expand *-key from right most leaf level block of the sub-tree, of which, the original block is root */ if (cdb_sc_normal != (status = (gvcst_expand_any_key(blk_base, blk_base + tblk_size, expanded_star_key, &star_rec_size, &star_keylen, &star_keycmpc, hist_ptr)))) return status; if (*keylen + *keycmpc) /* Previous key exists */ { GET_CMPC(*keycmpc, expanded_key, expanded_star_key); } memcpy(expanded_key, expanded_star_key, star_keylen + star_keycmpc); *keylen = star_keylen + star_keycmpc - *keycmpc; *rec_size = *keylen + *keycmpc + BSTAR_REC_SIZE; return cdb_sc_normal; } /* end else if *-record */ }/* end of "while" loop */ if (curptr == rec_top) { return cdb_sc_normal; } else { assert(t_tries < CDB_STAGNATE); return cdb_sc_rmisalign; } } fis-gtm-V6.0-003/sr_port/gvcst_expand_free_subtree.c0000644000032200000250000001516012201176157021422 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "cdb_sc.h" /* atleast for cdb_sc_* codes */ #include "copy.h" /* atleast for the GET_USHORT macros */ #include "gdsroot.h" /* atleast for gds_file_id used by sgmnt_data in gdsfhead.h */ #include "gdskill.h" /* atleast for the kill_set and blk_ident structures */ #include "gdsblk.h" /* atleast for the blk_hdr and rec_hdr structures */ #include "gtm_facility.h" /* atleast for gdsfhead.h */ #include "fileinfo.h" /* atleast for gdsfhead.h */ #include "gdsbt.h" /* atleast for gdsfhead.h */ #include "gdsfhead.h" /* atleast for cs_addrs, cs_data etc. */ #include "filestruct.h" /* atleast for the FILE_INFO macro */ #include "gdscc.h" /* atleast for cw_set_element in tp.h */ #include "jnl.h" /* atleast for tp.h */ #include "buddy_list.h" /* atleast for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* atleast for off_chain */ #include "t_qread.h" #include "gvcst_bmp_mark_free.h" #include "gvcst_delete_blk.h" #include "gvcst_kill_sort.h" #include "gvcst_expand_free_subtree.h" #include "rc_cpt_ops.h" #include "wcs_phase2_commit_wait.h" GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF sgm_info *sgm_info_ptr; GBLREF uint4 dollar_tlevel; GBLREF unsigned char rdfail_detail; GBLREF inctn_opcode_t inctn_opcode; error_def(ERR_GVKILLFAIL); error_def(ERR_IGNBMPMRKFREE); void gvcst_expand_free_subtree(kill_set *ks_head) { blk_hdr_ptr_t bp; blk_ident *ksb; block_id blk; boolean_t flush_cache = FALSE, was_crit; cache_rec_ptr_t cr; int cnt, cycle; int4 kill_error, temp_long; kill_set *ks; off_chain chain; rec_hdr_ptr_t rp, rp1, rtop; uint4 save_dollar_tlevel; sm_uc_ptr_t temp_buff; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; unsigned short temp_ushort; trans_num ret_tn; inctn_opcode_t save_inctn_opcode; bt_rec_ptr_t bt; unsigned int level; csa = cs_addrs; csd = cs_data; /* If ever the following assert is removed, "flush_cache" shouldn't be set to FALSE unconditionally as it is now */ assert(!csd->dsid); /* see related comment in gvcst_kill before the call to this routine */ temp_buff = (unsigned char *)malloc(cs_data->blk_size); for (ks = ks_head; NULL != ks; ks = ks->next_kill_set) { for (cnt = 0; cnt < ks->used; ++cnt) { ksb = &ks->blk[cnt]; if (0 != ksb->level) { if (!(was_crit = csa->now_crit)) grab_crit(gv_cur_region); # ifdef UNIX if (csa->onln_rlbk_cycle != csa->nl->onln_rlbk_cycle) { /* Concurrent online rollback. We don't want to continue with rest of the logic to add more * blocks to the kill-set and do the gvcst_bmp_mark_free. Return to the caller. Since we * haven't sync'ed the cycles, the next tranasction commit will detect the online rollback * and the restart logic will handle it appropriately. */ free(temp_buff); rel_crit(gv_cur_region); send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_IGNBMPMRKFREE, 4, REG_LEN_STR(gv_cur_region), DB_LEN_STR(gv_cur_region)); return; } # endif if (dollar_tlevel && ksb->flag) { chain.flag = 1; chain.next_off = 0; chain.cw_index = ksb->block; assert(SIZEOF(chain) == SIZEOF(blk)); blk = *(block_id *)&chain; } else blk = ksb->block; if (!(bp = (blk_hdr_ptr_t)t_qread(blk, (sm_int_ptr_t)&cycle, &cr))) { /* This should have worked because t_qread was done in crit */ free(temp_buff); rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_GVKILLFAIL, 2, 1, &rdfail_detail); } if (NULL != cr) { /* It is possible that t_qread returned a buffer from first_tp_srch_status. * In that case, t_qread does not wait for cr->in_tend to be zero since * there is no need to wait as long as all this is done inside of the TP * transaction. But the gvcst_expand_free_subtree logic is special in that it * is done AFTER the TP transaction is committed but with dollar_tlevel still * set to non-zero. So it is possible that cr->in_tend is non-zero in this case. * Hence we need to check if cr->in_tend is non-zero and if so wait for commit * to complete before scanning the block for child-block #s to free. */ if (dollar_tlevel && cr->in_tend) wcs_phase2_commit_wait(csa, cr); assert(!cr->twin || cr->bt_index); assert((NULL == (bt = bt_get(blk))) || (CR_NOTVALID == bt->cache_index) || (cr == (cache_rec_ptr_t)GDS_REL2ABS(bt->cache_index)) && (0 == cr->in_tend)); } memcpy(temp_buff, bp, bp->bsiz); if (!was_crit) rel_crit(gv_cur_region); for (rp = (rec_hdr_ptr_t)(temp_buff + SIZEOF(blk_hdr)), rtop = (rec_hdr_ptr_t)(temp_buff + ((blk_hdr_ptr_t)temp_buff)->bsiz); rp < rtop; rp = rp1) { GET_USHORT(temp_ushort, &rp->rsiz); rp1 = (rec_hdr_ptr_t)((sm_uc_ptr_t)rp + temp_ushort); if ((sm_uc_ptr_t)rp1 < (sm_uc_ptr_t)(rp + 1) + SIZEOF(block_id)) { /* This should have worked because a local copy was made while crit */ assert(FALSE); kill_error = cdb_sc_rmisalign; free(temp_buff); rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_GVKILLFAIL, 2, 1, &kill_error); } GET_LONG(temp_long, (block_id_ptr_t)((sm_uc_ptr_t)rp1 - SIZEOF(block_id))); if (dollar_tlevel) { chain = *(off_chain *)&temp_long; if ((1 == chain.flag) && ((int)chain.cw_index >= sgm_info_ptr->cw_set_depth)) { assert(sgm_info_ptr->tp_csa == cs_addrs); GTMASSERT; } assert(chain.flag || temp_long < csa->ti->total_blks); } level = ((blk_hdr_ptr_t)temp_buff)->levl; gvcst_delete_blk(temp_long, level - 1, TRUE); if ((1 == level) && !dollar_tlevel && cs_data->dsid && !flush_cache) rc_cpt_entry(temp_long); /* Invalidate single block */ } ksb->level = 0; } else { if (!dollar_tlevel && cs_data->dsid && !flush_cache) rc_cpt_entry(ksb->block); } } gvcst_kill_sort(ks); save_dollar_tlevel = dollar_tlevel; assert(1 >= dollar_tlevel); dollar_tlevel = 0; /* temporarily for gvcst_bmp_mark_free */ GVCST_BMP_MARK_FREE(ks, ret_tn, inctn_invalid_op, inctn_bmp_mark_free_gtm, inctn_opcode, csa) dollar_tlevel = save_dollar_tlevel; } free(temp_buff); } fis-gtm-V6.0-003/sr_port/gvcst_expand_free_subtree.h0000644000032200000250000000117112201176157021424 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GVCST_EXPAND_FREE_SUBTREE_INCLUDED #define GVCST_EXPAND_FREE_SUBTREE_INCLUDED void gvcst_expand_free_subtree(kill_set *ks_head); #endif /* GVCST_EXPAND_FREE_SUBTREE_INCLUDED */ fis-gtm-V6.0-003/sr_port/gvcst_expand_key.c0000644000032200000250000000425712201176157017545 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "cdb_sc.h" #include "copy.h" #include "gvcst_expand_key.h" GBLREF unsigned int t_tries; enum cdb_sc gvcst_expand_key(blk_hdr_ptr_t bp, int4 rec_top, gv_key *key) { unsigned short temp_ushort; int tmp_cmpc; int4 r_offset; rec_hdr_ptr_t rp, rtop; sm_uc_ptr_t p; unsigned char *kbase, *kend, *kprv, *ktop, last, current; assert(SIZEOF(rec_hdr) <= SIZEOF(blk_hdr)); kbase = kend = key->base; ktop = &key->base[key->top]; rp = (rec_hdr_ptr_t)bp; rtop = (rec_hdr_ptr_t)((sm_uc_ptr_t)bp + rec_top); for (r_offset = SIZEOF(blk_hdr); ; GET_USHORT(temp_ushort, &rp->rsiz), r_offset = temp_ushort) { /* WARNING: Assumes that SIZEOF(rec_hdr) <= SIZEOF(blk_hdr) */ if (r_offset < SIZEOF(rec_hdr)) { assert(CDB_STAGNATE > t_tries); return cdb_sc_r2small; } rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)rp + r_offset); if (rp > rtop) { assert(CDB_STAGNATE > t_tries); return cdb_sc_rmisalign; } current = 1; kend = kbase + EVAL_CMPC(rp); p = (sm_uc_ptr_t)(rp + 1); for (;;) { if (kend >= ktop) { assert(CDB_STAGNATE > t_tries); return cdb_sc_keyoflow; } last = current; *kend++ = current = *p++; if (last == 0) { if (current == 0) break; else kprv = kend - 1; /* start of last key */ } } if (rp == rtop) { key->end = kend - kbase - 1; key->prev = kprv - kbase; if (KEY_DELIMITER == *kbase) /* A valid key wouldn't start with a '\0' character. So the block must have been * concurrently modified. */ return cdb_sc_mkblk; return cdb_sc_normal; } kprv = kend - 1; /* start of last key */ } } fis-gtm-V6.0-003/sr_port/gvcst_expand_key.h0000644000032200000250000000116612201176157017546 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GVCST_EXPAND_KEY_INCLUDED #define GVCST_EXPAND_KEY_INCLUDED enum cdb_sc gvcst_expand_key(blk_hdr_ptr_t bp, int4 rec_top, gv_key *key); #endif /* GVCST_EXPAND_KEY_INCLUDED */ fis-gtm-V6.0-003/sr_port/gvcst_gblmod.c0000644000032200000250000001062312201176157016654 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" /* needed for jnl.h */ #include "gdscc.h" /* needed for tp.h */ #include "jnl.h" /* needed for tp.h */ #include "gdskill.h" /* needed for tp.h */ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* needed for T_BEGIN_READ_NONTP_OR_TP macro */ #include "t_end.h" /* prototypes */ #include "t_retry.h" #include "t_begin.h" #include "gvcst_protos.h" /* for gvcst_gblmod,gvcst_search prototype */ #include "copy.h" #include "gtmimagename.h" /* needed for spanning nodes */ GBLREF gv_namehead *gv_target; GBLREF gv_key *gv_currkey; GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF uint4 dollar_tlevel; GBLREF unsigned int t_tries; LITREF mstr nsb_dummy; error_def(ERR_GBLMODFAIL); bool gvcst_gblmod(mval *v) { boolean_t gblmod, is_dummy; enum cdb_sc status; int key_size, key_size2, data_len; srch_hist *alt_history; blk_hdr_ptr_t bp; rec_hdr_ptr_t rp; unsigned short match, match2, rsiz, offset_to_value, oldend; srch_blk_status *bh; sm_uc_ptr_t b_top; trans_num tn_to_compare; T_BEGIN_READ_NONTP_OR_TP(ERR_GBLMODFAIL); assert(t_tries < CDB_STAGNATE || cs_addrs->now_crit); /* we better hold crit in the final retry (TP & non-TP) */ for (;;) { gblmod = TRUE; if (cdb_sc_normal == (status = gvcst_search(gv_currkey, NULL))) { alt_history = gv_target->alt_hist; alt_history->h[0].blk_num = 0; VMS_ONLY( if (cs_addrs->hdr->resync_tn >= ((blk_hdr_ptr_t)gv_target->hist.h[0].buffaddr)->tn) gblmod = FALSE; ) # ifdef UNIX tn_to_compare = ((blk_hdr_ptr_t)gv_target->hist.h[0].buffaddr)->tn; bh = gv_target->hist.h; bp = (blk_hdr_ptr_t) bh->buffaddr; rp = (rec_hdr_ptr_t) (bh->buffaddr + bh->curr_rec.offset); b_top = bh->buffaddr + bp->bsiz; GET_USHORT(rsiz, &rp->rsiz); key_size = gv_currkey->end + 1; data_len = rsiz + EVAL_CMPC(rp) - SIZEOF(rec_hdr) - key_size; match = bh->curr_rec.match; if (key_size == match) { if ((0 > data_len) || ((sm_uc_ptr_t)rp + rsiz > b_top)) { status = cdb_sc_rmisalign1; t_retry(status); continue; } offset_to_value = SIZEOF(rec_hdr) + key_size - EVAL_CMPC(rp); /* If it could be a spanning node, i.e., has special value, then try to get tn from the * block that contains the first special subscript. Since dummy nodes always have the * same value, the tn number is not updated It s enough to do only the first piece * since all pieces of a spanning node are killed before an update is applied. */ if (IS_SN_DUMMY(data_len, (sm_uc_ptr_t)rp + offset_to_value)) { oldend = gv_currkey->end; APPEND_HIDDEN_SUB(gv_currkey); if (cdb_sc_normal == (status = gvcst_search(gv_currkey, alt_history))) { key_size2 = gv_currkey->end + 1; match = alt_history->h[0].curr_rec.match; if (key_size2 == match) tn_to_compare = ((blk_hdr_ptr_t)alt_history->h[0].buffaddr)->tn; } else { gv_currkey->end = oldend; gv_currkey->base[gv_currkey->end - 1] = KEY_DELIMITER; gv_currkey->base[gv_currkey->end] = KEY_DELIMITER; t_retry(status); continue; } gv_currkey->end = oldend; gv_currkey->base[gv_currkey->end - 1] = KEY_DELIMITER; gv_currkey->base[gv_currkey->end] = KEY_DELIMITER; } } if (cs_addrs->hdr->zqgblmod_tn > tn_to_compare) gblmod = FALSE; # endif if (!dollar_tlevel) { if ((trans_num)0 == t_end(&gv_target->hist, 0 == alt_history->h[0].blk_num ? NULL : alt_history, TN_NOT_SPECIFIED)) continue; } else { status = tp_hist(0 == alt_history->h[0].blk_num ? NULL : alt_history); if (cdb_sc_normal != status) { t_retry(status); continue; } } return gblmod; } t_retry(status); } } fis-gtm-V6.0-003/sr_port/gvcst_get.c0000644000032200000250000002042512201176157016170 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "stringpool.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "cdb_sc.h" #include "copy.h" #include "filestruct.h" /* needed for jnl.h */ #include "gdscc.h" /* needed for tp.h */ #include "jnl.h" /* needed for tp.h */ #include "gdskill.h" /* needed for tp.h */ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* needed for T_BEGIN_READ_NONTP_OR_TP macro */ #ifdef UNIX /* needed for frame_pointer in GVCST_ROOT_SEARCH_AND_PREP macro */ # include "repl_msg.h" # include "gtmsource.h" # include "rtnhdr.h" # include "stack_frame.h" # include "wbox_test_init.h" #endif #include "t_end.h" /* prototypes */ #include "t_retry.h" #include "t_begin.h" #include "gvcst_protos.h" /* for gvcst_search,gvcst_get prototype */ /* needed for spanning nodes */ #include "op.h" #include "op_tcommit.h" #include "error.h" #include "tp_frame.h" #include "tp_restart.h" #include "gtmimagename.h" LITREF mval literal_batch; LITREF mstr nsb_dummy; GBLREF gv_namehead *gv_target; GBLREF gv_key *gv_currkey; GBLREF spdesc stringpool; GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF uint4 dollar_tlevel; GBLREF unsigned int t_tries; error_def(ERR_DBROLLEDBACK); error_def(ERR_GVGETFAIL); error_def(ERR_TPRETRY); DEFINE_NSB_CONDITION_HANDLER(gvcst_get_ch) boolean_t gvcst_get(mval *v) { /* To avoid an extra function call, the outer if-check can be brought out into op_gvget (a final optimization) */ boolean_t gotit, gotspan, gotpiece, gotdummy, sn_tpwrapped; boolean_t est_first_pass; mval val_ctrl, val_piece; int gblsize, chunk_size, i, total_len, oldend, tmp_numsubs; unsigned short numsubs; sm_uc_ptr_t sn_ptr; int debug_len; int save_dollar_tlevel; DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); gotit = gvcst_get2(v, NULL); # ifdef UNIX DEBUG_ONLY(debug_len = (int)v->str.len); /* Ensure v isn't garbage pointer by actually accessing it */ if (gotit && IS_SN_DUMMY(v->str.len, v->str.addr)) { /* Start TP transaction to piece together value */ IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(return gotit); if (!dollar_tlevel) { sn_tpwrapped = TRUE; op_tstart((IMPLICIT_TSTART), TRUE, &literal_batch, 0); ESTABLISH_NORET(gvcst_get_ch, est_first_pass); GVCST_ROOT_SEARCH_AND_PREP(est_first_pass); } else sn_tpwrapped = FALSE; oldend = gv_currkey->end; /* fix up since it should only be externally counted as one get */ INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_get, (gtm_uint64_t) -1); gotdummy = gvcst_get2(v, NULL); /* Will be returned if not currently a spanning node */ APPEND_HIDDEN_SUB(gv_currkey); /* fix up since it should only be externally counted as one get */ INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_get, (gtm_uint64_t) -1); gotspan = gvcst_get2(&val_ctrl, NULL); /* Search for control subscript */ if (gotspan) { /* Spanning node indeed, as expected. Piece it together */ if (val_ctrl.str.len == 6) { GET_NSBCTRL(val_ctrl.str.addr, numsubs, gblsize); } else { /* Temporarily account for mixture of control node formats between FT04 and FT05. * Note that this only works for block sizes greater than 1000. */ SSCANF(val_ctrl.str.addr, "%d,%d", &tmp_numsubs, &gblsize); numsubs = tmp_numsubs; } ENSURE_STP_FREE_SPACE(gblsize + cs_addrs->hdr->blk_size); /* give leeway.. think about more */ sn_ptr = stringpool.free; total_len = 0; v->str.addr = (char *)sn_ptr; for (i = 0; i < numsubs; i++) { NEXT_HIDDEN_SUB(gv_currkey, i); gotpiece = gvcst_get2(&val_piece, sn_ptr); if (gotpiece) { sn_ptr += val_piece.str.len; total_len += val_piece.str.len; } assert(total_len < (gblsize + cs_addrs->hdr->blk_size)); if (!gotpiece || (total_len > gblsize)) break; } if ((total_len != gblsize) || (i != numsubs)) /* Fetched value either too small or too big compared to what control subscript says */ t_retry(cdb_sc_spansize); } RESTORE_CURRKEY(gv_currkey, oldend); if (sn_tpwrapped) { op_tcommit(); REVERT; /* remove our condition handler */ } if (gotspan) { v->mvtype = MV_STR; /*v->str.addr = (char *)stringpool.free;*/ v->str.len = gblsize; stringpool.free += gblsize; } gotit = gotspan || gotdummy; } assert(save_dollar_tlevel == dollar_tlevel); # endif return gotit; } boolean_t gvcst_get2(mval *v, unsigned char *sn_ptr) { blk_hdr_ptr_t bp; enum cdb_sc status; int key_size, data_len; int tmp_cmpc; rec_hdr_ptr_t rp; sm_uc_ptr_t b_top; srch_blk_status *bh; unsigned short rsiz; # ifdef DEBUG boolean_t in_op_gvget_lcl; # endif DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; DEBUG_ONLY( /* Store global variable in_op_gvget in a local variable and reset the global right away to ensure that the global * value does not incorrectly get carried over to the next call of gvcst_get (e.g. it if was from "op_fngvget"). */ in_op_gvget_lcl = TREF(in_op_gvget); TREF(in_op_gvget) = FALSE; ) T_BEGIN_READ_NONTP_OR_TP(ERR_GVGETFAIL); assert(t_tries < CDB_STAGNATE || cs_addrs->now_crit); /* we better hold crit in the final retry (TP & non-TP) */ for (;;) { #if defined(DEBUG) && defined(UNIX) if (gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_GVGETFAIL == gtm_white_box_test_case_number)) { status = cdb_sc_blknumerr; t_retry(status); continue; } #endif if (cdb_sc_normal == (status = gvcst_search(gv_currkey, NULL))) { bh = gv_target->hist.h; if ((key_size = gv_currkey->end + 1) == bh->curr_rec.match) { /* The following code is duplicated in gvcst_dataget. Any changes here might need * to be reflected there as well. */ bp = (blk_hdr_ptr_t)bh->buffaddr; b_top = bh->buffaddr + bp->bsiz; rp = (rec_hdr_ptr_t)(bh->buffaddr + bh->curr_rec.offset); GET_USHORT(rsiz, &rp->rsiz); data_len = rsiz + EVAL_CMPC(rp) - SIZEOF(rec_hdr) - key_size; if ((0 > data_len) || ((sm_uc_ptr_t)rp + rsiz > b_top)) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_rmisalign1; } else { if (!sn_ptr) { ENSURE_STP_FREE_SPACE(data_len); assert(stringpool.top - stringpool.free >= data_len); memcpy(stringpool.free, (sm_uc_ptr_t)rp + rsiz - data_len, data_len); } else memcpy(sn_ptr, (sm_uc_ptr_t)rp + rsiz - data_len, data_len); if (!dollar_tlevel) { if ((trans_num)0 == t_end(&gv_target->hist, NULL, TN_NOT_SPECIFIED)) continue; } else { status = tp_hist(NULL); if (cdb_sc_normal != status) { t_retry(status); continue; } } v->mvtype = MV_STR; v->str.len = data_len; if (!sn_ptr) { v->str.addr = (char *)stringpool.free; stringpool.free += data_len; INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_get, 1); } else v->str.addr = (char *)sn_ptr; return TRUE; } } else { DEBUG_ONLY(TREF(ready2signal_gvundef) = in_op_gvget_lcl;) if (!dollar_tlevel) { if ((trans_num)0 == t_end(&gv_target->hist, NULL, TN_NOT_SPECIFIED)) { assert(FALSE == TREF(ready2signal_gvundef)); /* t_end should have reset this */ continue; } } else { status = tp_hist(NULL); if (cdb_sc_normal != status) { assert(FALSE == TREF(ready2signal_gvundef)); /* tp_hist should have reset this */ t_retry(status); continue; } } assert(FALSE == TREF(ready2signal_gvundef)); /* t_end/tp_hist should have reset this up front */ INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_get, 1); return FALSE; } } t_retry(status); } } fis-gtm-V6.0-003/sr_port/gvcst_incr.c0000644000032200000250000000553612201176157016352 0ustar librarygtc/**************************************************************** * * * Copyright 2004, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" /* needed for gdsfhead.h */ #include "gdsblk.h" /* needed for gdsfhead.h */ #include "gtm_facility.h" /* needed for gdsfhead.h */ #include "fileinfo.h" /* needed for gdsfhead.h */ #include "gdsbt.h" /* needed for gdsfhead.h */ #include "gdsfhead.h" /* needed for gvcst_protos.h */ #include "gdsblkops.h" #include "filestruct.h" #include "jnl.h" #include "gdscc.h" /* needed for tp.h */ #include "gdskill.h" /* needed for tp.h */ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "mvalconv.h" /* for i2mval prototype for the MV_FORCE_MVAL macro */ #include "gvcst_protos.h" /* for gvcst_incr prototype */ GBLREF boolean_t in_gvcst_incr; GBLREF mval increment_delta_mval; GBLREF mval *post_incr_mval; GBLREF sgm_info *sgm_info_ptr; void gvcst_incr(mval *increment, mval *result) { assert(!in_gvcst_incr); assert(MV_IS_NUMERIC(increment)); /* op_gvincr or gtcmtr_increment should have done the MV_FORCE_NUM before calling */ in_gvcst_incr = TRUE; post_incr_mval = result; /* it is possible (due to some optimizations in the compiler) that both the input parameters "increment" and "result" * point to the same mval. if we pass "increment" and "result" as they are to gvcst_put, it is possible due to the code * flow that gvcst_put needs to read the value of "increment" after it is done modifying "result" (it can do this by * changing the global variable "post_incr_mval"). in this case it will read a bad value of "increment" (since it will * now be reading the modified value of "result"). therefore we do not pass them as they are. Instead, since we are * interested in only the numeric value of "increment", we take a copy of "increment" into an mval ("increment_delta_mval") * and force it to be numeric. It is the address of this mval that is passed to gvcst_put. Any changes to "post_incr_mval" * will not affect this mval so it is safe to read this anytime in gvcst_put. The mval "increment_delta_mval" is also * used in gvincr_recompute_upd_array. */ increment_delta_mval = *increment; /* Since we should be caring about just the numeric part, nullify the string part of the mval */ increment_delta_mval.str.len = 0; gvcst_put(&increment_delta_mval); assert(!in_gvcst_incr); /* should have been reset by gvcst_put */ in_gvcst_incr = FALSE; /* just in case it is not reset already by gvcst_put */ } fis-gtm-V6.0-003/sr_port/gvcst_init.c0000644000032200000250000010530212201176157016352 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include /* for offsetof macro */ #include "gtm_string.h" #include "gtm_time.h" #include "cdb_sc.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsblk.h" #include "gdskill.h" #include "gdscc.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "filestruct.h" #include "iosp.h" #include "jnl.h" #include "hashtab_int4.h" /* needed for tp.h */ #include "buddy_list.h" /* needed for tp.h */ #include "tp.h" #include "gtm_stdlib.h" /* for ATOI */ #include "cryptdef.h" #include "mlkdef.h" #include "error.h" #include "gt_timer.h" #include "gtmimagename.h" #include "trans_log_name.h" #include "gtm_logicals.h" #include "dbfilop.h" #include "set_num_additional_processors.h" #include "have_crit.h" #include "t_retry.h" #include "dpgbldir.h" #include "longset.h" /* needed for cws_insert.h */ #include "cws_insert.h" /* for CWS_INIT macro */ #include "gvcst_protos.h" /* for gvcst_init,gvcst_init_sysops,gvcst_tp_init prototype */ #include "compswap.h" #include "send_msg.h" #include "targ_alloc.h" /* for "targ_free" prototype */ #include "hashtab_mname.h" #include "process_gvt_pending_list.h" #include "gtmmsg.h" #ifdef UNIX #include "heartbeat_timer.h" #include "anticipatory_freeze.h" #include "wbox_test_init.h" #define MAX_DBINIT_RETRY 4 #endif #ifdef GTM_FD_TRACE #include "gtm_dbjnl_dupfd_check.h" #endif GBLREF gd_region *gv_cur_region, *db_init_region; GBLREF sgmnt_data_ptr_t cs_data; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_addrs *cs_addrs_list; GBLREF boolean_t gtcm_connection; GBLREF bool licensed; GBLREF int4 lkid; GBLREF char *update_array, *update_array_ptr; GBLREF uint4 update_array_size, cumul_update_array_size; GBLREF ua_list *first_ua, *curr_ua; GBLREF short crash_count; GBLREF uint4 dollar_tlevel; GBLREF jnl_format_buffer *non_tp_jfb_ptr; GBLREF boolean_t mupip_jnl_recover; GBLREF buddy_list *global_tlvl_info_list; GBLREF tp_region *tp_reg_free_list; /* Ptr to list of tp_regions that are unused */ GBLREF tp_region *tp_reg_list; /* Ptr to list of tp_regions for this transaction */ GBLREF unsigned int t_tries; GBLREF struct_jrec_tcom tcom_record; GBLREF boolean_t tp_in_use; GBLREF uint4 region_open_count; GBLREF sm_uc_ptr_t reformat_buffer; GBLREF int reformat_buffer_len; GBLREF volatile int reformat_buffer_in_use; /* used only in DEBUG mode */ GBLREF volatile int4 fast_lock_count; GBLREF gvt_container *gvt_pending_list; GBLREF boolean_t dse_running; GBLREF jnl_gbls_t jgbl; #ifdef UNIX GBLREF boolean_t pool_init; GBLREF boolean_t jnlpool_init_needed; GBLREF jnlpool_addrs jnlpool; #endif LITREF char gtm_release_name[]; LITREF int4 gtm_release_name_len; error_def(ERR_BADDBVER); error_def(ERR_DBCREINCOMP); error_def(ERR_DBFLCORRP); error_def(ERR_DBNOTGDS); error_def(ERR_DBVERPERFWARN1); error_def(ERR_DBVERPERFWARN2); error_def(ERR_MMNODYNUPGRD); error_def(ERR_REGOPENFAIL); void assert_jrec_member_offsets(void) { assert(REAL_JNL_HDR_LEN % DISK_BLOCK_SIZE == 0); assert(JNL_HDR_LEN % DISK_BLOCK_SIZE == 0); /* We currently assume that the journal file header size is aligned relative to the filesystem block size. * which is currently assumed to be a 2-power (e.g. 512 bytes, 1K, 2K, 4K etc.) but never more than 64K * (MAX_IO_BLOCK_SIZE). Given this, we keep the journal file header size at 64K for Unix and 512-byte aligned * for VMS. This way any process updating the file header will hold crit and do aligned writes. Any process * writing the journal file data (journal records) on disk will hold the qio lock and can safely do so without * ever touching the journal file header area. If ever MAX_IO_BLOCK_SIZE changes (say because some filesystem * block size changes to 128K) such that JNL_HDR_LEN is no longer aligned to that, we want to know hence this assert. */ assert(JNL_HDR_LEN % MAX_IO_BLOCK_SIZE == 0); assert(REAL_JNL_HDR_LEN == SIZEOF(jnl_file_header)); UNIX_ONLY(assert(REAL_JNL_HDR_LEN <= JNL_HDR_LEN);) VMS_ONLY(assert(REAL_JNL_HDR_LEN == JNL_HDR_LEN);) assert(JNL_HDR_LEN == JNL_FILE_FIRST_RECORD); assert(DISK_BLOCK_SIZE >= PINI_RECLEN + EPOCH_RECLEN + PFIN_RECLEN + EOF_RECLEN); assert((JNL_ALLOC_MIN * DISK_BLOCK_SIZE) > JNL_HDR_LEN); /* Following assert is for JNL_FILE_TAIL_PRESERVE macro in tp.h */ assert(PINI_RECLEN >= EPOCH_RECLEN && PINI_RECLEN >= PFIN_RECLEN && PINI_RECLEN >= EOF_RECLEN); /* jnl_string structure has a 8-bit nodeflags field and a 24-bit length field. In some cases, this is * used as a 32-bit length field (e.g. in the value part of the SET record or ZTWORMHOLE record). These * usages treat the 32-bits as a jnl_str_len_t type and access it directly. Hence the requirement that * jnl_str_len_t be the same size as 32-bits and also the same as the offset to the "text" member. * If this assert fails, all places that reference jnl_str_len_t need to be revisited. */ assert(SIZEOF(jnl_str_len_t) == SIZEOF(uint4)); assert(SIZEOF(jnl_str_len_t) == offsetof(jnl_string, text[0])); /* since time in jnl record is a uint4, and since JNL_SHORT_TIME expects time_t, we better ensure they are same. * A change in the size of time_t would mean a redesign of the fields. */ assert(SIZEOF(time_t) == GTM64_ONLY(SIZEOF(gtm_int8)) NON_GTM64_ONLY(SIZEOF(int4))); /* Make sure all jnl_seqno fields start at same offset. mur_output_record and others rely on this. */ assert(offsetof(struct_jrec_null, jnl_seqno) == offsetof(struct_jrec_upd, token_seq.jnl_seqno)); assert(offsetof(struct_jrec_null, jnl_seqno) == offsetof(struct_jrec_epoch, jnl_seqno)); assert(offsetof(struct_jrec_null, jnl_seqno) == offsetof(struct_jrec_eof, jnl_seqno)); assert(offsetof(struct_jrec_null, jnl_seqno) == offsetof(struct_jrec_tcom, token_seq.jnl_seqno)); assert(offsetof(struct_jrec_null, jnl_seqno) == offsetof(struct_jrec_ztworm, token_seq.jnl_seqno)); /* Make sure all strm_seqno fields start at same offset. Lot of modules rely on this */ assert(offsetof(struct_jrec_null, strm_seqno) == offsetof(struct_jrec_upd, strm_seqno)); assert(offsetof(struct_jrec_null, strm_seqno) == offsetof(struct_jrec_tcom, strm_seqno)); assert(offsetof(struct_jrec_null, strm_seqno) == offsetof(struct_jrec_ztworm, strm_seqno)); /* EOF and EPOCH are not included in the above asserts because they have not ONE but 16 strm_seqno values each */ assert(offsetof(struct_jrec_ztcom, token) == offsetof(struct_jrec_upd, token_seq)); /* Make sure all jnl_seqno and token fields start at 8-byte boundary */ assert(offsetof(struct_jrec_upd, token_seq.jnl_seqno) == (ROUND_UP(offsetof(struct_jrec_upd, token_seq.jnl_seqno), SIZEOF(seq_num)))); assert(offsetof(struct_jrec_tcom, token_seq.jnl_seqno) == (ROUND_UP(offsetof(struct_jrec_tcom, token_seq.jnl_seqno), SIZEOF(seq_num)))); assert(offsetof(struct_jrec_null, jnl_seqno) == (ROUND_UP(offsetof(struct_jrec_null, jnl_seqno), SIZEOF(seq_num)))); assert(offsetof(struct_jrec_epoch, jnl_seqno) == (ROUND_UP(offsetof(struct_jrec_epoch, jnl_seqno), SIZEOF(seq_num)))); assert(offsetof(struct_jrec_eof, jnl_seqno) == (ROUND_UP(offsetof(struct_jrec_eof, jnl_seqno), SIZEOF(seq_num)))); /* All fixed size records must be multiple of 8-byte */ assert(TCOM_RECLEN == (ROUND_UP(SIZEOF(struct_jrec_tcom), JNL_REC_START_BNDRY))); assert(ZTCOM_RECLEN == (ROUND_UP(SIZEOF(struct_jrec_ztcom), JNL_REC_START_BNDRY))); assert(INCTN_RECLEN == (ROUND_UP(SIZEOF(struct_jrec_inctn), JNL_REC_START_BNDRY))); assert(PINI_RECLEN == (ROUND_UP(SIZEOF(struct_jrec_pini), JNL_REC_START_BNDRY))); assert(PFIN_RECLEN == (ROUND_UP(SIZEOF(struct_jrec_pfin), JNL_REC_START_BNDRY))); assert(NULL_RECLEN == (ROUND_UP(SIZEOF(struct_jrec_null), JNL_REC_START_BNDRY))); assert(EPOCH_RECLEN == (ROUND_UP(SIZEOF(struct_jrec_epoch), JNL_REC_START_BNDRY))); assert(EOF_RECLEN == (ROUND_UP(SIZEOF(struct_jrec_eof), JNL_REC_START_BNDRY))); /* Assert following comment which is relied upon in JNL_FILE_TAIL_PRESERVE macro. * "We know PINI_RECLEN is maximum of EPOCH_RECLEN, PFIN_RECLEN, EOF_RECLEN" */ assert(PINI_RECLEN > EPOCH_RECLEN); assert(PINI_RECLEN > PFIN_RECLEN); assert(PINI_RECLEN > EOF_RECLEN); /* Assumption about the structures in code */ assert(0 == MIN_ALIGN_RECLEN % JNL_REC_START_BNDRY); assert(SIZEOF(uint4) == SIZEOF(jrec_suffix)); assert((SIZEOF(jnl_record) + MAX_LOGI_JNL_REC_SIZE + SIZEOF(jrec_suffix)) < MAX_JNL_REC_SIZE); assert((DISK_BLOCK_SIZE * JNL_DEF_ALIGNSIZE) >= MAX_JNL_REC_SIZE);/* default alignsize supports max jnl record length */ assert(MAX_MAX_NONTP_JNL_REC_SIZE <= MAX_JNL_REC_SIZE); assert(MAX_DB_BLK_SIZE < MAX_MAX_NONTP_JNL_REC_SIZE); /* Ensure a PBLK record can accommodate a full GDS block */ assert(MAX_JNL_REC_SIZE <= (1 << 24)); /* Ensure that the 24-bit length field in the journal record can accommodate the maximum journal record size */ assert(tcom_record.prefix.forwptr == tcom_record.suffix.backptr); assert(TCOM_RECLEN == tcom_record.suffix.backptr); assert(SIZEOF(token_split_t) == SIZEOF(token_build)); /* Required for TOKEN_SET macro */ } void gvcst_init(gd_region *greg) { sgmnt_addrs *csa, *prevcsa, *regcsa; sgmnt_data_ptr_t csd; # ifdef VMS char cs_data_buff[ROUND_UP(SGMNT_HDR_LEN, DISK_BLOCK_SIZE)]; sgmnt_data_ptr_t temp_cs_data; # endif uint4 segment_update_array_size; int4 bsize; boolean_t realloc_alt_buff; file_control *fc; gd_region *prev_reg, *reg_top; # ifdef DEBUG cache_rec_ptr_t cr; bt_rec_ptr_t bt; blk_ident tmp_blk; # endif mstr log_nam, trans_log_nam; char trans_buff[MAX_FN_LEN + 1]; unique_file_id *greg_fid, *reg_fid; gd_addr *addr_ptr; tp_region *tr; ua_list *tmp_ua; time_t curr_time; uint4 curr_time_uint4, next_warn_uint4; unsigned int minus1 = (unsigned)-1; enum db_acc_method greg_acc_meth; ht_ent_mname *tabent, *topent, *stayent; gv_namehead *gvt, *gvt_stay; gvnh_reg_t *gvnh_reg; hash_table_mname *table; boolean_t added, first_wasopen, onln_rlbk_cycle_mismatch = FALSE; intrpt_state_t save_intrpt_ok_state; # ifdef UNIX replpool_identifier replpool_id; unsigned int full_len; int4 db_init_retry; # endif DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; UNSUPPORTED_PLATFORM_CHECK; assert(!jgbl.forw_phase_recovery); CWS_INIT; /* initialize the cw_stagnate hash-table */ /* check the header design assumptions */ assert(SIZEOF(th_rec) == (SIZEOF(bt_rec) - SIZEOF(bt->blkque))); assert(SIZEOF(cache_rec) == (SIZEOF(cache_state_rec) + SIZEOF(cr->blkque))); DEBUG_ONLY(assert_jrec_member_offsets();) assert(MAX_DB_BLK_SIZE < (1 << NEXT_OFF_MAX_BITS)); /* Ensure a off_chain record's next_off member * can work with all possible block sizes */ set_num_additional_processors(); DEBUG_ONLY( /* Note that the "block" member in the blk_ident structure in gdskill.h has 30 bits. * Currently, the maximum number of blocks is 2**30. If ever this increases, something * has to be correspondingly done to the "block" member to increase its capacity. * The following assert checks that we always have space in the "block" member * to represent a GDS block number. */ tmp_blk.block = minus1; assert(MAXTOTALBLKS_MAX - 1 <= tmp_blk.block); ) /* TH_BLOCK is currently a hardcoded constant as basing it on the offsetof macro does not work with the VMS compiler. * Therefore assert that TH_BLOCK points to the 512-byte block where the "trans_hist" member lies in the fileheader. */ assert(DIVIDE_ROUND_UP(offsetof(sgmnt_data, trans_hist), DISK_BLOCK_SIZE) == TH_BLOCK); if ((prev_reg = dbfilopn(greg)) != greg) { if (NULL == prev_reg || (gd_region *)-1L == prev_reg) /* (gd_region *)-1 == prev_reg => cm region open attempted */ return; /* Found same database already open - prev_reg contains addr of originally openned region */ greg->dyn.addr->file_cntl = prev_reg->dyn.addr->file_cntl; memcpy(greg->dyn.addr->fname, prev_reg->dyn.addr->fname, prev_reg->dyn.addr->fname_len); greg->dyn.addr->fname_len = prev_reg->dyn.addr->fname_len; csa = (sgmnt_addrs *)&FILE_INFO(greg)->s_addrs; PROCESS_GVT_PENDING_LIST(greg, csa, gvt_pending_list); csd = csa->hdr; if (NULL == csa->gvt_hashtab) { /* Already have another region that points to the same physical database file as this one. * Since two regions point to the same physical file, start maintaining a list of all global variable * names whose gv_targets have already been allocated on behalf of the current database file. * Future targ_allocs will check this list before they allocate (to avoid duplicate allocations). */ csa->gvt_hashtab = (hash_table_mname *)malloc(SIZEOF(hash_table_mname)); init_hashtab_mname(csa->gvt_hashtab, 0, HASHTAB_NO_COMPACT, HASHTAB_NO_SPARE_TABLE); assert(1 == csa->regcnt); first_wasopen = TRUE; } else first_wasopen = FALSE; for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr)) { table = addr_ptr->tab_ptr; for (tabent = table->base, topent = tabent + table->size; tabent < topent; tabent++) { if (HTENT_VALID_MNAME(tabent, gvnh_reg_t, gvnh_reg)) { /* Check if the gvt's region is the current region. * If so add gvt's variable name into the csa hashtable. */ gvt = gvnh_reg->gvt; assert((gvnh_reg->gd_reg != greg) || (csa == gvt->gd_csa)); /* If this is the first time a was_open region is happening for this csa, then * we want to merge gv_targets from both the regions into csa->gvt_hashtab. For * all future was_open cases, we want only to add gv_targets from the was_open region. */ if (first_wasopen && (csa == gvt->gd_csa) || !first_wasopen && (gvnh_reg->gd_reg == greg)) { /* Add gv_target into csa->gvt_hashtab */ added = add_hashtab_mname(csa->gvt_hashtab, &gvt->gvname, gvt, &stayent); assert(!added || (1 <= gvt->regcnt)); if (!added) { /* Entry already present. Increment gvt->regcnt. * If NOISOLATION status differs between the two, * choose the more pessimistic one. */ gvt_stay = (gv_namehead *)stayent->value; assert(gvt_stay != gvt); if (FALSE == gvt->noisolation) gvt_stay->noisolation = FALSE; assert(1 <= gvt_stay->regcnt); /* Now make gvnh_reg->gvt point to gvt_stay (instead of gvt) */ gvt_stay->regcnt++; gvt->regcnt--; gvnh_reg->gvt = gvt_stay; targ_free(gvt); } } } } } greg->max_rec_size = csd->max_rec_size; greg->max_key_size = csd->max_key_size; greg->null_subs = csd->null_subs; greg->std_null_coll = csd->std_null_coll; greg->jnl_state = csd->jnl_state; greg->jnl_file_len = csd->jnl_file_len; /* journal file name length */ memcpy(greg->jnl_file_name, csd->jnl_file_name, greg->jnl_file_len); /* journal file name */ greg->jnl_alq = csd->jnl_alq; greg->jnl_deq = csd->jnl_deq; greg->jnl_buffer_size = csd->jnl_buffer_size; greg->jnl_before_image = csd->jnl_before_image; SET_REGION_OPEN_TRUE(greg, WAS_OPEN_TRUE); assert(1 <= csa->regcnt); csa->regcnt++; /* Increment # of regions that point to this csa */ return; } GTM_FD_TRACE_ONLY(gtm_dbjnl_dupfd_check();) /* check if any of db or jnl fds collide (D9I11-002714) */ greg->was_open = FALSE; /* We shouldn't have crit on any region unless we are in TP and in the final retry or we are in mupip_set_journal trying to * switch journals across all regions. WBTEST_HOLD_CRIT_ENABLED is an exception because it exercises a deadlock situation so * it needs to hold multiple crits at the same time. Currently, there is no fine-granular checking for mupip_set_journal, * hence a coarse MUPIP_IMAGE check for image_type. */ assert(dollar_tlevel && (CDB_STAGNATE <= t_tries) || IS_MUPIP_IMAGE || (0 == have_crit(CRIT_HAVE_ANY_REG)) || WBTEST_ENABLED(WBTEST_HOLD_CRIT_ENABLED)); if (dollar_tlevel && (0 != have_crit(CRIT_HAVE_ANY_REG))) { /* To avoid deadlocks with currently holding crits and the DLM lock request to be done in db_init(), * we should insert this region in the tp_reg_list and tp_restart should do the gvcst_init after * having released crit on all regions. Note that this check should be done AFTER checking if the * region has already been opened (i.e. greg->was_open = TRUE logic above) since in that case we dont * do any heavyweight processing (like db_init which involves crit/DLM locks) and so dont need to restart. */ insert_region(greg, &tp_reg_list, &tp_reg_free_list, SIZEOF(tp_region)); t_retry(cdb_sc_needcrit); assert(FALSE); /* we should never reach here since t_retry should have unwound the M-stack and restarted the TP */ } csa = (sgmnt_addrs *)&FILE_INFO(greg)->s_addrs; #ifdef NOLICENSE licensed = TRUE; #else CRYPT_CHKSYSTEM; #endif db_init_region = greg; /* initialized for dbinit_ch */ csa->hdr = NULL; csa->nl = NULL; csa->jnl = NULL; csa->persistent_freeze = FALSE; /* want secshr_db_clnup() to clear an incomplete freeze/unfreeze codepath */ csa->regcnt = 1; /* At this point, only one region points to this csa */ csa->db_addrs[0] = csa->db_addrs[1] = NULL; csa->lock_addrs[0] = csa->lock_addrs[1] = NULL; # ifdef VMS greg_acc_meth = greg->dyn.addr->acc_meth; assert(dba_cm != greg_acc_meth); temp_cs_data = (sgmnt_data_ptr_t)cs_data_buff; fc = greg->dyn.addr->file_cntl; fc->file_type = greg_acc_meth; fc->op = FC_READ; fc->op_buff = (sm_uc_ptr_t)temp_cs_data; fc->op_len = SIZEOF(*temp_cs_data); fc->op_pos = 1; dbfilop(fc); DO_BADDBVER_CHK(greg, temp_cs_data); DO_DB_HDR_CHECK(greg, temp_cs_data); /* Basic sanity check on the file header fields */ if (greg_acc_meth != temp_cs_data->acc_meth) { greg_acc_meth = temp_cs_data->acc_meth; greg->dyn.addr->acc_meth = greg_acc_meth; } # endif /* Here's the shared memory layout: * * low address * * both * segment_data * (file_header) * MM_BLOCK * (master_map) * TH_BLOCK * BG * bt_header * (bt_buckets * bt_rec) * th_base (SIZEOF(que_ent) into an odd bt_rec) * bt_base * (n_bts * bt_rec) * LOCK_BLOCK (lock_space) * (lock_space_size) * cs_addrs->acc_meth.bg.cache_state * (cache_que_heads) * (bt_buckets * cache_rec) * (n_bts * cache_rec) * critical * (mutex_struct) * nl * (node_local) * [jnl_name * jnl_buffer] * MM * file contents * LOCK_BLOCK (lock_space) * (lock_space_size) * cs_addrs->acc_meth.mm.mmblk_state * (mmblk_que_heads) * (bt_buckets * mmblk_rec) * (n_bts * mmblk_rec) * critical * (mutex_struct) * nl * (node_local) * [jnl_name * jnl_buffer] * high address */ /* Ensure first 3 members (upto now_running) of node_local are at the same offset for any version. * * Structure ----> node_local <---- size 59392 [0xe800] * * offset = 0000 [0x0000] size = 0012 [0x000c] ----> node_local.label * offset = 0012 [0x000c] size = 0256 [0x0100] ----> node_local.fname * offset = 0268 [0x010c] size = 0036 [0x0024] ----> node_local.now_running * * This is so that the VERMISMATCH error can be successfully detected in db_init/mu_rndwn_file * and so that the db-file-name can be successfully obtained from orphaned shm by mu_rndwn_all. */ assert(0 == OFFSETOF(node_local, label[0])); assert(12 == SIZEOF(((node_local *)NULL)->label)); assert(12 == GDS_LABEL_SZ); assert(12 == OFFSETOF(node_local, fname[0])); assert(256 == SIZEOF(((node_local *)NULL)->fname)); assert(256 == (MAX_FN_LEN + 1)); assert(268 == OFFSETOF(node_local, now_running[0])); assert(36 == SIZEOF(((node_local *)NULL)->now_running)); assert(36 == MAX_REL_NAME); # ifdef UNIX START_HEARTBEAT_IF_NEEDED; if (!pool_init && jnlpool_init_needed && ANTICIPATORY_FREEZE_AVAILABLE && REPL_INST_AVAILABLE) jnlpool_init(GTMRELAXED, (boolean_t)FALSE, (boolean_t *)NULL); /* Any LSEEKWRITEs hence forth will wait if the instance is frozen. To aid in printing the region information before * and after the wait, csa->region is referenced. Since it is NULL at this point, set it to greg. This is a safe * thing to do since csa->region is anyways set in db_common_init (few lines below). */ csa->region = greg; # endif /* Protect the db_init and the code below until we set greg->open to TRUE. This is needed as otherwise, * if a MUPIP STOP is issued to this process at a time-window when db_init is completed but greg->open * is NOT set to TRUE, will cause gds_rundown NOT to clean up the shared memory created by db_init and * thus would be left over in the system. */ DEFER_INTERRUPTS(INTRPT_IN_GVCST_INIT); VMS_ONLY(db_init(greg, temp_cs_data)); # ifdef UNIX db_init_retry = 0; GTM_WHITE_BOX_TEST(WBTEST_HOLD_FTOK_UNTIL_BYPASS, db_init_retry, 3); for (; db_init_retry < MAX_DBINIT_RETRY; db_init_retry++) { if (0 == db_init(greg)) break; db_init_err_cleanup(MAX_DBINIT_RETRY > (db_init_retry + 1)); } if (MAX_DBINIT_RETRY == db_init_retry) /* We retried enough. Error out. */ { assert(IS_LKE_IMAGE || IS_DSE_IMAGE); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REGOPENFAIL, 4, REG_LEN_STR(greg), DB_LEN_STR(greg)); } # endif /* At this point, we have initialized the database, but haven't yet set reg->open to TRUE. If any rts_errors happen in * the meantime, there are no condition handlers established to handle the rts_error. More importantly, it is non-trivial * to add logic to such a condition handler to undo the effects of db_init. Also, in some cases, the rts_error can can * confuse future calls of db_init. By invoking DBG_MARK_RTS_ERROR_UNUSABLE, we can catch any rts_errors in future and * eliminate it on a case by case basis. */ UNIX_ONLY(DBG_MARK_RTS_ERROR_UNUSABLE); crash_count = csa->critical->crashcnt; csa->regnum = ++region_open_count; csd = csa->hdr; # ifdef GTM_TRIGGER /* Take copy of db trigger cycle into csa at db startup. Any concurrent changes to the * db trigger cycle (by MUPIP TRIGGER) will be detected at tcommit (t_end/tp_tend) time. */ csa->db_trigger_cycle = csd->db_trigger_cycle; # endif /* set csd and fill in selected fields */ assert(greg->dyn.addr->acc_meth == csd->acc_meth); /* db_init should have made sure this assert holds good */ greg_acc_meth = csd->acc_meth; /* It is necessary that we do the pending gv_target list reallocation BEFORE db_common_init as the latter resets * greg->max_key_size to be equal to the csd->max_key_size and hence process_gvt_pending_list might wrongly conclude * that NO reallocation (since it checks greg->max_key_size with csd->max_key_size) is needed when in fact a * reallocation might be necessary (if the user changed max_key_size AFTER database creation) */ PROCESS_GVT_PENDING_LIST(greg, csa, gvt_pending_list); db_common_init(greg, csa, csd); /* do initialization common to db_init() and mu_rndwn_file() */ /* If we are not fully upgraded, see if we need to send a warning to the operator console about performance. Compatibility mode is a known performance drain. Actually, we can send one of two messages. If the desired_db_format is for an earlier release than the current release, we send a performance warning that this mode degrades performance. However, if the desired_db_format is for the current version but there are blocks to convert still, we send a gengle reminder that running mupip reorg upgrade would be a good idea to get the full performance benefit of V5. */ time(&curr_time); assert(MAXUINT4 > curr_time); curr_time_uint4 = (uint4)curr_time; next_warn_uint4 = csd->next_upgrd_warn.cas_time; if (!csd->fully_upgraded && curr_time_uint4 > next_warn_uint4 && COMPSWAP_LOCK(&csd->next_upgrd_warn.time_latch, next_warn_uint4, 0, (curr_time_uint4 + UPGRD_WARN_INTERVAL), 0)) { /* The msg is due and we have successfully updated the next time interval */ if (GDSVCURR != csd->desired_db_format) send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBVERPERFWARN1, 2, DB_LEN_STR(greg)); else send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBVERPERFWARN2, 2, DB_LEN_STR(greg)); } /* Compute the maximum journal space requirements for a PBLK (including possible ALIGN record). * Use this variable in the TOTAL_TPJNL_REC_SIZE and TOTAL_NONTP_JNL_REC_SIZE macros instead of recomputing. */ csa->pblk_align_jrecsize = (int4)MIN_PBLK_RECLEN + csd->blk_size + (int4)MIN_ALIGN_RECLEN; segment_update_array_size = UA_SIZE(csd); if (first_ua == NULL) { /* first open of first database - establish an update array system */ assert(update_array == NULL); assert(update_array_ptr == NULL); assert(update_array_size == 0); tmp_ua = (ua_list *)malloc(SIZEOF(ua_list)); memset(tmp_ua, 0, SIZEOF(ua_list)); /* initialize tmp_ua->update_array and tmp_ua->next_ua to NULL */ tmp_ua->update_array = (char *)malloc(segment_update_array_size); tmp_ua->update_array_size = segment_update_array_size; /* assign global variables only after malloc() succeeds */ update_array_size = cumul_update_array_size = segment_update_array_size; update_array = update_array_ptr = tmp_ua->update_array; first_ua = curr_ua = tmp_ua; } else { /* there's already an update_array system in place */ assert(update_array != NULL); assert(update_array_size != 0); if (!dollar_tlevel && segment_update_array_size > first_ua->update_array_size) { /* no transaction in progress and the current array is too small - replace it */ assert(first_ua->update_array == update_array); assert(first_ua->update_array_size == update_array_size); assert(first_ua->next_ua == NULL); tmp_ua = first_ua; first_ua = curr_ua = NULL; free(update_array); tmp_ua->update_array = update_array = update_array_ptr = NULL; tmp_ua->update_array = (char *)malloc(segment_update_array_size); tmp_ua->update_array_size = segment_update_array_size; /* assign global variables only after malloc() succeeds */ update_array_size = cumul_update_array_size = segment_update_array_size; update_array = update_array_ptr = tmp_ua->update_array; first_ua = curr_ua = tmp_ua; } } assert(global_tlvl_info_list || !csa->sgm_info_ptr); if (JNL_ALLOWED(csa)) { bsize = csd->blk_size; realloc_alt_buff = FALSE; if (NULL == non_tp_jfb_ptr) { non_tp_jfb_ptr = (jnl_format_buffer *)malloc(SIZEOF(jnl_format_buffer)); non_tp_jfb_ptr->hi_water_bsize = bsize; non_tp_jfb_ptr->buff = (char *)malloc(MAX_NONTP_JNL_REC_SIZE(bsize)); non_tp_jfb_ptr->record_size = 0; /* initialize it to 0 since TOTAL_NONTPJNL_REC_SIZE macro uses it */ GTMCRYPT_ONLY(non_tp_jfb_ptr->alt_buff = NULL); } else if (bsize > non_tp_jfb_ptr->hi_water_bsize) { /* Need a larger buffer to accommodate larger non-TP journal records */ non_tp_jfb_ptr->hi_water_bsize = bsize; free(non_tp_jfb_ptr->buff); non_tp_jfb_ptr->buff = (char *)malloc(MAX_NONTP_JNL_REC_SIZE(bsize)); # ifdef GTM_CRYPT if (NULL != non_tp_jfb_ptr->alt_buff) { free(non_tp_jfb_ptr->alt_buff); realloc_alt_buff = TRUE; } # endif } /* If the journal records need to be encrypted in the journal file and if replication is in use, * we will need access to both the encrypted (for the journal file) and unencrypted (for the * journal pool) journal record contents. Allocate an alternative buffer if any open journaled region * is encrypted. */ # ifdef GTM_CRYPT if (realloc_alt_buff || (csd->is_encrypted && (NULL == non_tp_jfb_ptr->alt_buff))) non_tp_jfb_ptr->alt_buff = (char *)malloc(MAX_NONTP_JNL_REC_SIZE(non_tp_jfb_ptr->hi_water_bsize)); # endif /* csa->min_total_tpjnl_rec_size represents the minimum journal buffer space needed for a TP transaction. * It is a conservative estimate assuming that one ALIGN record and one PINI record will be written for * one set of fixed size jnl records written. * si->total_jnl_rec_size is initialized/reinitialized to this value here and in tp_clean_up(). * The purpose of this field is to avoid recomputation of the variable in tp_clean_up(). * In addition to this, space requirements for whatever journal records get formatted as part of * jnl_format() need to be taken into account. * This is done in jnl_format() where si->total_jnl_rec_size is appropriately incremented. */ csa->min_total_tpjnl_rec_size = PINI_RECLEN + TCOM_RECLEN + MIN_ALIGN_RECLEN; /* Similarly csa->min_total_nontpjnl_rec_size represents the minimum journal buffer space needed * for a non-TP transaction. * It is a conservative estimate assuming that one ALIGN record and one PINI record will be written for * one set of fixed size jnl records written. */ csa->min_total_nontpjnl_rec_size = PINI_RECLEN + MIN_ALIGN_RECLEN; } if (tp_in_use || !IS_GTM_IMAGE) gvcst_tp_init(greg); /* Initialize TP structures, else postpone till TP is used (only if GTM) */ if (!global_tlvl_info_list) { global_tlvl_info_list = (buddy_list *)malloc(SIZEOF(buddy_list)); initialize_list(global_tlvl_info_list, SIZEOF(global_tlvl_info), GBL_TLVL_INFO_LIST_INIT_ALLOC); } assert(!greg->was_open); SET_REGION_OPEN_TRUE(greg, WAS_OPEN_FALSE); csa = (sgmnt_addrs*)&FILE_INFO(greg)->s_addrs; if (NULL != csa->dir_tree) { /* It is possible that dir_tree has already been targ_alloc'ed. This is because GT.CM or VMS DAL * calls can run down regions without the process halting out. We don't want to double malloc. */ csa->dir_tree->clue.end = 0; } SET_CSA_DIR_TREE(csa, greg->max_key_size, greg); /* Now that reg->open is set to TRUE and directory tree is initialized, go ahead and set rts_error back to being usable */ UNIX_ONLY(DBG_MARK_RTS_ERROR_USABLE); /* gds_rundown if invoked from now on will take care of cleaning up the shared memory segment */ ENABLE_INTERRUPTS(INTRPT_IN_GVCST_INIT); if (dba_bg == greg_acc_meth) { /* Check if (a) this region has non-upgraded blocks and if so, (b) the reformat buffer exists and * (c) if it is big enough to deal with this region. If the region does not have any non-upgraded * block (blks_to_upgrd is 0) we will not allocate the buffer at this time. Note that this opens up * a small window for errors. If this buffer is not allocated and someone turns on compatibility * mode and before the process can discover this and allocate the buffer, it runs out of memory, * errors out and finds it is responsible for running down the database, it could fail on a recursive * memory error when it tries to allocate the block. This is (to me) an acceptable risk as it is * very low and compares favorably to the cost of every process allocating a database block sized * chunk of private storage that will be seldom if ever used (SE 3/2005). */ if (0 != csd->blks_to_upgrd && csd->blk_size > reformat_buffer_len) { /* Buffer not big enough (or does not exist) .. get a new one releasing old if it exists */ assert(0 == fast_lock_count); /* this is mainline (non-interrupt) code */ ++fast_lock_count; /* No interrupts across this use of reformat_buffer */ /* reformat_buffer_in_use should always be incremented only AFTER incrementing fast_lock_count * as it is the latter that prevents interrupts from using the reformat buffer. Similarly * the decrement of fast_lock_count should be done AFTER decrementing reformat_buffer_in_use. */ assert(0 == reformat_buffer_in_use); DEBUG_ONLY(reformat_buffer_in_use++;) if (reformat_buffer) free(reformat_buffer); /* Different blksized databases in use .. keep only largest one */ reformat_buffer = malloc(csd->blk_size); reformat_buffer_len = csd->blk_size; DEBUG_ONLY(reformat_buffer_in_use--;) assert(0 == reformat_buffer_in_use); --fast_lock_count; } } if ((dba_bg == greg_acc_meth) || (dba_mm == greg_acc_meth)) { /* Determine fid_index of current region's file_id across sorted file_ids of all regions open until now. * All regions which have a file_id lesser than that of current region will have no change to their fid_index * All regions which have a file_id greater than that of current region will have their fid_index incremented by 1 * The fid_index determination algorithm below has an optimization in that if the current region's file_id is * determined to be greater than that of a particular region, then all regions whose fid_index is lesser * than that particular region's fid_index are guaranteed to have a lesser file_id than the current region * so we do not compare those against the current region's file_id. * Note that the sorting is done only on DB/MM regions. GT.CM/DDP regions should not be part of TP transactions, * hence they will not be sorted. */ prevcsa = NULL; greg_fid = &(csa->nl->unique_id); for (regcsa = cs_addrs_list; NULL != regcsa; regcsa = regcsa->next_csa) { UNIX_ONLY(onln_rlbk_cycle_mismatch |= (regcsa->db_onln_rlbkd_cycle != regcsa->nl->db_onln_rlbkd_cycle)); if ((NULL != prevcsa) && (regcsa->fid_index < prevcsa->fid_index)) continue; reg_fid = &((regcsa)->nl->unique_id); VMS_ONLY(if (0 < memcmp(&(greg_fid->file_id), (char *)&(reg_fid->file_id), SIZEOF(gd_id)))) UNIX_ONLY(if (0 < gdid_cmp(&(greg_fid->uid), &(reg_fid->uid)))) { if ((NULL == prevcsa) || (regcsa->fid_index > prevcsa->fid_index)) prevcsa = regcsa; } else regcsa->fid_index++; } if (NULL == prevcsa) csa->fid_index = 1; else csa->fid_index = prevcsa->fid_index + 1; UNIX_ONLY( if (onln_rlbk_cycle_mismatch) { csa->root_search_cycle--; csa->onln_rlbk_cycle--; csa->db_onln_rlbkd_cycle--; } ) /* Add current csa into list of open csas */ csa->next_csa = cs_addrs_list; cs_addrs_list = csa; /* Also update tp_reg_list fid_index's as insert_region relies on it */ for (tr = tp_reg_list; NULL != tr; tr = tr->fPtr) tr->file.fid_index = (&FILE_INFO(tr->reg)->s_addrs)->fid_index; DBG_CHECK_TP_REG_LIST_SORTING(tp_reg_list); } # ifdef UNIX if (pool_init && REPL_ALLOWED(csd) && jnlpool_init_needed) { /* Last parameter to VALIDATE_INITIALIZED_JNLPOOL is TRUE if the process does logical updates and FALSE otherwise. * This parameter governs whether the macro can do SCNDDBNOUPD check or not. All the utilities that sets * jnlpool_init_needed global variable don't do logical updates (REORG, EXTEND, etc.). But, for GT.M, * jnlpool_init_needed is set to TRUE unconditionally. Even though GT.M can do logical updates, we pass FALSE * unconditionally to the macro (indicating no logical updates). This is because, at this point, there is no way to * tell if this process wants to open the database for read or write operation. If it is for a read operation, we * don't want the below macro to issue SCNDDBNOUPD error. If it is for write operation, we will skip the * SCNDDBNOUPD error message here. But, eventually when this process goes to gvcst_{put,kill} or op_ztrigger, * SCNDDBNOUPD is issued. */ VALIDATE_INITIALIZED_JNLPOOL(csa, csa->nl, greg, GTMRELAXED, SCNDDBNOUPD_CHECK_FALSE); } # endif return; } fis-gtm-V6.0-003/sr_port/gvcst_jrt_null.c0000644000032200000250000000421712201176157017243 0ustar librarygtc/**************************************************************** * * * Copyright 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" /* needed for jnl.h */ #include "gdscc.h" /* needed for jnl.h */ #include "jnl.h" #include "t_end.h" /* prototypes */ #include "t_retry.h" #include "t_begin.h" #include "gvcst_jrt_null.h" /* for gvcst_jrt_null prototype */ #include "jnl_get_checksum.h" GBLREF jnl_format_buffer *non_tp_jfb_ptr; GBLREF jnl_gbls_t jgbl; #ifdef DEBUG GBLREF uint4 dollar_tlevel; GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF unsigned int t_tries; #endif error_def(ERR_JRTNULLFAIL); void gvcst_jrt_null() { enum cdb_sc status; struct_jrec_null *rec; assert(NULL != gv_cur_region); assert(NULL != cs_addrs); assert(cs_addrs == &FILE_INFO(gv_cur_region)->s_addrs); t_begin(ERR_JRTNULLFAIL, UPDTRNS_DB_UPDATED_MASK); assert(!dollar_tlevel); assert(t_tries < CDB_STAGNATE || cs_addrs->now_crit); /* we better hold crit in the final retry */ non_tp_jfb_ptr->rectype = JRT_NULL; non_tp_jfb_ptr->record_size = NULL_RECLEN; non_tp_jfb_ptr->checksum = INIT_CHECKSUM_SEED; rec = (struct_jrec_null *)non_tp_jfb_ptr->buff; rec->prefix.jrec_type = JRT_NULL; rec->prefix.forwptr = NULL_RECLEN; rec->prefix.checksum = INIT_CHECKSUM_SEED; rec->suffix.backptr = NULL_RECLEN; rec->suffix.suffix_code = JNL_REC_SUFFIX_CODE; rec->filler = 0; jgbl.cumul_jnl_rec_len = NULL_RECLEN; /* The rest of the initialization is taken care of by jnl_write_logical (invoked in t_end below) */ DEBUG_ONLY(jgbl.cumul_index = 1;) for (;;) { DEBUG_ONLY(jgbl.cu_jnl_index = 0;) if ((trans_num)0 == t_end(NULL, NULL, TN_NOT_SPECIFIED)) continue; return; } } fis-gtm-V6.0-003/sr_port/gvcst_jrt_null.h0000644000032200000250000000103612201176157017244 0ustar librarygtc/**************************************************************** * * * Copyright 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GVCST_JRT_NULL_H__ #define __GVCST_JRT_NULL_H__ void gvcst_jrt_null(void); #endif fis-gtm-V6.0-003/sr_port/gvcst_kill.c0000644000032200000250000010626412201176176016353 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "gtm_string.h" #include "gtm_stdlib.h" #include "gtm_stdio.h" #include "gtm_inet.h" /* Required for gtmsource.h */ #ifdef VMS #include /* Required for gtmsource.h */ #endif #include "cdb_sc.h" #include "gdsroot.h" #include "gdskill.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gdscc.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "jnl.h" #include "copy.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "repl_msg.h" #include "gtmsource.h" #include "interlock.h" #include #include "stack_frame.h" #ifdef GTM_TRIGGER # include "gv_trigger.h" # include "gtm_trigger.h" # include "gv_trigger_protos.h" # include "mv_stent.h" # include "stringpool.h" #endif #include "tp_frame.h" #include "tp_restart.h" /* Include prototypes */ #include "gvcst_kill_blk.h" #include "t_qread.h" #include "t_end.h" #include "t_retry.h" #include "t_begin.h" #include "gvcst_expand_free_subtree.h" #include "gvcst_protos.h" /* for gvcst_kill,gvcst_search prototype */ #include "rc_cpt_ops.h" #include "add_inter.h" #include "sleep_cnt.h" #include "wcs_sleep.h" #include "wbox_test_init.h" #include "memcoherency.h" #include "util.h" #include "op.h" /* for op_tstart prototype */ #include "format_targ_key.h" /* for format_targ_key prototype */ #include "tp_set_sgm.h" /* for tp_set_sgm prototype */ #include "op_tcommit.h" /* for op_tcommit prototype */ #include "have_crit.h" #include "error.h" #include "gtmimagename.h" /* needed for spanning nodes */ GBLREF gd_region *gv_cur_region; GBLREF gv_key *gv_currkey, *gv_altkey; GBLREF int4 gv_keysize; GBLREF gv_namehead *gv_target; GBLREF jnl_fence_control jnl_fence_ctl; GBLREF kill_set *kill_set_tail; GBLREF uint4 dollar_tlevel; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF sgm_info *sgm_info_ptr; GBLREF unsigned char cw_set_depth; GBLREF unsigned int t_tries; GBLREF boolean_t need_kip_incr; GBLREF uint4 update_trans; GBLREF jnlpool_addrs jnlpool; GBLREF sgmnt_addrs *kip_csa; GBLREF boolean_t skip_dbtriggers; /* see gbldefs.c for description of this global */ GBLREF stack_frame *frame_pointer; GBLREF boolean_t gv_play_duplicate_kills; #ifdef GTM_TRIGGER GBLREF int tprestart_state; GBLREF int4 gtm_trigger_depth; GBLREF int4 tstart_trigger_depth; GBLREF boolean_t skip_INVOKE_RESTART; GBLREF boolean_t ztwormhole_used; /* TRUE if $ztwormhole was used by trigger code */ GBLREF mval dollar_ztwormhole; GBLREF unsigned char t_fail_hist[CDB_MAX_TRIES]; #endif #ifdef DEBUG GBLREF char *update_array, *update_array_ptr; GBLREF uint4 update_array_size; /* needed for the ENSURE_UPDATE_ARRAY_SPACE macro */ GBLREF jnl_gbls_t jgbl; GBLREF boolean_t donot_INVOKE_MUMTSTART; #endif UNIX_ONLY(GBLREF boolean_t span_nodes_disallowed;) error_def(ERR_DBROLLEDBACK); error_def(ERR_TPRETRY); error_def(ERR_GVKILLFAIL); #ifdef GTM_TRIGGER LITREF mval literal_null; LITREF mval *fndata_table[2][2]; #endif LITREF mval literal_batch; #define SKIP_ASSERT_TRUE TRUE #define SKIP_ASSERT_FALSE FALSE #define GOTO_RETRY(SKIP_ASSERT) \ { \ assert((CDB_STAGNATE > t_tries) || SKIP_ASSERT); \ goto retry; \ } DEFINE_NSB_CONDITION_HANDLER(gvcst_kill_ch) void gvcst_kill(boolean_t do_subtree) { boolean_t spanstat; boolean_t sn_tpwrapped; boolean_t est_first_pass; int oldend; int save_dollar_tlevel; DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); if (do_subtree) { /* If we're killing the whole subtree, that includes any spanning nodes. No need to do anything special */ gvcst_kill2(TRUE, NULL, FALSE); assert(save_dollar_tlevel == dollar_tlevel); return; } else { /* Attempt to zkill node, but abort if we might have a spanning node */ spanstat = 0; gvcst_kill2(FALSE, &spanstat, FALSE); assert(save_dollar_tlevel == dollar_tlevel); if (!spanstat) return; } VMS_ONLY(assert(FALSE)); # ifdef UNIX RTS_ERROR_IF_SN_DISALLOWED; oldend = gv_currkey->end; /* Almost certainly have a spanning node to zkill. So start a TP transaction to deal with it. */ if (!dollar_tlevel) { sn_tpwrapped = TRUE; op_tstart((IMPLICIT_TSTART + IMPLICIT_TRIGGER_TSTART), TRUE, &literal_batch, 0); assert(!donot_INVOKE_MUMTSTART); DEBUG_ONLY(donot_INVOKE_MUMTSTART = TRUE); ESTABLISH_NORET(gvcst_kill_ch, est_first_pass); GVCST_ROOT_SEARCH_AND_PREP(est_first_pass); } else sn_tpwrapped = FALSE; /* Fire any triggers FIRST, then proceed with the kill. If we started a lcl_implicit transaction in first gvcst_kill * triggers were rolled back. So if span_status indicates TRLBKTRIG, do them again. * Otherwise, skip triggers because they were either kept or didn't happen. * What if new triggers added between above gvcst_kill and now? Should cause a restart because trigger cycle changes? */ if (sn_tpwrapped) gvcst_kill2(FALSE, NULL, FALSE); /* zkill primary dummy node <--- jnling + trigs happen here */ /* kill any existing hidden subscripts */ APPEND_HIDDEN_SUB(gv_currkey); /* append "0211" to gv_currkey */ gvcst_kill2(FALSE, NULL, TRUE); RESTORE_CURRKEY(gv_currkey, oldend); if (sn_tpwrapped) { op_tcommit(); DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE); REVERT; /* remove our condition handler */ } assert(save_dollar_tlevel == dollar_tlevel); # endif } void gvcst_kill2(boolean_t do_subtree, boolean_t *span_status, boolean_t killing_chunks) { block_id gvt_root; boolean_t clue, flush_cache; boolean_t next_fenced_was_null, write_logical_jnlrecs, jnl_format_done; boolean_t left_extra, right_extra; boolean_t want_root_search = FALSE, is_dummy, succeeded, key_exists; rec_hdr_ptr_t rp; uint4 lcl_onln_rlbkd_cycle; int data_len, cur_val_offset; unsigned short rec_size; cw_set_element *tp_cse; enum cdb_sc cdb_status; int lev, end, target_key_size; uint4 prev_update_trans, actual_update; jnl_format_buffer *jfb, *ztworm_jfb; jnl_action_code operation; kill_set kill_set_head, *ks, *temp_ks; node_local_ptr_t cnl; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; srch_blk_status *bh, *left, *right; srch_hist *gvt_hist, *alt_hist, *dir_hist; srch_rec_status *left_rec_stat, local_srch_rec; uint4 segment_update_array_size; unsigned char *base; int lcl_dollar_tlevel, rc; uint4 nodeflags; gv_namehead *save_targ; sgm_info *si; # ifdef GTM_TRIGGER mint dlr_data; boolean_t is_tpwrap; boolean_t lcl_implicit_tstart; /* local copy of the global variable "implicit_tstart" */ gtm_trigger_parms trigparms; gvt_trigger_t *gvt_trigger; gvtr_invoke_parms_t gvtr_parms; int gtm_trig_status, idx; unsigned char *save_msp; mv_stent *save_mv_chain; mval *ztold_mval = NULL, ztvalue_new, ztworm_val; # endif # ifdef DEBUG boolean_t is_mm, root_search_done = FALSE; uint4 dbg_research_cnt; # endif DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; csa = cs_addrs; csd = csa->hdr; cnl = csa->nl; DEBUG_ONLY(is_mm = (dba_mm == csd->acc_meth)); GTMTRIG_ONLY( TRIG_CHECK_REPLSTATE_MATCHES_EXPLICIT_UPDATE(gv_cur_region, csa); if (IS_EXPLICIT_UPDATE) { /* This is an explicit update. Set ztwormhole_used to FALSE. Note that we initialize this only at the * beginning of the transaction and not at the beginning of each try/retry. If the application used * $ztwormhole in any retsarting try of the transaction, we consider it necessary to write the * TZTWORM/UZTWORM record even though it was not used in the succeeding/committing try. */ ztwormhole_used = FALSE; } ) JNLPOOL_INIT_IF_NEEDED(csa, csd, cnl); if (!dollar_tlevel) { kill_set_head.next_kill_set = NULL; if (jnl_fence_ctl.level) /* next_fenced_was_null is reliable only if we are in ZTransaction */ next_fenced_was_null = (NULL == csa->next_fenced) ? TRUE : FALSE; /* In case of non-TP explicit updates that invoke triggers the kills happen inside of TP. If those kills * dont cause any actual update, we need prev_update_trans set appropriately so update_trans can be reset. */ GTMTRIG_ONLY(prev_update_trans = 0); } else prev_update_trans = sgm_info_ptr->update_trans; assert(('\0' != gv_currkey->base[0]) && gv_currkey->end); DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_GVKILLFAIL); assert(NULL != update_array); assert(NULL != update_array_ptr); assert(0 != update_array_size); assert(update_array + update_array_size >= update_array_ptr); GTMTRIG_ONLY( lcl_implicit_tstart = FALSE; trigparms.ztvalue_new = NULL; ) operation = (do_subtree ? JNL_KILL : JNL_ZKILL); for (;;) { actual_update = 0; # ifdef GTM_TRIGGER gvtr_parms.num_triggers_invoked = 0; /* clear any leftover value */ is_tpwrap = FALSE; /* No trigger ^#t reads needed if skip_dbtriggers is TRUE (e.g. mupip load etc.) */ if (!skip_dbtriggers) { GVTR_INIT_AND_TPWRAP_IF_NEEDED(csa, csd, gv_target, gvt_trigger, lcl_implicit_tstart, is_tpwrap, ERR_GVKILLFAIL); assert(gvt_trigger == gv_target->gvt_trigger); } /* finish off any pending root search from previous retry */ REDO_ROOT_SEARCH_IF_NEEDED(want_root_search, cdb_status); if (cdb_sc_normal != cdb_status) { /* gvcst_root_search invoked from REDO_ROOT_SEARCH_IF_NEEDED ended up with a restart situation but did not * actually invoke t_retry. Instead, it returned control back to us asking us to restart. */ GOTO_RETRY(SKIP_ASSERT_TRUE); /* cannot enable assert (which has an assert about t_tries < CDB_STAGNATE) * because it is possible for us to get cdb_sc_gvtrootmod2 restart when * t_tries == CDB_STAGNATE. */ } # endif /* Need to reinitialize gvt_hist & alt_hist for each try as it might have got set to a value in the previous * retry that is inappropriate for this try (e.g. gvt_root value changed between tries). */ gvt_hist = &gv_target->hist; gvt_root = gv_target->root; /* refetch root in case it changed due to retries in this for loop */ if (!gvt_root) { assert(gv_play_duplicate_kills); /* No GVT for this global. So nothing to kill. But since we have to play the duplicate kill * (asserted above) we cannot return at this point. There are two cases. * (1) If we hold crit on the region at this point, then there is no way a concurrent update * could create a GVT for this global. So no ned of any extra history recordkeeping. * (2) If we dont hold crit though, this scenario is possible. Handle this by searching for * the global name in the directory tree and verifying that it is still missing. * a) If YES, then pass this history on to t_end/tp_hist as part of the duplicate kill play action. * This way we make sure no other process concurrently creates the GVT while we process this * duplicate kill transaction. * b) If NO, then some other process has created a GVT for this global after we started this * transaction. In this case we will have to first get the non-zero root block number of this * GVT and then use it in the rest of this function. Use the function "gvcst_redo_root_search" * for this purpose. It is possible that the root block is set to 0 even after the call to the * above function (because of a concurrent KILL of this GVT after we saw a non-zero value but * before the "gvcst_redo_root_search" invocation). In this case, we are back to square one. * So we redo the logic in this entire comment again each time going through t_retry. * In the 3rd retry, we will get crit and that time we will break out of this block of code * and move on to the real kill. */ alt_hist = NULL; if (csa->now_crit) { /* Case (1) : Clear history in case this gets passed to t_end/tp_hist later below */ gvt_hist->h[0].blk_num = 0; } else { /* Case (2) : Search for global name in directory tree */ save_targ = gv_target; SET_GV_ALTKEY_TO_GBLNAME_FROM_GV_CURRKEY; /* set up gv_altkey to be just the gblname */ gv_target = csa->dir_tree; dir_hist = &gv_target->hist; cdb_status = gvcst_search(gv_altkey, NULL); RESET_GV_TARGET_LCL(save_targ); if (cdb_sc_normal != cdb_status) { /* Retry the transaction. But reset directory tree clue as it is suspect at this point. * Needed as t_retry only resets clue of gv_target which is not the directory tree anymore. */ csa->dir_tree->clue.end = 0; GOTO_RETRY(SKIP_ASSERT_FALSE); } if ((gv_altkey->end + 1) == dir_hist->h[0].curr_rec.match) { /* Case (2b) : GVT now exists for this global */ cdb_status = cdb_sc_gvtrootmod; GOTO_RETRY(SKIP_ASSERT_FALSE); } else { /* Case (2a) : GVT does not exist for this global */ gvt_hist = dir_hist; /* validate directory tree history in t_end/tp_hist */ } } } else alt_hist = gv_target->alt_hist; DEBUG_ONLY(dbg_research_cnt = 0;) jnl_format_done = FALSE; write_logical_jnlrecs = JNL_WRITE_LOGICAL_RECS(csa); # ifdef GTM_TRIGGER dlr_data = 0; /* No trigger invocation needed if skip_dbtriggers is TRUE (e.g. mupip load etc.). * If gvt_root is 0 (possible only if gv_play_duplicate_kills is TRUE) we want to only journal the * kill but not touch the database or invoke triggers. So skip triggers in that case too. */ if (!skip_dbtriggers && (NULL != gvt_trigger) && gvt_root && !killing_chunks) { PUSH_ZTOLDMVAL_ON_M_STACK(ztold_mval, save_msp, save_mv_chain); /* Determine $ZTOLDVAL & $ZTDATA to fill in trigparms */ dlr_data = DG_DATAGET; /* tell dataget we want full info regarding descendants */ cdb_status = gvcst_dataget(&dlr_data, ztold_mval); if (cdb_sc_normal != cdb_status) GOTO_RETRY(SKIP_ASSERT_FALSE); assert((11 >= dlr_data) && (1 >= (dlr_data % 10))); /* Invoke triggers for KILL as long as $data is nonzero (1 or 10 or 11). * Invoke triggers for ZKILL only if $data is 1 or 11 (for 10 case, ZKILL is a no-op). */ if (do_subtree ? dlr_data : (dlr_data & 1)) { /* Either node or its descendants exists. Invoke KILL triggers for this node. * But first write journal records (ZTWORM and/or KILL) for the triggering nupdate. * "ztworm_jfb", "jfb" and "jnl_format_done" are set by the below macro. */ JNL_FORMAT_ZTWORM_IF_NEEDED(csa, write_logical_jnlrecs, operation, gv_currkey, NULL, ztworm_jfb, jfb, jnl_format_done); /* Initialize trigger parms that dont depend on the context of the matching trigger */ trigparms.ztoldval_new = ztold_mval; trigparms.ztdata_new = fndata_table[dlr_data / 10][dlr_data & 1]; if (NULL == trigparms.ztvalue_new) { /* Do not pass literal_null directly since $ztval can be modified inside trigger * code and literal_null is in read-only segment so will not be modifiable. * Hence the need for a dummy local variable mval "ztvalue_new" in the C stack. */ ztvalue_new = literal_null; trigparms.ztvalue_new = &ztvalue_new; } gvtr_parms.gvtr_cmd = do_subtree ? GVTR_CMDTYPE_KILL : GVTR_CMDTYPE_ZKILL; gvtr_parms.gvt_trigger = gvt_trigger; /* Now that we have filled in minimal information, let "gvtr_match_n_invoke" do the rest */ gtm_trig_status = gvtr_match_n_invoke(&trigparms, &gvtr_parms); assert((0 == gtm_trig_status) || (ERR_TPRETRY == gtm_trig_status)); if (ERR_TPRETRY == gtm_trig_status) { /* A restart has been signaled that we need to handle or complete the handling of. * This restart could have occurred reading the trigger in which case no * tp_restart() has yet been done or it could have occurred in trigger code in * which case we need to finish the incomplete tp_restart. In both cases this * must be an implicitly TP wrapped transaction. Our action is to complete the * necessary tp_restart() logic (t_retry is already completed so should be skipped) * and then re-do the gvcst_kill logic. */ assert(lcl_implicit_tstart || *span_status); cdb_status = cdb_sc_normal; /* signal "retry:" to avoid t_retry call */ assert(CDB_STAGNATE >= t_tries); GOTO_RETRY(SKIP_ASSERT_TRUE);; /* Cannot check assert because above assert is >= t_tries */ } REMOVE_ZTWORM_JFB_IF_NEEDED(ztworm_jfb, jfb, sgm_info_ptr); } /* else : we dont invoke any KILL/ZTKILL type triggers for a node whose $data is 0 */ POP_MVALS_FROM_M_STACK_IF_NEEDED(ztold_mval, save_msp, save_mv_chain); } # endif assert(csd == cs_data); /* assert csd is in sync with cs_data even if there were MM db file extensions */ assert(csd == csa->hdr); si = sgm_info_ptr; /* Has to be AFTER the GVTR_INIT_AND_TPWRAP_IF_NEEDED macro in case that sets * sgm_info_ptr to a non-NULL value (if a non-TP transaction is tp wrapped for triggers). */ assert(t_tries < CDB_STAGNATE || csa->now_crit); /* we better hold crit in the final retry (TP & non-TP) */ if (!dollar_tlevel) { CHECK_AND_RESET_UPDATE_ARRAY; /* reset update_array_ptr to update_array */ kill_set_tail = &kill_set_head; for (ks = &kill_set_head; NULL != ks; ks = ks->next_kill_set) ks->used = 0; } else { segment_update_array_size = UA_NON_BM_SIZE(csd); ENSURE_UPDATE_ARRAY_SPACE(segment_update_array_size); } clue = (0 != gv_target->clue.end); research: if (gvt_root) { #if defined(DEBUG) && defined(UNIX) if (gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_GVKILLFAIL == gtm_white_box_test_case_number)) { cdb_status = cdb_sc_blknumerr; /* Skip assert inside GOTO_RETRY macro as the WBTEST_ANTIFREEZE_GVKILLFAIL white-box testcase * intentionally triggers a GVKILLFAIL error. */ GOTO_RETRY(SKIP_ASSERT_TRUE); } #endif if (cdb_sc_normal != (cdb_status = gvcst_search(gv_currkey, NULL))) GOTO_RETRY(SKIP_ASSERT_FALSE); assert(gv_altkey->top == gv_currkey->top); assert(gv_altkey->top == gv_keysize); end = gv_currkey->end; assert(end < gv_currkey->top); memcpy(gv_altkey, gv_currkey, SIZEOF(gv_key) + end); base = &gv_altkey->base[0]; if (do_subtree) { base[end - 1] = 1; assert(KEY_DELIMITER == base[end]); base[++end] = KEY_DELIMITER; } else { # ifdef UNIX target_key_size = gv_currkey->end + 1; bh = &gv_target->hist.h[0]; key_exists = (target_key_size == bh->curr_rec.match); if (key_exists) { /* check for spanning node dummy value: a single zero byte */ rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)bh->buffaddr + bh->curr_rec.offset); GET_USHORT(rec_size, &rp->rsiz); cur_val_offset = SIZEOF(rec_hdr) + target_key_size - EVAL_CMPC((rec_hdr_ptr_t)rp); data_len = rec_size - cur_val_offset; is_dummy = IS_SN_DUMMY(data_len, (sm_uc_ptr_t)rp + cur_val_offset); if (is_dummy && (NULL != span_status) && !(span_nodes_disallowed && csd->span_node_absent)) { need_kip_incr = FALSE; if (!dollar_tlevel) { update_trans = 0; succeeded = ((trans_num)0 != t_end(gvt_hist, NULL, TN_NOT_SPECIFIED)); if (!succeeded) { /* see other t_end */ assert((NULL == kip_csa) && (csd == cs_data)); update_trans = UPDTRNS_DB_UPDATED_MASK; continue; } *span_status = TRUE; return; } else { cdb_status = tp_hist(NULL); if (cdb_sc_normal != cdb_status) GOTO_RETRY(SKIP_ASSERT_FALSE); *span_status = TRUE; # ifdef GTM_TRIGGER if (lcl_implicit_tstart) { /* Rollback triggers */ OP_TROLLBACK(-1); return; } # endif /* do not return in case of entering with TP, still set span_status */ } } } # endif if (killing_chunks) { /* Second call of gvcst_kill2 within TP transaction in gvcst_kill * Kill all hidden subscripts... */ base[end - 3] = STR_SUB_MAXVAL; base[end - 2] = STR_SUB_MAXVAL; base[end - 1] = KEY_DELIMITER; base[end - 0] = KEY_DELIMITER; } else { base[end] = 1; base[++end] = KEY_DELIMITER; base[++end] = KEY_DELIMITER; } } gv_altkey->end = end; if (cdb_sc_normal != (cdb_status = gvcst_search(gv_altkey, alt_hist))) GOTO_RETRY(SKIP_ASSERT_FALSE); if (alt_hist->depth != gvt_hist->depth) { cdb_status = cdb_sc_badlvl; GOTO_RETRY(SKIP_ASSERT_FALSE); } right_extra = FALSE; left_extra = TRUE; for (lev = 0; 0 != gvt_hist->h[lev].blk_num; ++lev) { left = &gvt_hist->h[lev]; right = &alt_hist->h[lev]; assert(0 != right->blk_num); left_rec_stat = left_extra ? &left->prev_rec : &left->curr_rec; if (left->blk_num == right->blk_num) { cdb_status = gvcst_kill_blk(left, lev, gv_currkey, *left_rec_stat, right->curr_rec, right_extra, &tp_cse); assert(!dollar_tlevel || (NULL == tp_cse) || (left->cse == tp_cse)); assert( dollar_tlevel || (NULL == tp_cse)); if (tp_cse) actual_update = UPDTRNS_DB_UPDATED_MASK; if (cdb_sc_normal == cdb_status) break; gv_target->clue.end = 0; /* If need to go up from leaf (or higher), history wont be valid */ if (clue) { /* Clue history valid only for data block, need to re-search */ clue = FALSE; DEBUG_ONLY(dbg_research_cnt++;) goto research; } if (cdb_sc_delete_parent != cdb_status) GOTO_RETRY(SKIP_ASSERT_FALSE); left_extra = right_extra = TRUE; } else { gv_target->clue.end = 0; /* If more than one block involved, history will not be valid */ if (clue) { /* Clue history valid only for data block, need to re-search */ clue = FALSE; DEBUG_ONLY(dbg_research_cnt++;) goto research; } local_srch_rec.offset = ((blk_hdr_ptr_t)left->buffaddr)->bsiz; local_srch_rec.match = 0; cdb_status = gvcst_kill_blk(left, lev, gv_currkey, *left_rec_stat, local_srch_rec, FALSE, &tp_cse); assert(!dollar_tlevel || (NULL == tp_cse) || (left->cse == tp_cse)); assert( dollar_tlevel || (NULL == tp_cse)); if (tp_cse) actual_update = UPDTRNS_DB_UPDATED_MASK; if (cdb_sc_normal == cdb_status) left_extra = FALSE; else if (cdb_sc_delete_parent == cdb_status) { left_extra = TRUE; cdb_status = cdb_sc_normal; } else GOTO_RETRY(SKIP_ASSERT_FALSE); local_srch_rec.offset = local_srch_rec.match = 0; cdb_status = gvcst_kill_blk(right, lev, gv_altkey, local_srch_rec, right->curr_rec, right_extra, &tp_cse); assert(!dollar_tlevel || (NULL == tp_cse) || (right->cse == tp_cse)); assert( dollar_tlevel || (NULL == tp_cse)); if (tp_cse) actual_update = UPDTRNS_DB_UPDATED_MASK; if (cdb_sc_normal == cdb_status) right_extra = FALSE; else if (cdb_sc_delete_parent == cdb_status) { right_extra = TRUE; cdb_status = cdb_sc_normal; } else GOTO_RETRY(SKIP_ASSERT_FALSE); } } } if (!gv_play_duplicate_kills) { /* Determine whether the kill is going to update the db or not. If not, skip the kill altogether. * The variable "actual_update" is set accordingly below. */ if (!dollar_tlevel) { assert(!jnl_format_done); assert(0 == actual_update); /* for non-TP, tp_cse is NULL even if cw_set_depth is non-zero */ if (0 != cw_set_depth) actual_update = UPDTRNS_DB_UPDATED_MASK; /* Reset update_trans (to potentially non-zero value) in case it got set to 0 in previous retry. */ update_trans = actual_update; } else { # ifdef GTM_TRIGGER if (!actual_update) /* possible only if the node we are attempting to KILL does not exist now */ { /* Note that it is possible that the node existed at the time of the "gvcst_dataget" but * got killed later when we did the gvcst_search (right after the "research:" label). This * is possible if any triggers invoked in between KILLed the node and/or all its * descendants. We still want to consider this case as an actual update to the database * as far as journaling is concerned (this is because we have already formatted the * KILL journal record) so set actual_update to UPDTRNS_DB_UPDATED_MASK in this case. * Note that it is possible that the node does not exist now due to a restartable * situation (instead of due to a KILL inside trigger code). In that case, it is safe to * set actual_update to UPDTRNS_DB_UPDATED_MASK (even though we did not do any update to * the database) since we will be restarting anyways. For ZKILL, check if dlr_data was * 1 or 11 and for KILL, check if it was 1, 10 or 11. */ # ifdef DEBUG if (!gvtr_parms.num_triggers_invoked && (do_subtree ? dlr_data : (dlr_data & 1))) { /* Triggers were not invoked but still the node that existed a few * steps above does not exist now. This is a restartable situation. * Assert that. */ assert(!skip_dbtriggers); TREF(donot_commit) |= DONOTCOMMIT_GVCST_KILL_ZERO_TRIGGERS; } # endif if (do_subtree ? dlr_data : (dlr_data & 1)) actual_update = UPDTRNS_DB_UPDATED_MASK; } # endif NON_GTMTRIG_ONLY(assert(!jnl_format_done)); assert(!actual_update || si->cw_set_depth GTMTRIG_ONLY(|| gvtr_parms.num_triggers_invoked || TREF(donot_commit))); assert(!(prev_update_trans & ~UPDTRNS_VALID_MASK)); if (!actual_update) si->update_trans = prev_update_trans; /* restore status prior to redundant KILL */ } } else { /* Since "gv_play_duplicate_kills" is set, irrespective of whether the node/subtree to be * killed exists or not in the db, consider this as a db-updating kill. */ if (!dollar_tlevel) { assert(!jnl_format_done); assert(0 == actual_update); /* for non-TP, tp_cse is NULL even if cw_set_depth is non-zero */ /* See comment above IS_OK_TO_INVOKE_GVCST_KILL macro for why the below assert is the way it is */ assert(!jgbl.forw_phase_recovery || cw_set_depth || (JS_IS_DUPLICATE & jgbl.mur_jrec_nodeflags) || jgbl.mur_options_forward); if (0 != cw_set_depth) actual_update = UPDTRNS_DB_UPDATED_MASK; /* Set update_trans to TRUE unconditionally since we want to play duplicate kills */ update_trans = UPDTRNS_DB_UPDATED_MASK; } else { /* See comment above IS_OK_TO_INVOKE_GVCST_KILL macro for why the below assert is the way it is */ /*assert(!jgbl.forw_phase_recovery || actual_update || (JS_IS_DUPLICATE & jgbl.mur_jrec_nodeflags) || jgbl.mur_options_forward);*/ assert(si->update_trans); } } if (write_logical_jnlrecs && (actual_update || gv_play_duplicate_kills) && !killing_chunks) { /* Maintain journal records only if the kill actually resulted in a database update OR if * "gv_play_duplicate_kills" is TRUE. In the latter case, even though no db blocks will be touched, * it will still increment the db curr_tn and write jnl records. * * skip_dbtriggers is set to TRUE for trigger unsupporting platforms. So, nodeflags will be set to skip * triggers on secondary. This ensures that updates happening in primary (trigger unsupporting platform) * is treated in the same order in the secondary (trigger supporting platform) irrespective of whether * the secondary has defined triggers or not for the global that is being updated. */ if (!dollar_tlevel) { nodeflags = 0; if (skip_dbtriggers) nodeflags |= JS_SKIP_TRIGGERS_MASK; if (!actual_update) { assert(gv_play_duplicate_kills); nodeflags |= JS_IS_DUPLICATE; } assert(!jnl_format_done); jfb = jnl_format(operation, gv_currkey, NULL, nodeflags); assert(NULL != jfb); } else if (!jnl_format_done) { nodeflags = 0; if (skip_dbtriggers) nodeflags |= JS_SKIP_TRIGGERS_MASK; if (!actual_update) { assert(gv_play_duplicate_kills); nodeflags |= JS_IS_DUPLICATE; } # ifdef GTM_TRIGGER /* Do not replicate implicit updates */ assert(tstart_trigger_depth <= gtm_trigger_depth); if (gtm_trigger_depth > tstart_trigger_depth) { /* Ensure that JS_SKIP_TRIGGERS_MASK and JS_NOT_REPLICATED_MASK are mutually exclusive. */ assert(!(nodeflags & JS_SKIP_TRIGGERS_MASK)); nodeflags |= JS_NOT_REPLICATED_MASK; } # endif /* Write KILL journal record */ jfb = jnl_format(operation, gv_currkey, NULL, nodeflags); assert(NULL != jfb); } } flush_cache = FALSE; if (!dollar_tlevel) { if ((0 != csd->dsid) && (0 < kill_set_head.used) && (gvt_hist->h[1].blk_num != alt_hist->h[1].blk_num)) { /* multi-level delete */ rc_cpt_inval(); flush_cache = TRUE; } if (0 < kill_set_head.used) /* increase kill_in_prog */ { need_kip_incr = TRUE; if (!csa->now_crit) /* Do not sleep while holding crit */ WAIT_ON_INHIBIT_KILLS(cnl, MAXWAIT2KILL); } if ((trans_num)0 == t_end(gvt_hist, alt_hist, TN_NOT_SPECIFIED)) { assert(csd == cs_data); /* To ensure they are the same even if MM extensions happened in between */ if (jnl_fence_ctl.level && next_fenced_was_null && actual_update && write_logical_jnlrecs) { /* If ZTransaction and first KILL and the kill resulted in an update * Note that "write_logical_jnlrecs" is used above instead of JNL_WRITE_LOGICAL_RECS(csa) * since the value of the latter macro might have changed inside the call to t_end() * (since jnl state changes could change the JNL_ENABLED check which is part of the macro). */ assert(NULL != csa->next_fenced); assert(jnl_fence_ctl.fence_list == csa); jnl_fence_ctl.fence_list = csa->next_fenced; csa->next_fenced = NULL; } need_kip_incr = FALSE; assert(NULL == kip_csa); /* We could have entered gvcst_kill trying to kill a global that does not exist but later due to a * concurrent set, we are about to retry. In such a case, update_trans could have been set to 0 * (from actual_update above). Reset update_trans to non-zero for the next retry as we expect the * kill to happen in this retry. */ update_trans = UPDTRNS_DB_UPDATED_MASK; continue; } assert(csd == cs_data); /* To ensure they are the same even if MM extensions happened in between */ } else { cdb_status = tp_hist(alt_hist); if (cdb_sc_normal != cdb_status) GOTO_RETRY(SKIP_ASSERT_FALSE); } /* Note down $tlevel (used later) before it is potentially changed by op_tcommit below */ lcl_dollar_tlevel = dollar_tlevel; # ifdef GTM_TRIGGER if (lcl_implicit_tstart) { assert(gvt_root); GVTR_OP_TCOMMIT(cdb_status); if (cdb_sc_normal != cdb_status) GOTO_RETRY(SKIP_ASSERT_TRUE); } # endif if (!killing_chunks) INCR_GVSTATS_COUNTER(csa, cnl, n_kill, 1); if (gvt_root && (0 != gv_target->clue.end)) { /* If clue is still valid, then the deletion was confined to a single block */ assert(gvt_hist->h[0].blk_num == alt_hist->h[0].blk_num); /* In this case, the "right hand" key (which was searched via gv_altkey) was the last search * and should become the clue. Furthermore, the curr.match from this last search should be * the history's curr.match. However, this record will have been shuffled to the position of * the "left hand" key, and therefore, the original curr.offset should be left untouched. */ gvt_hist->h[0].curr_rec.match = alt_hist->h[0].curr_rec.match; COPY_CURRKEY_TO_GVTARGET_CLUE(gv_target, gv_altkey); } NON_GTMTRIG_ONLY(assert(lcl_dollar_tlevel == dollar_tlevel)); if (!lcl_dollar_tlevel) { assert(!dollar_tlevel); assert(0 < kill_set_head.used || (NULL == kip_csa)); if (0 < kill_set_head.used) /* free subtree, decrease kill_in_prog */ { /* If csd->dsid is non-zero then some rc code was exercised before the changes * to prevent pre-commit expansion of the kill subtree. Not clear on what to do now. */ assert(!csd->dsid); ENABLE_WBTEST_ABANDONEDKILL; gvcst_expand_free_subtree(&kill_set_head); assert(csd == cs_data); /* To ensure they are the same even if MM extensions happened in between */ DECR_KIP(csd, csa, kip_csa); } assert(0 < kill_set_head.used || (NULL == kip_csa)); for (ks = kill_set_head.next_kill_set; NULL != ks; ks = temp_ks) { temp_ks = ks->next_kill_set; free(ks); } assert(0 < kill_set_head.used || (NULL == kip_csa)); } GTMTRIG_ONLY(assert(NULL == ztold_mval)); return; retry: # ifdef GTM_TRIGGER if (lcl_implicit_tstart) { assert(!skip_dbtriggers); assert(!skip_INVOKE_RESTART); assert((cdb_sc_normal != cdb_status) || (ERR_TPRETRY == gtm_trig_status)); if (cdb_sc_normal != cdb_status) skip_INVOKE_RESTART = TRUE; /* causes t_retry to invoke only tp_restart without any rts_error */ /* else: t_retry has already been done by gtm_trigger so no need to do it again for this try */ } # endif assert((cdb_sc_normal != cdb_status) GTMTRIG_ONLY(|| lcl_implicit_tstart || *span_status)); if (cdb_sc_normal != cdb_status) { GTMTRIG_ONLY(POP_MVALS_FROM_M_STACK_IF_NEEDED(ztold_mval, save_msp, save_mv_chain)); t_retry(cdb_status); GTMTRIG_ONLY(skip_INVOKE_RESTART = FALSE); } else { /* else: t_retry has already been done so no need to do that again but need to still invoke tp_restart * to complete pending "tprestart_state" related work. */ # ifdef GTM_TRIGGER assert(ERR_TPRETRY == gtm_trig_status); TRIGGER_BASE_FRAME_UNWIND_IF_NOMANSLAND; POP_MVALS_FROM_M_STACK_IF_NEEDED(ztold_mval, save_msp, save_mv_chain); if (!lcl_implicit_tstart) { /* We started an implicit transaction for spanning nodes in gvcst_kill. Invoke restart to return. */ assert(*span_status && !skip_INVOKE_RESTART && (&gvcst_kill_ch == ctxt->ch)); INVOKE_RESTART; } # endif rc = tp_restart(1, !TP_RESTART_HANDLES_ERRORS); assert(0 == rc GTMTRIG_ONLY(&& TPRESTART_STATE_NORMAL == tprestart_state)); } assert(0 < t_tries); # ifdef GTM_TRIGGER if (lcl_implicit_tstart) { SET_WANT_ROOT_SEARCH(cdb_status, want_root_search); assert(!skip_INVOKE_RESTART); /* if set to TRUE above, should have been reset by t_retry */ } # endif /* At this point, we can be in TP only if we implicitly did a tstart in gvcst_kill (as part of a trigger update). * Assert that. Since the t_retry/tp_restart would have reset si->update_trans, we need to set it again. * So reinvoke the T_BEGIN call only in case of TP. For non-TP, update_trans is unaffected by t_retry. */ assert(!dollar_tlevel GTMTRIG_ONLY(|| lcl_implicit_tstart)); if (dollar_tlevel) { /* op_ztrigger has similar code and should be maintained in parallel */ tp_set_sgm(); /* set sgm_info_ptr & first_sgm_info for TP start */ T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_GVKILLFAIL); /* set update_trans and t_err for wrapped TP */ } else { /* We could have entered gvcst_kill trying to kill a global that does not exist but later due to a * concurrent set, came here for retry. In such a case, update_trans could have been set to 0 * (from actual_update). Reset update_trans to non-zero for the next retry as we expect the kill to * happen in this retry. */ update_trans = UPDTRNS_DB_UPDATED_MASK; } assert(csd == cs_data); /* To ensure they are the same even if MM extensions happened in between */ } } fis-gtm-V6.0-003/sr_port/gvcst_kill_blk.c0000644000032200000250000003314212201176157017174 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gdskill.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "cdb_sc.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "copy.h" #include "gdscc.h" #include "filestruct.h" #include "jnl.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* Include prototypes */ #include "t_write.h" #include "t_create.h" #include "gvcst_delete_blk.h" #include "gvcst_kill_blk.h" GBLREF sgmnt_data_ptr_t cs_data; GBLREF gv_namehead *gv_target; GBLREF char *update_array, *update_array_ptr; GBLREF uint4 update_array_size; /* for the BLK_* macros */ GBLREF sgmnt_addrs *cs_addrs; GBLREF unsigned int t_tries; GBLREF uint4 dollar_tlevel; GBLREF sgm_info *sgm_info_ptr; GBLREF boolean_t horiz_growth; /* delete all records greater than low and less than high in blkhist->blk_num */ enum cdb_sc gvcst_kill_blk(srch_blk_status *blkhist, char level, gv_key *search_key, srch_rec_status low, srch_rec_status high, boolean_t right_extra, cw_set_element **cseptr) { typedef sm_uc_ptr_t bytptr; unsigned short temp_ushort; int4 temp_long; int tmp_cmpc; int blk_size, blk_seg_cnt, lmatch, rmatch, targ_len, prev_len, targ_base, next_rec_shrink, temp_int, blkseglen; bool kill_root, first_copy; blk_hdr_ptr_t old_blk_hdr; rec_hdr_ptr_t left_ptr; /*pointer to record before first record to delete*/ rec_hdr_ptr_t del_ptr; /*pointer to first record to delete*/ rec_hdr_ptr_t right_ptr; /*pointer to record after last record to delete*/ rec_hdr_ptr_t right_prev_ptr; rec_hdr_ptr_t rp, rp1; /*scratch record pointer*/ rec_hdr_ptr_t first_in_blk, top_of_block, new_rec_hdr, star_rec_hdr; blk_segment *bs1, *bs_ptr; block_index new_block_index; unsigned char *skb; static readonly block_id zeroes = 0; cw_set_element *cse, *old_cse; bytptr curr, prev, right_bytptr; off_chain chain1, curr_chain, prev_chain; block_id blk; sm_uc_ptr_t buffer; *cseptr = NULL; if (low.offset == high.offset) return cdb_sc_normal; blk = blkhist->blk_num; if (dollar_tlevel) { PUT_LONG(&chain1, blk); if ((1 == chain1.flag) && ((int)chain1.cw_index >= sgm_info_ptr->cw_set_depth)) { assert(sgm_info_ptr->tp_csa == cs_addrs); assert(FALSE == cs_addrs->now_crit); return cdb_sc_blknumerr; } } buffer = blkhist->buffaddr; old_blk_hdr = (blk_hdr_ptr_t)buffer; kill_root = FALSE; blk_size = cs_data->blk_size; first_in_blk = (rec_hdr_ptr_t)((bytptr)old_blk_hdr + SIZEOF(blk_hdr)); top_of_block = (rec_hdr_ptr_t)((bytptr)old_blk_hdr + old_blk_hdr->bsiz); left_ptr = (rec_hdr_ptr_t)((bytptr)old_blk_hdr + low.offset); right_ptr = (rec_hdr_ptr_t)((bytptr)old_blk_hdr + high.offset); if (right_extra && right_ptr < top_of_block) { right_prev_ptr = right_ptr; GET_USHORT(temp_ushort, &right_ptr->rsiz); right_ptr = (rec_hdr_ptr_t)((bytptr)right_ptr + temp_ushort); } if ((bytptr)left_ptr < (bytptr)old_blk_hdr || (bytptr)right_ptr > (bytptr)top_of_block || (bytptr)left_ptr >= (bytptr)right_ptr) { assert(CDB_STAGNATE > t_tries); return cdb_sc_rmisalign; } if ((bytptr)left_ptr == (bytptr)old_blk_hdr) { if ((bytptr)right_ptr == (bytptr)top_of_block) { if ((bytptr)first_in_blk == (bytptr)top_of_block) { if (0 != level) { assert(CDB_STAGNATE > t_tries); return cdb_sc_rmisalign; } return cdb_sc_normal; } if (!gv_target->hist.h[level + 1].blk_num) kill_root = TRUE; else return cdb_sc_delete_parent; } del_ptr = first_in_blk; } else { GET_USHORT(temp_ushort, &left_ptr->rsiz); del_ptr = (rec_hdr_ptr_t)((bytptr)left_ptr + temp_ushort); if ((bytptr)del_ptr <= (bytptr)(left_ptr + 1) || (bytptr)del_ptr > (bytptr)right_ptr) { assert(CDB_STAGNATE > t_tries); return cdb_sc_rmisalign; } } if ((bytptr)del_ptr == (bytptr)right_ptr) return cdb_sc_normal; lmatch = low.match; rmatch = high.match; if (level) { for (rp = del_ptr ; rp < right_ptr ; rp = rp1) { GET_USHORT(temp_ushort, &rp->rsiz); rp1 = (rec_hdr_ptr_t)((bytptr)rp + temp_ushort); if (((bytptr)rp1 < (bytptr)(rp + 1) + SIZEOF(block_id)) || ((bytptr)rp1 < buffer) || ((bytptr)rp1 > (buffer + blk_size))) { assert(CDB_STAGNATE > t_tries); return cdb_sc_rmisalign; } GET_LONG(temp_long, ((bytptr)rp1 - SIZEOF(block_id))); if (dollar_tlevel) { chain1 = *(off_chain *)&temp_long; if ((1 == chain1.flag) && ((int)chain1.cw_index >= sgm_info_ptr->cw_set_depth)) { assert(sgm_info_ptr->tp_csa == cs_addrs); assert(FALSE == cs_addrs->now_crit); return cdb_sc_blknumerr; } } gvcst_delete_blk(temp_long, level - 1, FALSE); } } if (kill_root) { /* create an empty data block */ BLK_INIT(bs_ptr, bs1); if (!BLK_FINI(bs_ptr, bs1)) { assert(CDB_STAGNATE > t_tries); return cdb_sc_mkblk; } new_block_index = t_create(blk, (uchar_ptr_t)bs1, 0, 0, 0); /* create index block */ BLK_ADDR(new_rec_hdr, SIZEOF(rec_hdr), rec_hdr); new_rec_hdr->rsiz = SIZEOF(rec_hdr) + SIZEOF(block_id); SET_CMPC(new_rec_hdr, 0); BLK_INIT(bs_ptr, bs1); BLK_SEG(bs_ptr, (bytptr)new_rec_hdr, SIZEOF(rec_hdr)); BLK_SEG(bs_ptr, (bytptr)&zeroes, SIZEOF(block_id)); if (!BLK_FINI(bs_ptr, bs1)) { assert(CDB_STAGNATE > t_tries); return cdb_sc_mkblk; } cse = t_write(blkhist, (unsigned char *)bs1, SIZEOF(blk_hdr) + SIZEOF(rec_hdr), new_block_index, 1, TRUE, FALSE, GDS_WRITE_KILLTN); assert(!dollar_tlevel || !cse->high_tlevel); *cseptr = cse; if (NULL != cse) cse->first_off = 0; return cdb_sc_normal; } next_rec_shrink = (int)(old_blk_hdr->bsiz + ((bytptr)del_ptr - (bytptr)right_ptr)); if (SIZEOF(blk_hdr) >= next_rec_shrink) { assert(CDB_STAGNATE > t_tries); return cdb_sc_rmisalign; } if ((bytptr)right_ptr == (bytptr)top_of_block) { if (level) { GET_USHORT(temp_ushort, &left_ptr->rsiz); next_rec_shrink += SIZEOF(rec_hdr) + SIZEOF(block_id) - temp_ushort; } } else { targ_base = (rmatch < lmatch) ? rmatch : lmatch; prev_len = 0; if (right_extra) { EVAL_CMPC2(right_prev_ptr, tmp_cmpc); targ_len = tmp_cmpc - targ_base; if (targ_len < 0) targ_len = 0; temp_int = tmp_cmpc - EVAL_CMPC(right_ptr); if (0 >= temp_int) prev_len = - temp_int; else { if (temp_int < targ_len) targ_len -= temp_int; else targ_len = 0; } } else { targ_len = EVAL_CMPC(right_ptr) - targ_base; if (targ_len < 0) targ_len = 0; } next_rec_shrink += targ_len + prev_len; } BLK_INIT(bs_ptr, bs1); first_copy = TRUE; blkseglen = (int)((bytptr)del_ptr - (bytptr)first_in_blk); if (0 < blkseglen) { if (((bytptr)right_ptr != (bytptr)top_of_block) || (0 == level)) { BLK_SEG(bs_ptr, (bytptr)first_in_blk, blkseglen); first_copy = FALSE; } else { blkseglen = (int)((bytptr)left_ptr - (bytptr)first_in_blk); if (0 < blkseglen) { BLK_SEG(bs_ptr, (bytptr)first_in_blk, blkseglen); first_copy = FALSE; } BLK_ADDR(star_rec_hdr, SIZEOF(rec_hdr), rec_hdr); SET_CMPC(star_rec_hdr, 0); star_rec_hdr->rsiz = (unsigned short)(SIZEOF(rec_hdr) + SIZEOF(block_id)); BLK_SEG(bs_ptr, (bytptr)star_rec_hdr, SIZEOF(rec_hdr)); GET_USHORT(temp_ushort, &left_ptr->rsiz); BLK_SEG(bs_ptr, ((bytptr)left_ptr + temp_ushort - SIZEOF(block_id)), SIZEOF(block_id)); } } blkseglen = (int)((bytptr)top_of_block - (bytptr)right_ptr); assert(0 <= blkseglen); if (0 != blkseglen) { next_rec_shrink = targ_len + prev_len; if (0 >= next_rec_shrink) { BLK_SEG(bs_ptr, (bytptr)right_ptr, blkseglen); } else { BLK_ADDR(new_rec_hdr, SIZEOF(rec_hdr), rec_hdr); SET_CMPC(new_rec_hdr, EVAL_CMPC(right_ptr) - next_rec_shrink); GET_USHORT(temp_ushort, &right_ptr->rsiz); new_rec_hdr->rsiz = temp_ushort + next_rec_shrink; BLK_SEG(bs_ptr, (bytptr)new_rec_hdr, SIZEOF(rec_hdr)); if (targ_len) { BLK_ADDR(skb, targ_len, unsigned char); memcpy(skb, &search_key->base[targ_base], targ_len); BLK_SEG(bs_ptr, skb, targ_len); } if (prev_len) BLK_SEG(bs_ptr, (bytptr)(right_prev_ptr + 1) , prev_len); right_bytptr = (bytptr)(right_ptr + 1); blkseglen = (int)((bytptr)top_of_block - right_bytptr); if (0 < blkseglen) { BLK_SEG(bs_ptr, right_bytptr, blkseglen); } else { assert(CDB_STAGNATE > t_tries); return cdb_sc_rmisalign; } } } if (!BLK_FINI(bs_ptr, bs1)) { assert(CDB_STAGNATE > t_tries); return cdb_sc_mkblk; } cse = t_write(blkhist, (unsigned char *)bs1, 0, 0, level, first_copy, TRUE, GDS_WRITE_KILLTN); assert(!dollar_tlevel || !cse->high_tlevel); *cseptr = cse; if (horiz_growth) { old_cse = cse->low_tlevel; assert(old_cse && old_cse->done); assert(2 == (SIZEOF(old_cse->undo_offset) / SIZEOF(old_cse->undo_offset[0]))); assert(2 == (SIZEOF(old_cse->undo_next_off) / SIZEOF(old_cse->undo_next_off[0]))); assert(!old_cse->undo_next_off[0] && !old_cse->undo_offset[0]); assert(!old_cse->undo_next_off[1] && !old_cse->undo_offset[1]); } if ((NULL != cse) && (0 != cse->first_off)) { /* fix up chains in the block to account for deleted records */ prev = NULL; curr = buffer + cse->first_off; GET_LONGP(&curr_chain, curr); while (curr < (bytptr)del_ptr) { /* follow chain to first deleted record */ if (0 == curr_chain.next_off) break; if (right_ptr == top_of_block && (bytptr)del_ptr - curr == SIZEOF(off_chain)) break; /* special case described below: stop just before the first deleted record */ prev = curr; curr += curr_chain.next_off; GET_LONGP(&curr_chain, curr); } if (right_ptr == top_of_block && (bytptr)del_ptr - curr == SIZEOF(off_chain)) { /* if the right side of the block is gone and our last chain is in the last record, * terminate the chain and adjust the previous entry to point at the new *-key * NOTE: this assumes there's NEVER a TP delete of records in the GVT */ assert(0 != level); /* store next_off in old_cse before actually changing it in the buffer(for rolling back) */ if (horiz_growth) { old_cse->undo_next_off[0] = curr_chain.next_off; old_cse->undo_offset[0] = (block_offset)(curr - buffer); assert(old_cse->undo_offset[0]); } curr_chain.next_off = 0; GET_LONGP(curr, &curr_chain); if (NULL != prev) { /* adjust previous chain next_off to reflect the fact that the record it refers to is now a *-key */ GET_LONGP(&prev_chain, prev); /* store next_off in old_cse before actually changing it in the buffer(for rolling back) */ if (horiz_growth) { old_cse->undo_next_off[1] = prev_chain.next_off; old_cse->undo_offset[1] = (block_offset)(prev - buffer); assert(old_cse->undo_offset[1]); } prev_chain.next_off = (unsigned int)((bytptr)left_ptr - prev + (unsigned int)(SIZEOF(rec_hdr))); GET_LONGP(prev, &prev_chain); } else /* it's the first (and only) one */ cse->first_off = (block_offset)((bytptr)left_ptr - buffer + SIZEOF(rec_hdr)); } else if (curr >= (bytptr)del_ptr) { /* may be more records on the right that aren't deleted */ while (curr < (bytptr)right_ptr) { /* follow chain past last deleted record */ if (0 == curr_chain.next_off) break; curr += curr_chain.next_off; GET_LONGP(&curr_chain, curr); } /* prev : ptr to chain record immediately preceding the deleted area, * or 0 if none. * * curr : ptr to chain record immediately following the deleted area, * or to last chain record. */ if (curr < (bytptr)right_ptr) { /* the former end of the chain is going, going, gone */ if (NULL != prev) { /* terminate the chain before the delete */ GET_LONGP(&prev_chain, prev); /* store next_off in old_cse before actually changing it in the buffer(for rolling back) */ if (horiz_growth) { old_cse->undo_next_off[0] = prev_chain.next_off; old_cse->undo_offset[0] = (block_offset)(prev - buffer); assert(old_cse->undo_offset[0]); } prev_chain.next_off = 0; GET_LONGP(prev, &prev_chain); } else cse->first_off = 0; /* the whole chain is gone */ } else { /* stitch up the left and right to account for the hole in the middle */ /* next_rec_shrink is the change in record size due to the new compression count */ if (NULL != prev) { GET_LONGP(&prev_chain, prev); /* ??? new compression may be less (ie +) so why are negative shrinks ignored? */ /* store next_off in old_cse before actually changing it in the buffer(for rolling back) */ if (horiz_growth) { old_cse->undo_next_off[0] = prev_chain.next_off; old_cse->undo_offset[0] = (block_offset)(prev - buffer); assert(old_cse->undo_offset[0]); } prev_chain.next_off = (unsigned int)(curr - prev - ((bytptr)right_ptr - (bytptr)del_ptr) + (next_rec_shrink > 0 ? next_rec_shrink : 0)); GET_LONGP(prev, &prev_chain); } else /* curr remains first: adjust the head */ cse->first_off = (block_offset)(curr - buffer - ((bytptr)right_ptr - (bytptr)del_ptr) + (next_rec_shrink > 0 ? next_rec_shrink : 0)); } } } horiz_growth = FALSE; return cdb_sc_normal; } fis-gtm-V6.0-003/sr_port/gvcst_kill_blk.h0000644000032200000250000000140312201176157017174 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2005 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GVCST_KILL_BLK_DEFINED /* Declare parms for gvcst_kill_blk.c */ enum cdb_sc gvcst_kill_blk (srch_blk_status *blkhist, char level, gv_key *search_key, srch_rec_status low, srch_rec_status high, boolean_t right_extra, cw_set_element **cseptr); #define GVCST_KILL_BLK_DEFINED #endif fis-gtm-V6.0-003/sr_port/gvcst_kill_sort.c0000644000032200000250000000316512201176157017415 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdskill.h" #include "gvcst_kill_sort.h" #define S_CUTOFF 15 void gvcst_kill_sort(kill_set *k) { block_id_ptr_t stack[50],*sp; block_id v,t; block_id_ptr_t l,r; block_id_ptr_t ix,jx,kx; assert(k->used <= BLKS_IN_KILL_SET); sp = stack; l = (block_id_ptr_t)(k->blk); r = l + k->used-1; for (;;) if (r - l < S_CUTOFF) { for (ix = l + 1 ; ix <= r ; ix++) { for (jx = ix , t = *ix; jx > l && *(jx-1) > t; jx--) *jx = *(jx - 1); *jx = t; } if (sp <= stack) break; else { l = *--sp; r = *--sp; } } else { ix = l; jx = r; kx = l + ((int)(r - l) / 2); kx = (*ix > *jx) ? ((*jx > *kx) ? jx: ((*ix > *kx) ? kx : ix)): ((*jx < *kx) ? jx: ((*ix > *kx) ? ix : kx)); t = *kx; *kx = *jx; *jx = t; ix--; do { do ix++; while (*ix < t); do jx--; while (*jx > t); v = *ix; *ix = *jx; *jx = v; } while (jx > ix); *jx = *ix; *ix = *r; *r = v; if (ix - l > r - ix) { *sp++ = ix - 1; *sp++ = l; l = ix + 1; } else { *sp++ = r; *sp++ = ix + 1; r = ix - 1; } } return; } fis-gtm-V6.0-003/sr_port/gvcst_kill_sort.h0000644000032200000250000000104712201176157017417 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GVCST_KILL_SORT_H__ #define __GVCST_KILL_SORT_H__ void gvcst_kill_sort(kill_set *k); #endif fis-gtm-V6.0-003/sr_port/gvcst_lbm_check.c0000644000032200000250000000454512201176157017325 0ustar librarygtc/**************************************************************** * * * Copyright 2005, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gdskill.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdsbml.h" #include "gvcst_lbm_check.h" /* Routines for checking status of database blocks using a given local bitmap */ /* There are two bits that denote the status of a block in the local bitmap: 0b00 busy 0b01 free 0b10 invalid 0b11 recycled (but free) The low order bit can be used to denote busy or free so that is what is actually tested. Inputs: 1) pointer to local bit map data (blk_ptr + SIZEOF(blk_hdr)). 2) bit offset to test into bitmap. */ boolean_t gvcst_blk_is_allocated(uchar_ptr_t lbmap, int lm_offset) { int uchar_offset, uchar_offset_rem; unsigned char result_byte; uchar_ptr_t map_byte; assert(BLKS_PER_LMAP * BML_BITS_PER_BLK > lm_offset); uchar_offset = lm_offset / BITS_PER_UCHAR; uchar_offset_rem = lm_offset % BITS_PER_UCHAR; map_byte = lbmap + uchar_offset; result_byte = (*map_byte >> uchar_offset_rem) & 0x3; switch(result_byte) { case 0x00: return TRUE; case 0x01: case 0x03: return FALSE; default: GTMASSERT; } return FALSE; /* Can't get here but keep compiler happy */ } /* Similarly this routine tells if the block was EVER allocated (allocated or recycled) */ boolean_t gvcst_blk_ever_allocated(uchar_ptr_t lbmap, int lm_offset) { int uchar_offset, uchar_offset_rem; unsigned char result_byte; uchar_ptr_t map_byte; assert(BLKS_PER_LMAP * BML_BITS_PER_BLK > lm_offset); uchar_offset = lm_offset / BITS_PER_UCHAR; uchar_offset_rem = lm_offset % BITS_PER_UCHAR; map_byte = lbmap + uchar_offset; result_byte = (*map_byte >> uchar_offset_rem) & 0x3; switch(result_byte) { case 0x00: case 0x03: return TRUE; case 0x01: return FALSE; default: GTMASSERT; } return FALSE; /* Can't get here but keep compiler happy */ } fis-gtm-V6.0-003/sr_port/gvcst_lbm_check.h0000644000032200000250000000120712201176157017322 0ustar librarygtc/**************************************************************** * * * Copyright 2005 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GVCST_LBM_CHECK_H #define GVCST_LBM_CHECK_H boolean_t gvcst_blk_is_allocated(uchar_ptr_t lbmap, int lm_offset); boolean_t gvcst_blk_ever_allocated(uchar_ptr_t lbmap, int lm_offset); #endif fis-gtm-V6.0-003/sr_port/gvcst_lftsib.c0000644000032200000250000000612112201176157016671 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "cdb_sc.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "copy.h" /* Include prototypes */ #include "t_qread.h" #include "gvcst_protos.h" /* for gvcst_search_blk,gvcst_lftsib prototype */ /* WARNING: assumes that the search history for the current target is in gv_target.hist */ GBLREF sgmnt_addrs *cs_addrs; GBLREF gv_namehead *gv_target; GBLREF gv_key *gv_currkey; GBLREF unsigned char rdfail_detail; GBLREF srch_blk_status *first_tp_srch_status; /* overriding value of srch_blk_status given by t_qread in case of TP */ GBLREF unsigned int t_tries; enum cdb_sc gvcst_lftsib(srch_hist *full_hist) { srch_blk_status *old, *new, *old_base, *new_base; rec_hdr_ptr_t rp; unsigned short rec_size; enum cdb_sc ret_val; block_id blk; unsigned short rtop, temp_short; sm_uc_ptr_t buffer_address, bp; int4 cycle; new_base = &full_hist->h[0]; old = old_base = &gv_target->hist.h[0]; for (;;) { buffer_address = old->buffaddr; temp_short = old->prev_rec.offset; if (temp_short > 0) break; old++; if (0 == old->blk_num) return cdb_sc_endtree; if (old->cr && (old->blk_num != old->cr->blk)) { assert(CDB_STAGNATE > t_tries); return cdb_sc_lostcr; } if (cdb_sc_normal != (ret_val = gvcst_search_blk(gv_currkey, old))) return ret_val; } /* old now points to the first block which had a non-zero prev_rec.offset */ new = new_base + (old - old_base + 1); full_hist->depth = (uint4)(old - old_base); (new--)->blk_num = 0; new->blk_num = old->blk_num; new->tn = old->tn; new->cse = NULL; new->first_tp_srch_status = old->first_tp_srch_status; assert(new->level == old->level); assert(new->blk_target == old->blk_target); new->buffaddr = old->buffaddr; new->curr_rec = old->prev_rec; new->cycle = old->cycle; new->cr = old->cr; temp_short = new->curr_rec.offset; rp = (rec_hdr_ptr_t)(temp_short + new->buffaddr); GET_USHORT(rec_size, &rp->rsiz); rtop = temp_short + rec_size; if (((blk_hdr_ptr_t)new->buffaddr)->bsiz < rtop) return cdb_sc_rmisalign; bp = new->buffaddr; while (--new >= new_base) { --old; GET_LONG(blk, ((sm_int_ptr_t)(bp + rtop - SIZEOF(block_id)))); new->tn = cs_addrs->ti->curr_tn; new->cse = NULL; if (NULL == (buffer_address = t_qread(blk, &new->cycle, &new->cr))) return((enum cdb_sc)rdfail_detail); new->first_tp_srch_status = first_tp_srch_status; assert(new->level == old->level); assert(new->blk_target == old->blk_target); new->blk_num = blk; new->buffaddr = buffer_address; bp = new->buffaddr; rtop = ((blk_hdr_ptr_t)new->buffaddr)->bsiz; } return cdb_sc_normal; } fis-gtm-V6.0-003/sr_port/gvcst_map_build.c0000644000032200000250000000430012201176157017337 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "gdscc.h" #include "gdsbml.h" #include "send_msg.h" /* prototypes */ #include "gvcst_map_build.h" #include "min_max.h" #include "wbox_test_init.h" GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; void gvcst_map_build(uint4 *array, sm_uc_ptr_t base_addr, cw_set_element *cs, trans_num ctn) { boolean_t status; uint4 (*bml_func)(); uint4 bitnum, ret; #ifdef DEBUG int4 prev_bitnum, actual_cnt = 0; if (!gtm_white_box_test_case_enabled || (WBTEST_ANTIFREEZE_DBBMLCORRUPT != gtm_white_box_test_case_number)) { VALIDATE_BM_BLK(cs->blk, (blk_hdr_ptr_t)base_addr, cs_addrs, gv_cur_region, status); assert(status); /* assert it is a valid bitmap block */ } #endif ((blk_hdr_ptr_t)base_addr)->tn = ctn; base_addr += SIZEOF(blk_hdr); assert(cs_addrs->now_crit); /* Don't want to be messing with highest_lbm_with_busy_blk outside crit */ DETERMINE_BML_FUNC(bml_func, cs, cs_addrs); DEBUG_ONLY(prev_bitnum = -1;) while (bitnum = *array) /* caution : intended assignment */ { assert((uint4)bitnum < cs_addrs->hdr->bplmap); /* check that bitnum is positive and within 0 to bplmap */ assert((int4)bitnum > prev_bitnum); /* assert that blocks are sorted in the update array */ ret = (* bml_func)(bitnum, base_addr); DEBUG_ONLY( if (cs->reference_cnt > 0) actual_cnt++; /* block is being marked busy */ else if (!ret) actual_cnt--; /* block is transitioning from BUSY to either RECYCLED or FREE */ /* all other state changes do not involve updates to the free_blocks count */ ) array++; DEBUG_ONLY(prev_bitnum = (int4)bitnum); } assert(actual_cnt == cs->reference_cnt); } fis-gtm-V6.0-003/sr_port/gvcst_map_build.h0000644000032200000250000000120612201176157017346 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GVCST_MAP_BUILD_INCLUDED #define GVCST_MAP_BUILD_INCLUDED void gvcst_map_build(uint4 *array, sm_uc_ptr_t base_addr, cw_set_element *cs, trans_num ctn); #endif /* GVCST_MAP_BUILD_INCLUDED */ fis-gtm-V6.0-003/sr_port/gvcst_order.c0000644000032200000250000001607312201176157016530 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "cdb_sc.h" #include "copy.h" #include "filestruct.h" /* needed for jnl.h */ #include "gdscc.h" /* needed for tp.h */ #include "jnl.h" /* needed for tp.h */ #include "gdskill.h" /* needed for tp.h */ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* needed for T_BEGIN_READ_NONTP_OR_TP macro */ #ifdef UNIX /* needed for frame_pointer in GVCST_ROOT_SEARCH_AND_PREP macro */ # include "repl_msg.h" # include "gtmsource.h" # include "rtnhdr.h" # include "stack_frame.h" # include "wbox_test_init.h" #endif #include "t_end.h" /* prototypes */ #include "t_retry.h" #include "t_begin.h" #include "gvcst_protos.h" /* for gvcst_rtsib,gvcst_search,gvcst_search_blk,gvcst_order prototype */ /* needed for spanning nodes */ #include "op.h" #include "op_tcommit.h" #include "error.h" #include "tp_frame.h" #include "tp_restart.h" #include "gtmimagename.h" LITREF mval literal_batch; GBLREF sgmnt_data_ptr_t cs_data; GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF gv_namehead *gv_target; GBLREF gv_key *gv_currkey, *gv_altkey; GBLREF int4 gv_keysize; GBLREF uint4 dollar_tlevel; GBLREF unsigned int t_tries; error_def(ERR_DBROLLEDBACK); error_def(ERR_GVORDERFAIL); error_def(ERR_TPRETRY); DEFINE_NSB_CONDITION_HANDLER(gvcst_order_ch) bool gvcst_order(void) { /* See gvcst_query.c */ bool found, is_hidden, sn_tpwrapped; boolean_t est_first_pass; char save_currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)]; gv_key *save_gv_currkey; int end, prev, oldend; int save_dollar_tlevel; DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); found = gvcst_order2(); # ifdef UNIX assert(save_dollar_tlevel == dollar_tlevel); CHECK_HIDDEN_SUBSCRIPT_AND_RETURN(found, gv_altkey, is_hidden); assert(found && is_hidden); IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(return found); SAVE_GV_CURRKEY_LAST_SUBSCRIPT(gv_currkey, prev, oldend); if (!dollar_tlevel) { sn_tpwrapped = TRUE; op_tstart((IMPLICIT_TSTART), TRUE, &literal_batch, 0); ESTABLISH_NORET(gvcst_order_ch, est_first_pass); GVCST_ROOT_SEARCH_AND_PREP(est_first_pass); } else sn_tpwrapped = FALSE; INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_order, (gtm_uint64_t) -1); found = gvcst_order2(); if (found) { CHECK_HIDDEN_SUBSCRIPT(gv_altkey, is_hidden); if (is_hidden) { /* Replace last subscript to be the highest possible hidden subscript so another * gvcst_order2 will give us the next non-hidden subscript. */ end = gv_altkey->end; gv_currkey->base[end - 4] = 2; gv_currkey->base[end - 3] = 0xFF; gv_currkey->base[end - 2] = 0xFF; gv_currkey->base[end - 1] = 1; gv_currkey->base[end + 0] = 0; gv_currkey->base[end + 1] = 0; gv_currkey->end = end + 1; /* fix up since it should only be externally counted as one $order */ INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_order, (gtm_uint64_t) -1); found = gvcst_order2(); } } if (sn_tpwrapped) { op_tcommit(); REVERT; /* remove our condition handler */ } RESTORE_GV_CURRKEY_LAST_SUBSCRIPT(gv_currkey, prev, oldend); assert(save_dollar_tlevel == dollar_tlevel); # endif return found; } bool gvcst_order2(void) { blk_hdr_ptr_t bp; boolean_t found, two_histories; enum cdb_sc status; rec_hdr_ptr_t rp; unsigned short rec_size; srch_blk_status *bh; srch_hist *rt_history; sm_uc_ptr_t c1, c2, ctop, alt_top; int tmp_cmpc; T_BEGIN_READ_NONTP_OR_TP(ERR_GVORDERFAIL); for (;;) { assert(t_tries < CDB_STAGNATE || cs_addrs->now_crit); /* we better hold crit in the final retry (TP & non-TP) */ two_histories = FALSE; #if defined(DEBUG) && defined(UNIX) if (gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_GVORDERFAIL == gtm_white_box_test_case_number)) { status = cdb_sc_blknumerr; t_retry(status); continue; } #endif if (cdb_sc_normal == (status = gvcst_search(gv_currkey, NULL))) { found = TRUE; bh = gv_target->hist.h; rp = (rec_hdr_ptr_t)(bh->buffaddr + bh->curr_rec.offset); bp = (blk_hdr_ptr_t)bh->buffaddr; if ((rec_hdr_ptr_t)CST_TOB(bp) <= rp) { two_histories = TRUE; rt_history = gv_target->alt_hist; status = gvcst_rtsib(rt_history, 0); if (cdb_sc_normal == status) { bh = rt_history->h; if (cdb_sc_normal != (status = gvcst_search_blk(gv_currkey, bh))) { t_retry(status); continue; } rp = (rec_hdr_ptr_t)(bh->buffaddr + bh->curr_rec.offset); bp = (blk_hdr_ptr_t)bh->buffaddr; } else { if (cdb_sc_endtree == status) { found = FALSE; two_histories = FALSE; /* second history not valid */ } else { t_retry(status); continue; } } } if (found) { assert(gv_altkey->top == gv_currkey->top); assert(gv_altkey->top == gv_keysize); assert(gv_altkey->end < gv_altkey->top); /* store new subscipt */ c1 = gv_altkey->base; alt_top = gv_altkey->base + gv_altkey->top - 1; /* Make alt_top one less than gv_altkey->top to allow double-null at end of a key-name */ /* 4/17/96 * HP compiler bug work-around. The original statement was * c2 = (unsigned char *)CST_BOK(rp) + bh->curr_rec.match - rp->cmpc; * * ...but this was sometimes compiled incorrectly (the lower 4 bits * of rp->cmpc, sign extended, were subtracted from bh->curr_rec.match). * I separated out the subtraction of rp->cmpc. * * -VTF. */ c2 = (sm_uc_ptr_t)CST_BOK(rp) + bh->curr_rec.match; memcpy(c1, gv_currkey->base, bh->curr_rec.match); c1 += bh->curr_rec.match; c2 -= EVAL_CMPC(rp); GET_USHORT(rec_size, &rp->rsiz); ctop = (sm_uc_ptr_t)rp + rec_size; for (;;) { if (c2 >= ctop || c1 >= alt_top) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_rmisalign; goto restart; /* goto needed because of nested FOR loop */ } if (0 == (*c1++ = *c2++)) { *c1 = 0; break; } } gv_altkey->end = c1 - gv_altkey->base; assert(gv_altkey->end < gv_altkey->top); } if (!dollar_tlevel) { if ((trans_num)0 == t_end(&gv_target->hist, two_histories ? rt_history : NULL, TN_NOT_SPECIFIED)) continue; } else { status = tp_hist(two_histories ? rt_history : NULL); if (cdb_sc_normal != status) { t_retry(status); continue; } } assert(cs_data == cs_addrs->hdr); INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_order, 1); return (found && (bh->curr_rec.match >= gv_currkey->prev)); } restart: t_retry(status); } } fis-gtm-V6.0-003/sr_port/gvcst_protos.h0000644000032200000250000000721612201176157016747 0ustar librarygtc/**************************************************************** * * * Copyright 2004, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* collection of prototypes of gvcst_* modules that need a bare minimum of mdef.h & gdsfhead.h to be already included */ #ifndef GVCST_PROTOS_H_INCLUDED #define GVCST_PROTOS_H_INCLUDED void db_auto_upgrade(gd_region *reg); #ifdef VMS void db_init(gd_region *reg, sgmnt_data_ptr_t tsd); #else int db_init(gd_region *reg); void db_init_err_cleanup(boolean_t retry_dbinit); void gvcst_redo_root_search(void); #endif gd_region *dbfilopn (gd_region *reg); void dbsecspc(gd_region *reg, sgmnt_data_ptr_t csd, gtm_uint64_t *sec_size); mint gvcst_data(void); mint gvcst_data2(void); enum cdb_sc gvcst_dataget(mint *dollar_data, mval *val); enum cdb_sc gvcst_dataget2(mint *dollar_data, mval *val, unsigned char *sn_ptr); bool gvcst_gblmod(mval *v); boolean_t gvcst_get(mval *v); boolean_t gvcst_get2(mval *v, unsigned char *sn_ptr); void gvcst_incr(mval *increment, mval *result); void gvcst_init(gd_region *greg); void gvcst_kill(boolean_t do_subtree); void gvcst_kill2(boolean_t do_subtree, boolean_t *span_status, boolean_t killing_chunks); enum cdb_sc gvcst_lftsib(srch_hist *full_hist); bool gvcst_order(void); bool gvcst_order2(void); void gvcst_put(mval *v); void gvcst_put2(mval *val, span_parms *parms); bool gvcst_query(void); bool gvcst_query2(void); boolean_t gvcst_queryget(mval *val); boolean_t gvcst_queryget2(mval *val, unsigned char *sn_ptr); enum cdb_sc gvcst_root_search(boolean_t donot_restart); enum cdb_sc gvcst_rtsib(srch_hist *full_hist, int level); enum cdb_sc gvcst_search(gv_key *pKey, srch_hist *pHist); enum cdb_sc gvcst_search_blk(gv_key *pKey, srch_blk_status *pStat); enum cdb_sc gvcst_search_tail(gv_key *pKey, srch_blk_status *pStat, gv_key *pOldKey); void gvcst_tp_init(gd_region *); bool gvcst_zprevious(void); bool gvcst_zprevious2(void); /* gvcst_dataget and gvcst_dataget2 take the following values as input */ #define DG_GETONLY 2 #define DG_DATAONLY 3 #define DG_DATAGET 4 #define DG_GETSNDATA 5 GBLREF boolean_t gv_play_duplicate_kills; /* In case "gv_play_duplicate_kills" is TRUE, invoke "gvcst_kill" even if the GVT does not exist. This is so we record * in the jnl file and the db (curr_tn wise) that such a KILL occurred. Also do this only if the update is an explicit * update. Else this update is not replicated so we dont have the need to write a journal record for the KILL. While at * this, add a few asserts that in case of backward recovery, the to-be-killed node always exists. This is because backward * recovery is supposed to mirror GT.M activity on the database and so should see the exact same state of the database * that GT.M saw. The only exception is in case of replication and the update process wrote a KILL jnl record because it * has to mirror the jnl state of the primary. In this case though nodeflags will have the JS_IS_DUPLICATE bit set. */ #define IS_OK_TO_INVOKE_GVCST_KILL(GVT) \ ( \ DBG_ASSERT(!jgbl.forw_phase_recovery || gv_play_duplicate_kills GTMTRIG_ONLY(&& IS_EXPLICIT_UPDATE_NOASSERT)) \ DBG_ASSERT(!jgbl.forw_phase_recovery || gv_target->root || (JS_IS_DUPLICATE & jgbl.mur_jrec_nodeflags) \ || jgbl.mur_options_forward) \ (GVT->root || (gv_play_duplicate_kills GTMTRIG_ONLY(&& IS_EXPLICIT_UPDATE_NOASSERT))) \ ) #endif fis-gtm-V6.0-003/sr_port/gvcst_put.c0000644000032200000250000033217312201176176016230 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "gtm_stdio.h" #include "gtm_stdlib.h" #include "gtm_string.h" #include "gtm_inet.h" /* Required for gtmsource.h */ #ifdef VMS #include /* Required for gtmsource.h */ #endif #include "gdsroot.h" #include "gdskill.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "cdb_sc.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "jnl.h" #include "gdscc.h" #include "copy.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "rc_oflow.h" #include "repl_msg.h" #include "gtmsource.h" #include #include "stack_frame.h" #include "mv_stent.h" #ifdef GTM_TRIGGER # include "gv_trigger.h" # include "gtm_trigger.h" # include "gv_trigger_protos.h" # include "subscript.h" # include "stringpool.h" #endif #include "tp_frame.h" #include "tp_restart.h" /* Include prototypes */ #include "t_write.h" #include "t_write_root.h" #include "t_end.h" #include "t_retry.h" #include "t_begin.h" #include "t_create.h" #include "gvcst_blk_build.h" #include "gvcst_expand_key.h" #include "gvcst_protos.h" /* for gvcst_search,gvcst_search_blk,gvcst_put prototype */ #include "op.h" /* for op_add & op_tstart prototype */ #include "format_targ_key.h" /* for format_targ_key prototype */ #include "gvsub2str.h" /* for gvsub2str prototype */ #include "tp_set_sgm.h" /* for tp_set_sgm prototype */ #include "op_tcommit.h" /* for op_tcommit prototype */ #include "have_crit.h" #include "error.h" #include "gtmimagename.h" /* for spanning nodes */ #ifdef UNIX #include "preemptive_db_clnup.h" #endif #ifdef GTM_TRIGGER LITREF mval literal_null; LITREF mval literal_one; LITREF mval literal_zero; #endif LITREF mval literal_batch; LITREF mstr nsb_dummy; /* Globals that will not change in value across nested trigger calls of gvcst_put OR even if they might change in value, * the change is such that they dont need save/restore logic surrounding the "gtm_trigger" call. Any new GBLREFs that are * added in this module need to be examined for interference between gvcst_put and nested trigger call and any save/restore * logic (if needed) should be appropriately added surrounding the "gtm_trigger" invocation. */ GBLREF boolean_t gvdupsetnoop; /* if TRUE, duplicate SETs update journal but not database (except for curr_tn++) */ GBLREF boolean_t horiz_growth; GBLREF boolean_t in_gvcst_incr; GBLREF char *update_array, *update_array_ptr; GBLREF gv_key *gv_altkey; GBLREF gv_namehead *reset_gv_target; GBLREF inctn_opcode_t inctn_opcode; GBLREF int gv_fillfactor; GBLREF int rc_set_fragment; /* Contains offset within data at which data fragment starts */ GBLREF int4 gv_keysize; GBLREF int4 prev_first_off, prev_next_off; GBLREF uint4 update_trans; GBLREF jnl_format_buffer *non_tp_jfb_ptr; GBLREF jnl_gbls_t jgbl; GBLREF jnlpool_addrs jnlpool; GBLREF uint4 dollar_tlevel; GBLREF uint4 process_id; GBLREF uint4 update_array_size, cumul_update_array_size; /* the current total size of the update array */ GBLREF unsigned char t_fail_hist[CDB_MAX_TRIES]; GBLREF unsigned int t_tries; GBLREF cw_set_element cw_set[CDB_CW_SET_SIZE];/* create write set. */ GBLREF boolean_t skip_dbtriggers; /* see gbldefs.c for description of this global */ GBLREF stack_frame *frame_pointer; GBLREF mv_stent *mv_chain; #ifdef GTM_TRIGGER GBLREF int tprestart_state; GBLREF int4 gtm_trigger_depth; GBLREF int4 tstart_trigger_depth; GBLREF boolean_t skip_INVOKE_RESTART; GBLREF boolean_t ztwormhole_used; /* TRUE if $ztwormhole was used by trigger code */ #endif #ifdef DEBUG GBLREF boolean_t skip_block_chain_tail_check; GBLREF boolean_t donot_INVOKE_MUMTSTART; #endif /* Globals that could change in value across nested trigger calls of gvcst_put AND need to be saved/restored */ GBLREF boolean_t is_dollar_incr; GBLREF gd_region *gv_cur_region; GBLREF gv_key *gv_currkey; GBLREF gv_namehead *gv_target; GBLREF mval *post_incr_mval; GBLREF mval increment_delta_mval; GBLREF sgm_info *sgm_info_ptr; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; UNIX_ONLY(GBLREF enum gtmImageTypes image_type;) UNIX_ONLY(GBLREF boolean_t span_nodes_disallowed;) error_def(ERR_DBROLLEDBACK); error_def(ERR_GVINCRISOLATION); error_def(ERR_GVIS); error_def(ERR_GVPUTFAIL); error_def(ERR_REC2BIG); error_def(ERR_RSVDBYTE2HIGH); error_def(ERR_TEXT); error_def(ERR_TPRETRY); error_def(ERR_UNIMPLOP); /* Before issuing an error, add GVT to the list of known gvts in this TP transaction in case it is not already done. * This GVT addition is usually done by "tp_hist" but that function has most likely not yet been invoked in gvcst_put. * Doing this addition will ensure we remember to reset any non-zero clue in dir_tree as part of tp_clean_up when a TROLLBACK * or TRESTART (implicit or explicit) occurs. Not doing so could means if an ERR_REC2BIG happens here, control will * go to the error trap and if it does a TROLLBACK (which does a tp_clean_up) we would be left with a potentially out-of-date * clue of GVT which if used for later global references could result in db integ errors. */ #define ENSURE_VALUE_WITHIN_MAX_REC_SIZE(value, GVT) \ { \ if (dollar_tlevel) \ ADD_TO_GVT_TP_LIST(GVT, RESET_FIRST_TP_SRCH_STATUS_FALSE); /* note: macro updates read_local_tn if necessary */ \ if (VMS_ONLY(gv_currkey->end + 1 + SIZEOF(rec_hdr) +) value.len > gv_cur_region->max_rec_size) \ { \ if (0 == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) \ end = &buff[MAX_ZWR_KEY_SZ - 1]; \ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(10) ERR_REC2BIG, 4, VMS_ONLY(gv_currkey->end + 1 + SIZEOF(rec_hdr) +) \ value.len, (int4)gv_cur_region->max_rec_size, \ REG_LEN_STR(gv_cur_region), ERR_GVIS, 2, end - buff, buff); \ } \ } /* See comment before ENSURE_VALUE_WITHIN_MAX_REC_SIZE macro definition for why the ADD_TO_GVT_TP_LIST call below is necessary */ #define ISSUE_RSVDBYTE2HIGH_ERROR(GVT) \ { \ if (dollar_tlevel) \ ADD_TO_GVT_TP_LIST(GVT, RESET_FIRST_TP_SRCH_STATUS_FALSE); /* note: macro updates read_local_tn if necessary */ \ /* The record that is newly inserted/updated does not fit by itself in a separate block \ * if the current reserved-bytes for this database is taken into account. Cannot go on. \ */ \ if (0 == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) \ end = &buff[MAX_ZWR_KEY_SZ - 1]; \ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(11) ERR_RSVDBYTE2HIGH, 5, new_blk_size_single, \ REG_LEN_STR(gv_cur_region), blk_size, blk_reserved_bytes, \ ERR_GVIS, 2, end - buff, buff); \ } #define RESTORE_ZERO_GVT_ROOT_ON_RETRY(LCL_ROOT, GV_TARGET, DIR_HIST, DIR_TREE) \ { \ if (!LCL_ROOT) \ { \ assert(NULL != DIR_HIST); \ assert(DIR_TREE == GV_TARGET->gd_csa->dir_tree); \ /* t_retry only resets gv_target->clue and not the clue of the directory tree. \ * But DIR_HIST non-null implies the directory tree was used in a gvcst_search and hence \ * was validated (in t_end/tp_hist),so we need to reset its clue before the next try. \ */ \ DIR_TREE->clue.end = 0; \ /* We had reset the root block from zero to a non-zero value within \ * this function, but since we are restarting, we can no longer be \ * sure of the validity of the root block. Reset it to 0 so it will \ * be re-determined in the next global reference. \ */ \ GV_TARGET->root = 0; \ } \ } #define RECORD_FITS_IN_A_BLOCK(VAL, KEY, BLK_SZ, RESERVED_BYTES) \ ((VAL)->str.len <= COMPUTE_CHUNK_SIZE(KEY, BLK_SZ, RESERVED_BYTES)) #define ZKILL_NODELETS \ { \ APPEND_HIDDEN_SUB(gv_currkey); \ if (gv_target->root) \ gvcst_kill2(FALSE, NULL, TRUE); /* zkill any existing spanning nodelets.. */ \ RESTORE_CURRKEY(gv_currkey, oldend); \ } #define POP_MVALS_FROM_M_STACK_IF_REALLY_NEEDED(lcl_span_status, ztold_mval, save_msp, save_mv_chain) \ { \ if (!lcl_span_status) \ POP_MVALS_FROM_M_STACK_IF_NEEDED(ztold_mval, save_msp, save_mv_chain); \ } #ifdef DEBUG # define DBG_SAVE_VAL_AT_FUN_ENTRY \ { /* Save copy of "val" at function entry. \ * Make sure this is not touched by any nested trigger code */ \ dbg_lcl_val = val; \ dbg_vallen = val->str.len; \ memcpy(dbg_valbuff, val->str.addr, MIN(ARRAYSIZE(dbg_valbuff), dbg_vallen)); \ } # define DBG_CHECK_VAL_AT_FUN_EXIT \ { /* Check "val" is same as what it was at function entry.(i.e. was not touched by nested trigger code). \ * The only exception is if $ZTVAL changed "val" in which case gvcst_put would have been redone. */ \ assert(dbg_vallen == dbg_lcl_val->str.len); \ assert(0 == memcmp(dbg_valbuff, dbg_lcl_val->str.addr, MIN(ARRAYSIZE(dbg_valbuff), dbg_vallen))); \ } #else # define DBG_SAVE_VAL_AT_FUN_ENTRY # define DBG_CHECK_VAL_AT_FUN_EXIT #endif #define GOTO_RETRY \ { \ GTMTRIG_DBG_ONLY(dbg_trace_array[dbg_num_iters].retry_line = __LINE__); \ goto retry; \ } CONDITION_HANDLER(gvcst_put_ch) { int rc; START_CH; if ((int)ERR_TPRETRY == SIGNAL) { /* delay tp_restart till after the long jump and some other stuff */ UNWIND(NULL, NULL); } NEXTCH; } void gvcst_put(mval *val) { boolean_t sn_tpwrapped, fits; boolean_t est_first_pass; mval val_ctrl, val_piece, val_dummy; mval *pre_incr_mval, *save_val; block_id lcl_root; int gblsize, chunk_size, i, oldend; unsigned short numsubs; unsigned char mychars[MAX_NSBCTRL_SZ]; int save_dollar_tlevel, rc; boolean_t save_in_gvcst_incr; /* gvcst_put2 sets this FALSE, so save it in case we need to back out */ span_parms parms; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; parms.span_status = FALSE; parms.blk_reserved_bytes = cs_data->reserved_bytes; /* Only want to read once for consistency */ parms.enable_trigger_read_and_fire = TRUE; parms.enable_jnl_format = TRUE; lcl_root = gv_target->root; VMS_ONLY(gvcst_put2(val, &parms)); # ifdef UNIX /* deal with possibility of spanning nodes */ DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); fits = RECORD_FITS_IN_A_BLOCK(val, gv_currkey, cs_data->blk_size, parms.blk_reserved_bytes); save_in_gvcst_incr = in_gvcst_incr; if (fits) { gvcst_put2(val, &parms); if (!parms.span_status) { assert(save_dollar_tlevel == dollar_tlevel); return; /* We've successfully set a normal non-spanning global. */ } } RTS_ERROR_IF_SN_DISALLOWED; /* Either we need to create a spanning node, or kill one before resetting it */ GTMTRIG_ONLY(parms.ztold_mval = NULL); cs_data->span_node_absent = FALSE; oldend = gv_currkey->end; val_dummy.str = nsb_dummy; if (!dollar_tlevel) { sn_tpwrapped = TRUE; save_val = val; /* We pass the IMPLICIT_TRIGGER_TSTART flag because we might invoke a trigger, and in that case we want to avoid * invoking a restart from within gtm_trigger. Since we remove gvcst_put_ch before invoking the trigger * (see comment in errorsp.h), an attempt to invoke a restart returns us back to the mdb_condition_handler created * by the initial dm-start. Unwinding from there returns to the OS -- i.e., the process silently dies. * Also note that we need to ensure the retry logic at the bottom of gvcst_put2 is executed in case a restart * happens within a trigger invocation. We want to return from gvtr_match_n_invoke so we can goto retry. */ op_tstart((IMPLICIT_TSTART + IMPLICIT_TRIGGER_TSTART), TRUE, &literal_batch, 0); frame_pointer->flags |= SFF_IMPLTSTART_CALLD; assert(!donot_INVOKE_MUMTSTART); DEBUG_ONLY(donot_INVOKE_MUMTSTART = TRUE); ESTABLISH_NORET(gvcst_put_ch, est_first_pass); if (est_first_pass) { /* did a long jump back to here */ val = save_val; GTMTRIG_ONLY(POP_MVALS_FROM_M_STACK_IF_NEEDED(parms.ztold_mval, parms.save_msp, ((mv_stent *)parms.save_mv_chain))); preemptive_db_clnup(ERROR); /* Bluff about SEVERITY to reset gv_target and reset_gv_target tp_restart resets * but not reset_gv_target This matches flow with non-spanning-node tp_restart, * which does preemptive_db_clnup in mdb_condition_handler */ rc = tp_restart(1, !TP_RESTART_HANDLES_ERRORS); DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); RESTORE_ZERO_GVT_ROOT_ON_RETRY(lcl_root, gv_target, &cs_addrs->dir_tree->hist, cs_addrs->dir_tree); fits = RECORD_FITS_IN_A_BLOCK(val, gv_currkey, cs_data->blk_size, parms.blk_reserved_bytes); if (cdb_sc_onln_rlbk2 == LAST_RESTART_CODE) /* Database was taken back to a different logical state. We are an implicit TP transaction, and * as in the case of implicit TP for triggers, we issue a DBROLLEDBACK error that the application * programmer can catch. */ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_DBROLLEDBACK); } tp_set_sgm(); GVCST_ROOT_SEARCH; } else sn_tpwrapped = FALSE; parms.span_status = TRUE; parms.enable_trigger_read_and_fire = TRUE; parms.enable_jnl_format = TRUE; parms.ztval_gvcst_put_redo = FALSE; if (save_in_gvcst_incr) { in_gvcst_incr = FALSE; /* allow gvcst_put2 to do a regular set */ PUSH_MV_STENT(MVST_MVAL); /* protect pre_incr_mval from stp_gcol */ pre_incr_mval = &mv_chain->mv_st_cont.mvs_mval; gvcst_get(pre_incr_mval); /* what if it doesn't exist? needs to be treated as 0 */ pre_incr_mval->mvtype = MV_STR; op_add(pre_incr_mval, &increment_delta_mval, post_incr_mval); POP_MV_STENT(); /* pre_incr_mval */ assert(MV_IS_NUMERIC(post_incr_mval)); MV_FORCE_STR(post_incr_mval); val = post_incr_mval; /* its a number, should fit in single block.. unless ridick rsrvdbytes.. */ fits = RECORD_FITS_IN_A_BLOCK(val, gv_currkey, cs_data->blk_size, parms.blk_reserved_bytes); } /* Set the primary node. If we're setting a spanning node, that the primary node will have a dummy value, $char(0). * Journal formatting and triggers happen here. If ztval changed during trigger invocations to a large value, * we do a second gvcst_put2 to set the new value. */ parms.val_forjnl = val; gvcst_put2(((fits) ? val : &val_dummy), &parms); parms.enable_trigger_read_and_fire = FALSE; # ifdef GTM_TRIGGER if (parms.ztval_gvcst_put_redo) { val = parms.ztval_mval; parms.enable_jnl_format = TRUE; /* new val needs to be journaled */ parms.val_forjnl = val; fits = RECORD_FITS_IN_A_BLOCK(val, gv_currkey, cs_data->blk_size, parms.blk_reserved_bytes); assert(!fits); gvcst_put2(&val_dummy, &parms); } # endif ZKILL_NODELETS; /* Even if not creating a spanning node, may be replacing one */ if (!fits) { /* Need to create a spanning node. Break value up into chunks. */ parms.enable_jnl_format = FALSE; /* jnl formatting already done */ APPEND_HIDDEN_SUB(gv_currkey); chunk_size = COMPUTE_CHUNK_SIZE(gv_currkey, cs_data->blk_size, parms.blk_reserved_bytes); gblsize = val->str.len; numsubs = DIVIDE_ROUND_UP(gblsize, chunk_size); PUT_NSBCTRL(mychars, numsubs, gblsize); val_ctrl.str.addr = (char *)mychars; val_ctrl.str.len = 6; /* Count the spanning node set as one set */ INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_set, 1); gvcst_put2(&val_ctrl, &parms); /* Set control subscript, indicating glbsize and number of chunks */ for (i = 0; i < numsubs; i++) { NEXT_HIDDEN_SUB(gv_currkey, i); val_piece.str.len = MIN(chunk_size, gblsize - i * chunk_size); val_piece.str.addr = val->str.addr + i * chunk_size; gvcst_put2(&val_piece, &parms); } RESTORE_CURRKEY(gv_currkey, oldend); } GTMTRIG_ONLY(POP_MVALS_FROM_M_STACK_IF_NEEDED(parms.ztold_mval, parms.save_msp, ((mv_stent *)parms.save_mv_chain))); /* pop any stacked mvals before op_tcommit as it does its own popping */ if (sn_tpwrapped) { op_tcommit(); DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE); REVERT; /* remove our condition handler */ } assert(save_dollar_tlevel == dollar_tlevel); # endif /* ifdef UNIX */ } void gvcst_put2(mval *val, span_parms *parms) { sgmnt_addrs *csa; sgmnt_data_ptr_t csd; node_local_ptr_t cnl; int4 blk_size, blk_fill_size, blk_reserved_bytes; const int4 zeroes = 0; boolean_t jnl_format_done, is_dummy, needfmtjnl, fits, lcl_span_status; blk_segment *bs1, *bs_ptr, *new_blk_bs; block_id allocation_clue, tp_root, gvt_for_root, blk_num, last_split_blk_num[MAX_BT_DEPTH]; block_index left_hand_index, ins_chain_index, root_blk_cw_index, next_blk_index; block_offset next_offset, first_offset, ins_off1, ins_off2, old_curr_chain_next_off; cw_set_element *cse, *cse_new, *old_cse; gv_namehead *save_targ, *split_targ, *dir_tree; enum cdb_sc status; gv_key *temp_key; int tmp_cmpc; mstr value; off_chain chain1, curr_chain, prev_chain, chain2; rec_hdr_ptr_t curr_rec_hdr, extra_rec_hdr, next_rec_hdr, new_star_hdr, rp, tmp_rp; srch_blk_status *bh, *bq, *tp_srch_status; srch_hist *dir_hist; int cur_blk_size, blk_seg_cnt, delta, i, j, left_hand_offset, n, ins_chain_offset, new_blk_size_l, new_blk_size_r, new_blk_size_single, new_blk_size, blk_reserved_size, last_possible_left_offset, new_rec_size, next_rec_shrink, next_rec_shrink1, start_len, offset_sum, rec_cmpc, target_key_size, tp_lev, undo_index, cur_val_offset, curr_offset, bh_level; uint4 segment_update_array_size, key_top, cp2_len, bs1_2_len, bs1_3_len; char *va, last_split_direction[MAX_BT_DEPTH]; sm_uc_ptr_t cp1, cp2, curr; unsigned short extra_record_orig_size, rec_size, temp_short; unsigned int prev_rec_offset, prev_rec_match, curr_rec_offset, curr_rec_match; boolean_t copy_extra_record, level_0, new_rec, no_pointers, succeeded, key_exists; boolean_t make_it_null, gbl_target_was_set, duplicate_set, new_rec_goes_to_right, need_extra_block_split; key_cum_value *tempkv; jnl_format_buffer *jfb, *ztworm_jfb; jnl_action *ja; mval *set_val; /* actual right-hand-side value of the SET or $INCR command */ mval *val_forjnl; ht_ent_int4 *tabent; unsigned char buff[MAX_ZWR_KEY_SZ], *end, old_ch, new_ch; sm_uc_ptr_t buffaddr; block_id lcl_root, last_split_bnum; sgm_info *si; uint4 nodeflags; boolean_t write_logical_jnlrecs, can_write_logical_jnlrecs, blk_match, is_split_dir_left; int split_depth; mval *ja_val; int rc; int4 cse_first_off; enum split_dir last_split_dir; int4 data_len; # ifdef GTM_TRIGGER boolean_t is_tpwrap; boolean_t ztval_gvcst_put_redo, skip_hasht_read; gtm_trigger_parms trigparms; gvt_trigger_t *gvt_trigger; gvtr_invoke_parms_t gvtr_parms; int gtm_trig_status; unsigned char *save_msp; mv_stent *save_mv_chain; mval *ztold_mval = NULL; mval *ztval_mval; mint dlr_data; boolean_t lcl_implicit_tstart; /* local copy of the global variable "implicit_tstart" */ mval lcl_increment_delta_mval; /* local copy of "increment_delta_mval" */ boolean_t lcl_is_dollar_incr; /* local copy of is_dollar_incr taken at start of module. * used to restore is_dollar_incr in case of TP restarts */ mval *lcl_post_incr_mval; /* local copy of "post_incr_mval" at function entry. * used to restore "post_incr_mval" in case of TP restarts */ mval *lcl_val; /* local copy of "val" at function entry. * used to restore "val" in case of TP restarts */ mval *lcl_val_forjnl; mval *pval; /* copy of "value" (an mstr), protected from stp gcol */ DEBUG_ONLY(enum cdb_sc save_cdb_status;) # endif # ifdef DEBUG char dbg_valbuff[256]; mstr_len_t dbg_vallen; mval *dbg_lcl_val; int dbg_num_iters = -1; /* number of iterations through gvcst_put */ int lcl_dollar_tlevel, lcl_t_tries; typedef struct { unsigned int t_tries; int retry_line; boolean_t is_fresh_tn_start; boolean_t is_dollar_incr; boolean_t ztval_gvcst_put_redo; boolean_t is_extra_block_split; mval *val; boolean_t lcl_implicit_tstart; } dbg_trace; /* We want to capture all pertinent information across each iteration of gvcst_put. * There are 3 things that can contribute to a new iteration. * a) restarts from the primary set. * Max of 4 iterations. * b) extra_block_split from the primary set. It can have its own set of restarts too. * Max of 4 iterations per extra_block_split. * The # of extra block splits could be arbitrary in case of non-TP but cannot be more than 1 for TP * because in TP, we would have grabbed crit in the final retry and prevent any more concurrent updates. * c) ztval_gvcst_put_redo. This in turn can have its own set of restarts and extra_block_split iterations. * Could take a max of (a) + (b) = 4 + 4 = 8 iterations. * Total of 16 max iterations. If ever a transaction goes for more than this # of iterations (theoretically * possible in non-TP if a lot of extra block splits occur), we assert fail. */ dbg_trace dbg_trace_array[16]; boolean_t is_fresh_tn_start; boolean_t is_mm; # endif DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; is_dollar_incr = in_gvcst_incr; in_gvcst_incr = FALSE; csa = cs_addrs; csd = csa->hdr; cnl = csa->nl; assert(csd == cs_data); DEBUG_ONLY(is_mm = (dba_mm == csd->acc_meth);) # ifdef GTM_TRIGGER TRIG_CHECK_REPLSTATE_MATCHES_EXPLICIT_UPDATE(gv_cur_region, csa); if (IS_EXPLICIT_UPDATE) { /* This is an explicit update. Set ztwormhole_used to FALSE. Note that we initialize this only at the * beginning of the transaction and not at the beginning of each try/retry. If the application used * $ztwormhole in any retsarting try of the transaction, we consider it necessary to write the * TZTWORM/UZTWORM record even though it was not used in the succeeding/committing try. */ ztwormhole_used = FALSE; } # endif JNLPOOL_INIT_IF_NEEDED(csa, csd, cnl); blk_size = csd->blk_size; blk_reserved_bytes = parms->blk_reserved_bytes; blk_fill_size = (blk_size * gv_fillfactor) / 100 - blk_reserved_bytes; lcl_span_status = parms->span_status; if (lcl_span_status) { needfmtjnl = parms->enable_jnl_format; val_forjnl = parms->val_forjnl; # ifdef GTM_TRIGGER ztold_mval = parms->ztold_mval; skip_hasht_read = !parms->enable_trigger_read_and_fire; # endif } else { needfmtjnl = TRUE; val_forjnl = val; } jnl_format_done = !needfmtjnl; /* do "jnl_format" only once per logical non-tp transaction irrespective of * number of retries or number of chunks if spanning node */ GTMTRIG_ONLY( ztval_gvcst_put_redo = FALSE; skip_hasht_read = FALSE; ) assert(('\0' != gv_currkey->base[0]) && gv_currkey->end); DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); /* this needs to be initialized before any code that does a "goto retry" since this gets used there */ save_targ = gv_target; gbl_target_was_set = (INVALID_GV_TARGET != reset_gv_target); if (INVALID_GV_TARGET != reset_gv_target) gbl_target_was_set = TRUE; else { gbl_target_was_set = FALSE; reset_gv_target = save_targ; } DBG_SAVE_VAL_AT_FUN_ENTRY; GTMTRIG_ONLY( lcl_implicit_tstart = FALSE; DEBUG_ONLY(gvtr_parms.num_triggers_invoked = -1;) /* set to an out-of-design value; checked by an assert */ ) DEBUG_ONLY( status = cdb_sc_normal; lcl_dollar_tlevel = dollar_tlevel; ) fresh_tn_start: DEBUG_ONLY(lcl_t_tries = -1;) DEBUG_ONLY(is_fresh_tn_start = TRUE;) assert(!jnl_format_done || (dollar_tlevel GTMTRIG_ONLY(&& ztval_gvcst_put_redo)) || lcl_span_status); T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_GVPUTFAIL); tn_restart: /* t_tries should never decrease - it either increases or stays the same. If should decrease we could live-lock with * an oscillating t_tries and never reach CDB_STAGNATE (go from optimistic to pessimistic concurrency). Since we * typically do a normal increment and then, for certain conditions, do a complementary decrement, we assert that * the net effect is never a decrease. */ assert(csa == cs_addrs); /* no amount of retries should change cs_addrs from what it was at entry into gvcst_put */ assert((((int)t_tries) > lcl_t_tries) || (CDB_STAGNATE == t_tries)); DEBUG_ONLY(lcl_t_tries = t_tries;) /* update lcl_t_tries */ DEBUG_ONLY( dbg_num_iters++; assert(dbg_num_iters < ARRAYSIZE(dbg_trace_array)); dbg_trace_array[dbg_num_iters].is_fresh_tn_start = is_fresh_tn_start; dbg_trace_array[dbg_num_iters].t_tries = t_tries; is_fresh_tn_start = FALSE; dbg_trace_array[dbg_num_iters].is_dollar_incr = is_dollar_incr; GTMTRIG_ONLY(dbg_trace_array[dbg_num_iters].ztval_gvcst_put_redo = ztval_gvcst_put_redo;) dbg_trace_array[dbg_num_iters].val = val; GTMTRIG_ONLY(dbg_trace_array[dbg_num_iters].lcl_implicit_tstart = lcl_implicit_tstart;) dbg_trace_array[dbg_num_iters].is_extra_block_split = FALSE; dbg_trace_array[dbg_num_iters].retry_line = 0; split_targ = NULL; ) assert(csd == cs_data); /* To ensure they are the same even if MM extensions happened in between */ # ifdef GTM_TRIGGER gvtr_parms.num_triggers_invoked = 0; /* clear any leftover value */ assert(!ztval_gvcst_put_redo || IS_PTR_INSIDE_M_STACK(val)); is_tpwrap = FALSE; if (!skip_dbtriggers && !skip_hasht_read && parms->enable_trigger_read_and_fire) { GVTR_INIT_AND_TPWRAP_IF_NEEDED(csa, csd, gv_target, gvt_trigger, lcl_implicit_tstart, is_tpwrap, ERR_GVPUTFAIL); assert(gvt_trigger == gv_target->gvt_trigger); assert(gv_target == save_targ); /* gv_target should NOT have been mutated by the trigger reads */ if (is_tpwrap) { /* The above call to GVTR_INIT* macro created a TP transaction (by invoking op_tstart). * Save all pertinent global variable information that needs to be restored in case of * a restart. Note that the restart could happen in a nested trigger so these global * variables could have changed in value from what they were at gvcst_put entry, hence * the need to save/restore them. If this is not an implicitly tp wrapped transaction, * there is no need to do this save/restore because a restart will transfer control * back to the M code corresponding to the start of the transaction which would * automatically initialize these global variables to the appropriate values. */ assert(lcl_implicit_tstart); lcl_is_dollar_incr = is_dollar_incr; lcl_val = val; lcl_val_forjnl = val_forjnl; lcl_post_incr_mval = post_incr_mval; lcl_increment_delta_mval = increment_delta_mval; jnl_format_done = FALSE; } if (NULL != gvt_trigger) { PUSH_ZTOLDMVAL_ON_M_STACK(ztold_mval, save_msp, save_mv_chain); if (lcl_span_status) { /* Need the ability to pop vals from gvcst_put. */ parms->ztold_mval = ztold_mval; parms->save_msp = save_msp; parms->save_mv_chain = (unsigned char *)save_mv_chain; } } } # endif assert(csd == cs_data); /* assert csd is in sync with cs_data even if there were MM db file extensions */ si = sgm_info_ptr; /* Cannot be moved before GVTR_INIT_AND_TPWRAP_IF_NEEDED macro since we could enter gvcst_put * with sgm_info_ptr NULL but could tpwrap a non-tp transaction due to triggers. In that case * we want the updated sgm_info_ptr to be noted down in si and used later. */ assert((NULL == si) || (si->update_trans)); assert(NULL != update_array); assert(NULL != update_array_ptr); assert(0 != update_array_size); assert(update_array + update_array_size >= update_array_ptr); /* When the following two asserts trip, we should change the data types of prev_first_off * and prev_next_off, so they satisfy the assert. */ assert(SIZEOF(prev_first_off) >= SIZEOF(block_offset)); assert(SIZEOF(prev_next_off) >= SIZEOF(block_offset)); prev_first_off = prev_next_off = PREV_OFF_INVALID; horiz_growth = FALSE; assert(t_tries < CDB_STAGNATE || csa->now_crit); /* we better hold crit in the final retry (TP & non-TP) */ /* level_0 == true and no_pointers == false means that this is a directory tree data block containing pointers to roots */ level_0 = no_pointers = TRUE; assert(gv_altkey->top == gv_currkey->top); assert(gv_altkey->top == gv_keysize); assert(gv_currkey->end < gv_currkey->top); assert(gv_altkey->end < gv_altkey->top); temp_key = gv_currkey; dir_hist = NULL; ins_chain_index = 0; lcl_root = gv_target->root; tp_root = lcl_root; if (!dollar_tlevel) { CHECK_AND_RESET_UPDATE_ARRAY; /* reset update_array_ptr to update_array */ } else { segment_update_array_size = UA_NON_BM_SIZE(csd); ENSURE_UPDATE_ARRAY_SPACE(segment_update_array_size); curr_chain = *(off_chain *)&lcl_root; if (curr_chain.flag == 1) { tp_get_cw(si->first_cw_set, (int)curr_chain.cw_index, &cse); tp_root = cse->blk; assert(tp_root); } } if (0 == tp_root) { /* Global does not exist as far as we know. Creating a new one requires validating the directory tree path which * led us to this conclusion. So scan the directory tree here and validate its history at the end of this function. * If we decide to restart due to a concurrency conflict, remember to reset gv_target->root to 0 before restarting. */ gv_target = dir_tree = csa->dir_tree; SET_GV_ALTKEY_TO_GBLNAME_FROM_GV_CURRKEY; /* set up gv_altkey to be just the gblname */ dir_hist = &gv_target->hist; status = gvcst_search(gv_altkey, NULL); RESET_GV_TARGET_LCL(save_targ); if (cdb_sc_normal != status) GOTO_RETRY; if (gv_altkey->end + 1 == dir_hist->h[0].curr_rec.match) { tmp_rp = (rec_hdr_ptr_t)(dir_hist->h[0].buffaddr + dir_hist->h[0].curr_rec.offset); EVAL_CMPC2(tmp_rp, tmp_cmpc); GET_LONG(tp_root, (dir_hist->h[0].buffaddr + SIZEOF(rec_hdr) + dir_hist->h[0].curr_rec.offset + gv_altkey->end + 1 - tmp_cmpc)); if (dollar_tlevel) { gvt_for_root = dir_hist->h[0].blk_num; curr_chain = *(off_chain *)&gvt_for_root; if (curr_chain.flag == 1) tp_get_cw(si->first_cw_set, curr_chain.cw_index, &cse); else { if (NULL != (tabent = lookup_hashtab_int4(si->blks_in_use, (uint4 *)&gvt_for_root))) tp_srch_status = tabent->value; else tp_srch_status = NULL; cse = tp_srch_status ? tp_srch_status->cse : NULL; } assert(!cse || !cse->high_tlevel); } assert(0 == gv_target->root); gv_target->root = tp_root; } } blk_reserved_size = blk_size - blk_reserved_bytes; if (0 == tp_root) { /* there is no entry in the GVT (and no root), so create a new empty tree and put the name in the GVT */ /* Create the data block */ key_exists = FALSE; if (is_dollar_incr) { /* The global variable that is being $INCREMENTed does not exist. * $INCREMENT() should not signal UNDEF error but proceed with an implicit $GET(). */ assert(dollar_tlevel ? si->update_trans : update_trans); *post_incr_mval = *val; MV_FORCE_NUM(post_incr_mval); post_incr_mval->mvtype &= ~MV_STR; /* needed to force any alphanumeric string to numeric */ MV_FORCE_STR(post_incr_mval); assert(post_incr_mval->str.len); value = post_incr_mval->str; /* The MAX_REC_SIZE check could not be done in op_gvincr (like is done in op_gvput) because * the post-increment value is not known until here. so do the check here. */ ENSURE_VALUE_WITHIN_MAX_REC_SIZE(value, dir_tree); } else value = val->str; /* Potential size of a GVT leaf block containing just the new/updated record */ new_blk_size_single = SIZEOF(blk_hdr) + SIZEOF(rec_hdr) + temp_key->end + 1 + value.len; if (new_blk_size_single > blk_reserved_size) { /* The record that is newly inserted/updated does not fit by itself in a separate block * if the current reserved-bytes for this database is taken into account. Cannot go on. */ ISSUE_RSVDBYTE2HIGH_ERROR(dir_tree); } BLK_ADDR(curr_rec_hdr, SIZEOF(rec_hdr), rec_hdr); curr_rec_hdr->rsiz = SIZEOF(rec_hdr) + temp_key->end + 1 + value.len; SET_CMPC(curr_rec_hdr, 0); BLK_INIT(bs_ptr, new_blk_bs); BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr, SIZEOF(rec_hdr)); BLK_ADDR(cp1, temp_key->end + 1, unsigned char); memcpy(cp1, temp_key->base, temp_key->end + 1); BLK_SEG(bs_ptr, cp1, temp_key->end + 1); if (0 != value.len) { BLK_ADDR(va, value.len, char); memcpy(va, value.addr, value.len); BLK_SEG(bs_ptr, (unsigned char *)va, value.len); } if (0 == BLK_FINI(bs_ptr, new_blk_bs)) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } assert(new_blk_bs[0].len <= blk_reserved_size); /* Assert that new block has space for reserved bytes */ /* Create the index block */ BLK_ADDR(curr_rec_hdr, SIZEOF(rec_hdr), rec_hdr); curr_rec_hdr->rsiz = BSTAR_REC_SIZE; SET_CMPC(curr_rec_hdr, 0); BLK_INIT(bs_ptr, bs1); BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr, SIZEOF(rec_hdr)); BLK_SEG(bs_ptr, (unsigned char *)&zeroes, SIZEOF(block_id)); if (0 == BLK_FINI(bs_ptr, bs1)) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } assert(bs1[0].len <= blk_reserved_size); /* Assert that new block has space for reserved bytes */ allocation_clue = ALLOCATION_CLUE(csd->trans_hist.total_blks); next_blk_index = t_create(allocation_clue, (uchar_ptr_t)new_blk_bs, 0, 0, 0); ++allocation_clue; ins_chain_index = t_create(allocation_clue, (uchar_ptr_t)bs1, SIZEOF(blk_hdr) + SIZEOF(rec_hdr), next_blk_index, 1); root_blk_cw_index = ins_chain_index; temp_key = gv_altkey; gv_target->hist.h[0].blk_num = HIST_TERMINATOR; gv_target = dir_tree; bh = &gv_target->hist.h[0]; value.len = SIZEOF(block_id); value.addr = (char *)&zeroes; no_pointers = FALSE; } else { # ifdef GTM_TRIGGER if (lcl_span_status && (NULL != ztold_mval) && !skip_hasht_read && parms->enable_trigger_read_and_fire) { /* Dealing with spanning nodes, need to use a get routine to find ztold_val. Need to do this BEFORE * gvcst_search below or we'll disrupt gv_target->hist, which is used in the subsequent constructions. * Though we don't need dollar_data, we use gvcst_dataget since it returns status, allowing retry * cleanup to be done (RESET_GV_TARGET_LCL_AND_CLR_GBL in particular) before invoking a restart. */ assert(dollar_tlevel && !skip_dbtriggers); dlr_data = DG_GETONLY; /* tell dataget we just want to do a get; we don't care about descendants */ status = gvcst_dataget(&dlr_data, ztold_mval); if (cdb_sc_normal != status) GOTO_RETRY; } # endif #if defined(DEBUG) && defined(UNIX) if (gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_GVINCRPUTFAIL == gtm_white_box_test_case_number)) { status = cdb_sc_blknumerr; GOTO_RETRY; } #endif if (cdb_sc_normal != (status = gvcst_search(gv_currkey, NULL))) GOTO_RETRY; target_key_size = gv_currkey->end + 1; bh = &gv_target->hist.h[0]; key_exists = (target_key_size == bh->curr_rec.match); # ifdef UNIX if (key_exists) { /* check for spanning node dummy value: a single zero byte */ rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)bh->buffaddr + bh->curr_rec.offset); GET_USHORT(rec_size, &rp->rsiz); cur_val_offset = SIZEOF(rec_hdr) + target_key_size - EVAL_CMPC((rec_hdr_ptr_t)rp); data_len = rec_size - cur_val_offset; is_dummy = (1 == data_len) && ('\0' == *(sm_uc_ptr_t)((sm_uc_ptr_t)rp + cur_val_offset)); if (is_dummy && !lcl_span_status && (csa->dir_tree != gv_target) && !(span_nodes_disallowed && csd->span_node_absent)) { /* Validate that value is really $zchar(0) and either restart or back out of gvcst_put2. * Three cases: * 1) not in TP, no triggers * 2) in TP (triggers invoked or not) * 3) weren't in TP when we entered gvcst_put2, but did an op_tstart to check for triggers */ RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, DO_GVT_GVKEY_CHECK); if (!dollar_tlevel) { update_trans = 0; succeeded = ((trans_num)0 != t_end(&gv_target->hist, dir_hist, TN_NOT_SPECIFIED)); if (!succeeded) { /* see other t_end */ RESTORE_ZERO_GVT_ROOT_ON_RETRY(lcl_root, gv_target, dir_hist, dir_tree); jnl_format_done = !needfmtjnl; GTMTRIG_DBG_ONLY(dbg_trace_array[dbg_num_iters].retry_line = __LINE__); update_trans = UPDTRNS_DB_UPDATED_MASK; goto tn_restart; } } else { status = tp_hist(dir_hist); if (NULL != dir_hist) ADD_TO_GVT_TP_LIST(dir_tree, RESET_FIRST_TP_SRCH_STATUS_FALSE); if (cdb_sc_normal != status) GOTO_RETRY; # ifdef GTM_TRIGGER if (lcl_implicit_tstart) { /* Started TP for playing triggers. Abort and try again outside after nsb op_tstart * Otherwise, we were already in TP when we came into gvcst_put. Triggers can stay, * but finish put outside. */ POP_MVALS_FROM_M_STACK_IF_NEEDED(ztold_mval, save_msp, save_mv_chain); OP_TROLLBACK(-1); } # endif } parms->span_status = TRUE; return; } } # endif if (is_dollar_incr) { if (key_exists) { /* $INCR is being done on an existing global variable key in the database. * the value to set the key to has to be determined by adding the existing value * with the increment passed as the input parameter "val" (of type (mval *)) to gvcst_put */ if (cdb_sc_normal != (status = gvincr_compute_post_incr(bh))) { assert(CDB_STAGNATE > t_tries); GOTO_RETRY; } } else { /* The global variable that is being $INCREMENTed does not exist. $INCREMENT() should not * signal UNDEF error but proceed with an implicit $GET() */ *post_incr_mval = *val; MV_FORCE_NUM(post_incr_mval); post_incr_mval->mvtype &= ~MV_STR; /* needed to force any alphanumeric string to numeric */ MV_FORCE_STR(post_incr_mval); assert(post_incr_mval->str.len); } assert(MV_IS_STRING(post_incr_mval)); assert(dollar_tlevel ? si->update_trans : update_trans); value = post_incr_mval->str; /* The MAX_REC_SIZE check could not be done in op_gvincr (like is done in op_gvput) because * the post-increment value is not known until here. so do the check here. */ ENSURE_VALUE_WITHIN_MAX_REC_SIZE(value, gv_target); } else value = val->str; } /* -------------------------------------------------------------------------------------------- * The code for the non-block-split case is very similar to the code in recompute_upd_array. * Any changes in either place should be reflected in the other. * -------------------------------------------------------------------------------------------- */ need_extra_block_split = FALSE; /* Assume we don't require an additional block split (most common case) */ duplicate_set = FALSE; /* Assume this is NOT a duplicate set (most common case) */ split_depth = 0; split_targ = gv_target; for (succeeded = FALSE; !succeeded; no_pointers = level_0 = FALSE) { buffaddr = bh->buffaddr; cur_blk_size = ((blk_hdr_ptr_t)buffaddr)->bsiz; target_key_size = temp_key->end + 1; /* Potential size of a block containing just the new/updated record */ new_blk_size_single = SIZEOF(blk_hdr) + SIZEOF(rec_hdr) + target_key_size + value.len; if (new_blk_size_single > blk_reserved_size) { /* The record that is newly inserted/updated does not fit by itself in a separate block * if the current reserved-bytes for this database is taken into account. If this is not a * GVT leaf block, this situation is then possible if we are not in the final retry (and hence * dont hold crit on the region) and "temp_key->end" (and in turn "target_key_size") was * computed from a stale copy (due to concurrent updates or buffer reuse) of the global buffer * (effectively a restartable situation). If so, restart. If not issue error. */ if (no_pointers || (CDB_STAGNATE <= t_tries)) { ISSUE_RSVDBYTE2HIGH_ERROR(gv_target); } else { status = cdb_sc_mkblk; GOTO_RETRY; } } curr_rec_match = bh->curr_rec.match; curr_rec_offset = bh->curr_rec.offset; new_rec = (target_key_size != curr_rec_match); if (!new_rec && !no_pointers) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_lostcr; /* will a new cdb_sc status be better */ GOTO_RETRY; } rp = (rec_hdr_ptr_t)(buffaddr + curr_rec_offset); if (curr_rec_offset == cur_blk_size) { if ((FALSE == new_rec) && dollar_tlevel) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } rec_cmpc = 0; rec_size = 0; } else { GET_USHORT(rec_size, &rp->rsiz); rec_cmpc = EVAL_CMPC(rp); if ((sm_uc_ptr_t)rp + rec_size > (sm_uc_ptr_t)buffaddr + cur_blk_size) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } } prev_rec_match = bh->prev_rec.match; if (new_rec) { new_rec_size = SIZEOF(rec_hdr) + target_key_size - prev_rec_match + value.len; if (cur_blk_size <= (signed int)curr_rec_offset) /* typecast necessary to enforce "signed int" comparison */ next_rec_shrink = 0; else next_rec_shrink = curr_rec_match - rec_cmpc; delta = new_rec_size - next_rec_shrink; } else { if (rec_cmpc != prev_rec_match) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } assert(target_key_size > rec_cmpc); cur_val_offset = SIZEOF(rec_hdr) + (target_key_size - rec_cmpc); # ifdef GTM_TRIGGER if (no_pointers && (NULL != ztold_mval) && !skip_hasht_read && parms->enable_trigger_read_and_fire && !lcl_span_status) { /* Complete initialization of ztold_mval */ assert(!skip_dbtriggers); data_len = rec_size - cur_val_offset; if (0 > data_len) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_rmisalign; GOTO_RETRY; } ztold_mval->str.len = data_len; if (data_len) { if (!(IS_STP_SPACE_AVAILABLE(data_len))) { PUSH_MV_STENT(MVST_MVAL); /* protect "value" mstr from stp gcol */ pval = &mv_chain->mv_st_cont.mvs_mval; pval->str = value; ENSURE_STP_FREE_SPACE(data_len); value = pval->str; POP_MV_STENT(); /* pval */ } ztold_mval->str.addr = (char *)stringpool.free; memcpy(ztold_mval->str.addr, (sm_uc_ptr_t)rp + cur_val_offset, data_len); stringpool.free += data_len; } ztold_mval->mvtype = MV_STR; /* ztold_mval is now completely initialized */ } # endif new_rec_size = cur_val_offset + value.len; delta = new_rec_size - rec_size; if (!delta && value.len && !memcmp(value.addr, (sm_uc_ptr_t)rp + new_rec_size - value.len, value.len)) { duplicate_set = TRUE; if (gvdupsetnoop) { /* We do not want to touch the DB Blocks in case of a duplicate set unless the * dupsetnoop optimization is disabled. Since it is enabled, let us break right away. */ succeeded = TRUE; break; /* duplicate SET */ } } next_rec_shrink = 0; } blk_num = bh->blk_num; bh_level = bh->level; if (dollar_tlevel) { if ((SIZEOF(rec_hdr) + target_key_size - prev_rec_match + value.len) != new_rec_size) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } chain1 = *(off_chain *)&blk_num; if ((1 == chain1.flag) && ((int)chain1.cw_index >= si->cw_set_depth)) { assert(si->tp_csa == csa); assert(FALSE == csa->now_crit); status = cdb_sc_blknumerr; GOTO_RETRY; } } next_rec_shrink1 = next_rec_shrink; /* Potential size of the current block including the new/updated record */ new_blk_size = cur_blk_size + delta; /* It is possible due to concurrency issues (for example if the buffer that we are planning on updating * in shared memory got reused for a different block) that "new_blk_size" is lesser than "new_blk_size_single" * In those cases, we will go into the non-block-split case but eventually we will restart. */ assert((new_blk_size >= new_blk_size_single) || (CDB_STAGNATE > t_tries)); if ((new_blk_size <= blk_fill_size) || (new_blk_size <= new_blk_size_single)) { /* Update can be done without overflowing the block's fillfactor OR the record to be updated * is the only record in the new block. Do not split block in either case. This means we might * not honour the desired FillFactor if the only record in a block exceeds the blk_fill_size, * but in this case we are guaranteed the block has room for the current reserved bytes. */ if (no_pointers) /* level zero (normal) data block: no deferred pointer chains */ ins_chain_offset = 0; else /* index or directory level block */ ins_chain_offset =(int)((sm_uc_ptr_t)rp - buffaddr + new_rec_size - SIZEOF(block_id)); BLK_INIT(bs_ptr, bs1); if (0 == rc_set_fragment) { BLK_SEG(bs_ptr, buffaddr + SIZEOF(blk_hdr), curr_rec_offset - SIZEOF(blk_hdr)); BLK_ADDR(curr_rec_hdr, SIZEOF(rec_hdr), rec_hdr); curr_rec_hdr->rsiz = new_rec_size; SET_CMPC(curr_rec_hdr, prev_rec_match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr, SIZEOF(rec_hdr)); BLK_ADDR(cp1, target_key_size - prev_rec_match, unsigned char); memcpy(cp1, temp_key->base + prev_rec_match, target_key_size - prev_rec_match); BLK_SEG(bs_ptr, cp1, target_key_size - prev_rec_match); if (0 != value.len) { BLK_ADDR(va, value.len, char); memcpy(va, value.addr, value.len); BLK_SEG(bs_ptr, (unsigned char *)va, value.len); } if (!new_rec) rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)rp + rec_size); n = (int)(cur_blk_size - ((sm_uc_ptr_t)rp - buffaddr)); if (n > 0) { if (new_rec) { BLK_ADDR(next_rec_hdr, SIZEOF(rec_hdr), rec_hdr); next_rec_hdr->rsiz = rec_size - next_rec_shrink; SET_CMPC(next_rec_hdr, curr_rec_match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)next_rec_hdr, SIZEOF(rec_hdr)); next_rec_shrink += SIZEOF(rec_hdr); } if (n >= next_rec_shrink) { BLK_SEG(bs_ptr, (sm_uc_ptr_t)rp + next_rec_shrink, n - next_rec_shrink); } else { assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } } } else { /* With GT.M TRIGGERS, it is not clear how the RC protocol will work. The below assert is to * be informed whenever such usage happens (expected to be really rare) and handle it right * then instead of worrying about it during the initial trigger implementation. */ assert(FALSE); curr_rec_hdr = (rec_hdr_ptr_t)(buffaddr + curr_rec_offset); EVAL_CMPC2(curr_rec_hdr, tmp_cmpc); /* First piece is block prior to record + key + data prior to fragment */ BLK_SEG(bs_ptr, buffaddr + SIZEOF(blk_hdr), curr_rec_offset - SIZEOF(blk_hdr) + SIZEOF(rec_hdr) + rc_set_fragment + gv_currkey->end + 1 - tmp_cmpc); /* Second piece is fragment itself */ BLK_ADDR(va, value.len, char); memcpy(va, value.addr, value.len); BLK_SEG(bs_ptr, (unsigned char *)va, value.len); /* Third piece is data after fragment + rest of block after record */ n = (int)(cur_blk_size - ((sm_uc_ptr_t)curr_rec_hdr - buffaddr) - SIZEOF(rec_hdr) - (gv_currkey->end + 1 - tmp_cmpc) - rc_set_fragment - value.len); if (0 < n) BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr + gv_currkey->end + 1 - tmp_cmpc + rc_set_fragment + value.len, n); } if (0 == BLK_FINI(bs_ptr, bs1)) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } assert(bs1[0].len <= blk_reserved_size); /* Assert that new block has space for reserved bytes */ cse = t_write(bh, (unsigned char *)bs1, ins_chain_offset, ins_chain_index, bh_level, FALSE, FALSE, GDS_WRITE_PLAIN); assert(!dollar_tlevel || !cse->high_tlevel); if ((0 != ins_chain_offset) && (NULL != cse) && (0 != cse->first_off)) { /* formerly tp_offset_chain - inserts a new_entry in the chain */ assert((NULL != cse->new_buff) || horiz_growth && cse->low_tlevel->new_buff && (buffaddr == cse->low_tlevel->new_buff)); assert(0 == cse->next_off); assert(ins_chain_offset > (signed)SIZEOF(blk_hdr)); /* we want signed comparison */ assert((curr_rec_offset - SIZEOF(off_chain)) == (ins_chain_offset - new_rec_size)); offset_sum = cse->first_off; curr = buffaddr + offset_sum; /* The typecast is needed below to enforce a "signed int" (versus "unsigned int") comparison */ if (offset_sum >= (signed int)curr_rec_offset) { /* the new record is prior to the first existing chain record, id the new one as first */ /* first_off-------------v--------------------v * [blk_hdr]...[new rec ( )]...[existing rec ( )]... */ cse->next_off = cse->first_off - (ins_chain_offset - new_rec_size) - next_rec_shrink1; cse->first_off = ins_chain_offset; } else { if (horiz_growth) { old_cse = cse->low_tlevel; assert(old_cse->first_off); assert(old_cse && old_cse->done); assert(!old_cse->undo_next_off[0] && !old_cse->undo_offset[0]); } /* find chain records before and after the new one */ for ( ; ; curr += curr_chain.next_off) { /* try to make offset_sum identify the first chain entry after the new record */ GET_LONGP(&curr_chain, curr); assert(curr_chain.flag == 1); if (0 == curr_chain.next_off) break; offset_sum += curr_chain.next_off; /* The typecast is needed below to enforce a "signed int" comparison */ if (offset_sum >= (signed int)curr_rec_offset) break; } /* store the next_off in old_cse before changing it in the buffer (for rolling back) */ if (horiz_growth) { old_cse->undo_next_off[0] = curr_chain.next_off; old_cse->undo_offset[0] = (block_offset)(curr - buffaddr); assert(old_cse->undo_offset[0]); } if (0 == curr_chain.next_off) { /* the last chain record precedes the new record: just update it */ /* ---|---------------v * [blk_hdr]...[existing rec ( )]...[new rec ( )]... */ curr_chain.next_off = ins_chain_offset - offset_sum; GET_LONGP(curr, &curr_chain); } else { /* update the chain record before the new one */ /* ---|---------------v--------------------v * [blk_hdr]...[existing rec ( )]...[new rec ( )]...[existing rec ( )] */ curr_chain.next_off = (unsigned int)(ins_chain_offset - (curr - buffaddr)); GET_LONGP(curr, &curr_chain); cse->next_off = offset_sum - (ins_chain_offset - new_rec_size) - next_rec_shrink1; } } assert((ins_chain_offset + (int)cse->next_off) <= (delta + (sm_long_t)cur_blk_size - SIZEOF(off_chain))); } succeeded = TRUE; if (level_0) { if (new_rec) { /* New record insertion at leaf level. gvcst_search would have already updated clue to * reflect the new key, but we need to fix the search history to keep it in sync with clue. * This search history (and clue) will be used by the NEXT call to gvcst_search. * Note that clue.end could be 0 at this point (see "Clue less than first rec, invalidate" * comment in gvcst_search) in which case the below assignment is unnecessary (though does * not hurt) but we want to avoid the if check (since we expect clue to be non-zero mostly). */ assert((0 == gv_target->clue.end) || (gv_target->clue.end + 1 == target_key_size)); assert(1 < target_key_size); assert(bh->curr_rec.match != target_key_size); bh->curr_rec.match = target_key_size; } /* ------------------------------------------------------------------------------------------------- * We have to maintain information for future recomputation only if the following are satisfied * 1) The block is a leaf-level block * 2) We are in TP (indicated by non-null cse) * 3) The global has NOISOLATION turned ON * 4) The cw_set_element hasn't encountered a block-split or a kill * 5) We don't need an extra_block_split * * We can also add an optimization that only cse's of mode gds_t_write need to have such updations, * but because of the belief that for a nonisolated variable, we will very rarely encounter a * situation where a created block (in TP) will have some new keys added to it, and that adding * the check slows down the normal code, we don't do that check here. * ------------------------------------------------------------------------------------------------- */ if (cse && gv_target->noisolation && !cse->write_type && !need_extra_block_split) { assert(dollar_tlevel); if (is_dollar_incr) { /* See comment in ENSURE_VALUE_WITHIN_MAX_REC_SIZE macro * definition for why the below macro call is necessary. */ ADD_TO_GVT_TP_LIST(gv_target, RESET_FIRST_TP_SRCH_STATUS_FALSE); rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_GVINCRISOLATION, 2, gv_target->gvname.var_name.len, gv_target->gvname.var_name.addr); } if (NULL == cse->recompute_list_tail || 0 != memcmp(gv_currkey->base, cse->recompute_list_tail->key.base, gv_currkey->top)) { tempkv = (key_cum_value *)get_new_element(si->recompute_list, 1); tempkv->key = *gv_currkey; tempkv->next = NULL; memcpy(tempkv->key.base, gv_currkey->base, gv_currkey->end + 1); if (NULL == cse->recompute_list_head) { assert(NULL == cse->recompute_list_tail); cse->recompute_list_head = tempkv; } else cse->recompute_list_tail->next = tempkv; cse->recompute_list_tail = tempkv; } else tempkv = cse->recompute_list_tail; assert(0 == val->str.len || ((val->str.len == bs1[4].len) && 0 == memcmp(val->str.addr, bs1[4].addr, val->str.len))); tempkv->value.len = val->str.len; /* bs1[4].addr is undefined if val->str.len is 0 */ tempkv->value.addr = (char *)bs1[4].addr;/* but not used in that case, so ok */ } } } else { /* Block split required */ split_depth++; gv_target->clue.end = 0; /* invalidate clue */ /* Potential size of the left and right blocks, including the new record */ new_blk_size_l = curr_rec_offset + new_rec_size; new_blk_size_r = SIZEOF(blk_hdr) + SIZEOF(rec_hdr) + target_key_size + value.len + cur_blk_size - curr_rec_offset - (new_rec ? next_rec_shrink : rec_size); assert(new_blk_size_single <= blk_reserved_size); assert(blk_reserved_size >= blk_fill_size); extra_record_orig_size = 0; prev_rec_offset = bh->prev_rec.offset; /* Decide which side (left or right) the new record goes. Ensure either side has at least one record. * This means we might not honor the desired FillFactor if the only record in a block exceeds the * blk_fill_size, but in this case we are guaranteed the block has room for the current reserved bytes. * The typecast of curr_rec_offset is needed below to enforce a "signed int" comparison. */ if (new_blk_size_r > blk_fill_size) { new_rec_goes_to_right = (new_blk_size_r == new_blk_size_single); last_split_dir = NEWREC_DIR_FORCED; /* no choice in split direction */ } else if (new_blk_size_l > blk_fill_size) { new_rec_goes_to_right = TRUE; last_split_dir = NEWREC_DIR_FORCED; /* no choice in split direction */ } else { /* new_rec can go in either direction without any issues of fitting in. * This is where we need to use a few heuristics to ensure good block space utilization. * We note down which direction (left or right) the new record went in after the split. * We use that as the heuristic to identify the direction of data loading and do the * splits accordingly for future updates. */ last_split_dir = (enum split_dir)gv_target->last_split_direction[bh_level]; if (NEWREC_DIR_FORCED == last_split_dir) { /* dont have prior information to use heuristic. choose whichever side is less full. * if this turns out to not be the correct choice, we will correct ourselves at the * time of the next block split at the same level. */ last_split_dir = (new_blk_size_l < new_blk_size_r) ? NEWREC_DIR_LEFT : NEWREC_DIR_RIGHT; } else { /* Last block split at this level chose a specific direction for new_rec. See if * that heuristic worked. This is done by checking if the block # that new_rec went * into previously is the same block that is being split now. If so, that means the * previous choice of direction was actually not optimal. So try the other direction now. */ last_split_bnum = gv_target->last_split_blk_num[bh_level]; if (dollar_tlevel) { chain2 = *(off_chain *)&last_split_bnum; if (chain1.flag == chain2.flag) { if (!chain1.flag) blk_match = (blk_num == last_split_bnum); else { assert(chain1.cw_index < si->cw_set_depth); blk_match = (chain1.cw_index == chain2.cw_index); } } else blk_match = FALSE; } else { DEBUG_ONLY(chain1 = *(off_chain *)&last_split_bnum;) assert(!chain1.flag); blk_match = (blk_num == last_split_bnum); } is_split_dir_left = (NEWREC_DIR_LEFT == last_split_dir); if (blk_match) /* switch direction since last choice did not seem to have worked */ last_split_dir = is_split_dir_left ? NEWREC_DIR_RIGHT : NEWREC_DIR_LEFT; else { /* blk# did not match means there is a high likelihood that the current split * is happening in the OTHER sibling block from the previous block split operation * at the same level. There is no easy way of confirming this so we assume the * heuristic is doing its job, unless we see evidence otherwise. And that evidence * is IF the block sizes of the left and right halves dont match the direction of * choice (e.g. if we choose NEWREC_DIR_LEFT, we expect the right block to be * almost full and the left block to be almost empty and vice versa). * In this case too switch the direction. */ if (is_split_dir_left) { if (new_blk_size_l > new_blk_size_r) last_split_dir = NEWREC_DIR_RIGHT; } else { if (new_blk_size_l < new_blk_size_r) last_split_dir = NEWREC_DIR_LEFT; } } } new_rec_goes_to_right = (NEWREC_DIR_RIGHT == last_split_dir); } last_split_direction[bh_level] = (char)last_split_dir; if (new_rec_goes_to_right) { /* Left side of this block will be split off into a new block. * The new record and the right side of this block will remain in this block. */ /* prepare new block */ BLK_INIT(bs_ptr, bs1); if (level_0) { BLK_SEG(bs_ptr, buffaddr + SIZEOF(blk_hdr), curr_rec_offset - SIZEOF(blk_hdr)); } else { /* for index records, the record before the split becomes a new *-key */ /* Note: If the block split was caused by our appending the new record * to the end of the block, this code causes the record PRIOR to the * current *-key to become the new *-key. */ BLK_SEG(bs_ptr, buffaddr + SIZEOF(blk_hdr), prev_rec_offset - SIZEOF(blk_hdr)); BLK_ADDR(new_star_hdr, SIZEOF(rec_hdr), rec_hdr); new_star_hdr->rsiz = BSTAR_REC_SIZE; SET_CMPC(new_star_hdr, 0); BLK_SEG(bs_ptr, (sm_uc_ptr_t)new_star_hdr, SIZEOF(rec_hdr)); BLK_SEG(bs_ptr, (sm_uc_ptr_t)rp - SIZEOF(block_id), SIZEOF(block_id)); } new_blk_bs = bs1; if (0 == BLK_FINI(bs_ptr,bs1)) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } /* We want to assert that the left block has enough space for reserved bytes but * it is possible that it DOES NOT have enough space for reserved bytes if the pre-split * block was previously populated with a very low reserved bytes setting and if the current * reserved bytes setting is much higher than what the chosen split point would free up. * This is an issue waiting to be fixed by C9K01-003221. Until then the following assert * has to remain commented out. * * assert(bs1[0].len <= blk_reserved_size); */ /* prepare the existing block */ BLK_INIT(bs_ptr, bs1); ins_chain_offset = no_pointers ? 0 : (int)(SIZEOF(blk_hdr) + SIZEOF(rec_hdr) + target_key_size); left_hand_offset = left_hand_index = 0; if (!new_rec) rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)rp + rec_size); BLK_ADDR(curr_rec_hdr, SIZEOF(rec_hdr), rec_hdr); curr_rec_hdr->rsiz = target_key_size + SIZEOF(rec_hdr) + value.len; SET_CMPC(curr_rec_hdr, 0); BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr, SIZEOF(rec_hdr)); BLK_ADDR(cp1, target_key_size, unsigned char); memcpy(cp1, temp_key->base, target_key_size); BLK_SEG(bs_ptr, cp1, target_key_size); if (0 != value.len) { BLK_ADDR(va, value.len, char); memcpy(va, value.addr, value.len); BLK_SEG(bs_ptr, (unsigned char *)va, value.len); } if (buffaddr + cur_blk_size > (sm_uc_ptr_t)rp) { BLK_ADDR(next_rec_hdr, SIZEOF(rec_hdr), rec_hdr); GET_USHORT(next_rec_hdr->rsiz, &rp->rsiz); next_rec_hdr->rsiz -= next_rec_shrink; SET_CMPC(next_rec_hdr, new_rec ? curr_rec_match : EVAL_CMPC(rp)); BLK_SEG(bs_ptr, (sm_uc_ptr_t)next_rec_hdr, SIZEOF(rec_hdr)); next_rec_shrink += SIZEOF(rec_hdr); n = cur_blk_size - INTCAST(((sm_uc_ptr_t)rp - buffaddr)) - next_rec_shrink; if (0 > n) /* want signed compare as 'n' can be negative */ { assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } BLK_SEG(bs_ptr, (sm_uc_ptr_t)rp + next_rec_shrink, n); } if (0 == BLK_FINI(bs_ptr, bs1)) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } assert(bs1[0].len <= blk_reserved_size); /* Assert that right block has space for reserved bytes */ assert(gv_altkey->top == gv_currkey->top); assert(gv_altkey->end < gv_altkey->top); temp_key = gv_altkey; if (cdb_sc_normal != (status = gvcst_expand_key((blk_hdr_ptr_t)buffaddr, prev_rec_offset, temp_key))) GOTO_RETRY; } else { /* Insert in left hand (new) block */ if (!level_0) { /* In case of an index block, as long as the current record is not a *-record * (i.e. last record in the block) and copying an extra record into the left * block does not cause it to exceed the fill factor, copy an additional record. * Not doing the extra record copy for index blocks (was the case pre-V54002) has * been seen to create suboptimally filled index blocks (as low as 15% fillfactor) * depending on the patterns of updates. */ assert(new_rec); copy_extra_record = ((BSTAR_REC_SIZE != rec_size) && ((new_blk_size_l + BSTAR_REC_SIZE) <= blk_fill_size)); } else { copy_extra_record = ((0 == prev_rec_offset) && (NEWREC_DIR_LEFT == last_split_dir) && new_rec && (SIZEOF(blk_hdr) < cur_blk_size)); } BLK_INIT(bs_ptr, bs1); if (no_pointers) left_hand_offset = 0; else { left_hand_offset = curr_rec_offset + SIZEOF(rec_hdr); if (level_0 || copy_extra_record) left_hand_offset += target_key_size - prev_rec_match; } left_hand_index = ins_chain_index; ins_chain_index = ins_chain_offset = 0; BLK_SEG(bs_ptr, buffaddr + SIZEOF(blk_hdr), curr_rec_offset - SIZEOF(blk_hdr)); if (level_0) { /* After the initial split, will this record fit into the new left block? * If not, this pass will make room and we will do another block split on the next pass. */ assert((blk_seg_cnt + SIZEOF(rec_hdr) + target_key_size - prev_rec_match + value.len) == new_blk_size_l); assert((new_blk_size_single <= new_blk_size_l) || (CDB_STAGNATE > t_tries)); assert((new_blk_size_single != new_blk_size_l) || ((0 == prev_rec_offset) && (SIZEOF(blk_hdr) == curr_rec_offset))); assert((new_blk_size_single >= new_blk_size_l) || ((SIZEOF(blk_hdr) <= prev_rec_offset) && (SIZEOF(blk_hdr) < curr_rec_offset))); if ((new_blk_size_l > blk_fill_size) && (new_blk_size_l > new_blk_size_single)) { /* There is at least one existing record to the left of the split point. * Do the initial split this pass and make an extra split next pass. */ need_extra_block_split = TRUE; DEBUG_ONLY(dbg_trace_array[dbg_num_iters].is_extra_block_split = TRUE;) } else { BLK_ADDR(curr_rec_hdr, SIZEOF(rec_hdr), rec_hdr); curr_rec_hdr->rsiz = new_rec_size; SET_CMPC(curr_rec_hdr, prev_rec_match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr, SIZEOF(rec_hdr)); BLK_ADDR(cp1, target_key_size - prev_rec_match, unsigned char); memcpy(cp1, temp_key->base + prev_rec_match, target_key_size - prev_rec_match); BLK_SEG(bs_ptr, cp1, target_key_size - prev_rec_match); if (0 != value.len) { BLK_ADDR(va, value.len, char); memcpy(va, value.addr, value.len); BLK_SEG(bs_ptr, (unsigned char *)va, value.len); } if (copy_extra_record) { n = rec_size - curr_rec_match; /* typecast needed below to enforce a "signed int" comparison */ if ((n + (signed int)curr_rec_offset + new_rec_size) > blk_fill_size) copy_extra_record = FALSE; else { BLK_ADDR(extra_rec_hdr, SIZEOF(rec_hdr), rec_hdr); extra_rec_hdr->rsiz = n; SET_CMPC(extra_rec_hdr, curr_rec_match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)extra_rec_hdr, SIZEOF(rec_hdr)); if (n < (signed)SIZEOF(rec_hdr)) /* want signed compare */ { /* as 'n' can be negative */ assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } BLK_SEG(bs_ptr, buffaddr + SIZEOF(blk_hdr) + SIZEOF(rec_hdr) + curr_rec_match, n - SIZEOF(rec_hdr)); new_blk_size_l += n; } } } } else { if (copy_extra_record) { BLK_ADDR(curr_rec_hdr, SIZEOF(rec_hdr), rec_hdr); curr_rec_hdr->rsiz = new_rec_size; SET_CMPC(curr_rec_hdr, prev_rec_match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr, SIZEOF(rec_hdr)); BLK_ADDR(cp1, target_key_size - prev_rec_match, unsigned char); memcpy(cp1, temp_key->base + prev_rec_match, target_key_size - prev_rec_match); BLK_SEG(bs_ptr, cp1, target_key_size - prev_rec_match); assert(value.len); BLK_ADDR(va, value.len, char); memcpy(va, value.addr, value.len); BLK_SEG(bs_ptr, (unsigned char *)va, value.len); new_blk_size_l += BSTAR_REC_SIZE; } else new_blk_size_l = curr_rec_offset + BSTAR_REC_SIZE; BLK_ADDR(new_star_hdr, SIZEOF(rec_hdr), rec_hdr); new_star_hdr->rsiz = BSTAR_REC_SIZE; SET_CMPC(new_star_hdr, 0); BLK_SEG(bs_ptr, (sm_uc_ptr_t)new_star_hdr, SIZEOF(rec_hdr)); if (!copy_extra_record) { BLK_SEG(bs_ptr, (unsigned char *)&zeroes, SIZEOF(block_id)); } else BLK_SEG(bs_ptr, (sm_uc_ptr_t)rp + rec_size - SIZEOF(block_id), SIZEOF(block_id)); } new_blk_bs = bs1; if (0 == BLK_FINI(bs_ptr, bs1)) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } /* We want to assert that the left block has enough space for reserved bytes but * it is possible that it DOES NOT have enough space for reserved bytes if the pre-split * block was previously populated with a very low reserved bytes setting and if the current * reserved bytes setting is much higher than what the chosen split point would free up. * This is an issue waiting to be fixed by C9K01-003221. Until then the following assert * has to remain commented out. * * assert(bs1[0].len <= blk_reserved_size); */ /* assert that both !new_rec and copy_extra_record can never be TRUE at the same time */ assert(new_rec || !copy_extra_record); if (!new_rec || copy_extra_record) { /* Should guard for empty block??? */ rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)rp + rec_size); rec_cmpc = EVAL_CMPC(rp); temp_short = rec_size; GET_USHORT(rec_size, &rp->rsiz); } if (copy_extra_record) { extra_record_orig_size = temp_short; assert(gv_altkey->top == gv_currkey->top); assert(gv_altkey->end < gv_altkey->top); temp_key = gv_altkey; if (cdb_sc_normal != (status = gvcst_expand_key((blk_hdr_ptr_t)buffaddr, curr_rec_offset, temp_key))) GOTO_RETRY; } else if (temp_key != gv_altkey) { memcpy(gv_altkey, temp_key, SIZEOF(gv_key) + temp_key->end); temp_key = gv_altkey; } rec_size += rec_cmpc; BLK_INIT(bs_ptr, bs1); BLK_ADDR(next_rec_hdr, SIZEOF(rec_hdr), rec_hdr); next_rec_hdr->rsiz = rec_size; SET_CMPC(next_rec_hdr, 0); BLK_SEG(bs_ptr, (sm_uc_ptr_t)next_rec_hdr, SIZEOF(rec_hdr)); BLK_ADDR(cp1, rec_cmpc, unsigned char); memcpy(cp1, temp_key->base, rec_cmpc); BLK_SEG(bs_ptr, cp1, rec_cmpc); n = cur_blk_size - INTCAST(((sm_uc_ptr_t)rp - buffaddr)) - SIZEOF(rec_hdr); if (0 > n) /* want signed compare as 'n' can be negative */ { assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } BLK_SEG(bs_ptr, (sm_uc_ptr_t)(rp + 1), n); if (0 == BLK_FINI(bs_ptr, bs1)) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } /* We want to assert that the right block has enough space for reserved bytes but * it is possible that it DOES NOT have enough space for reserved bytes if the pre-split * block was previously populated with a very low reserved bytes setting and if the current * reserved bytes setting is much higher than what the chosen split point would free up. * This is an issue waiting to be fixed by C9K01-003221. Until then the following assert * has to remain commented out. * * assert(bs1[0].len <= blk_reserved_size); */ } next_blk_index = t_create(blk_num, (uchar_ptr_t)new_blk_bs, left_hand_offset, left_hand_index, bh_level); if (!no_pointers && dollar_tlevel) { /* there may be chains */ assert(new_rec); curr_chain = *(off_chain *)&blk_num; if (curr_chain.flag == 1) tp_get_cw(si->first_cw_set, curr_chain.cw_index, &cse); else { if (NULL != (tabent = lookup_hashtab_int4(si->blks_in_use, (uint4 *)&blk_num))) tp_srch_status = tabent->value; else tp_srch_status = NULL; cse = tp_srch_status ? tp_srch_status->cse : NULL; } assert(!cse || !cse->high_tlevel); if ((NULL != cse) && (0 != cse->first_off)) { /* there is an existing chain: fix to account for the split */ assert(NULL != cse->new_buff); assert(cse->done); assert(0 == cse->next_off); cse_new = si->last_cw_set; assert(!cse_new->high_tlevel); assert(0 == cse_new->next_off); assert(0 == cse_new->first_off); assert(cse_new->ins_off == left_hand_offset); assert(cse_new->index == left_hand_index); assert(cse_new->level == cse->level); cse_first_off = (int4)cse->first_off; offset_sum = cse_first_off; curr = buffaddr + offset_sum; GET_LONGP(&curr_chain, curr); assert(curr_chain.flag == 1); last_possible_left_offset = curr_rec_offset + extra_record_orig_size - SIZEOF(off_chain); /* some of the following logic used to be in tp_split_chain which was nixed */ if (offset_sum <= last_possible_left_offset) { /* the split falls within or after the chain; otherwise entire chain stays right */ assert((cse_first_off < curr_rec_offset) || (cse_first_off == last_possible_left_offset)); if (left_hand_offset && (curr_rec_offset < cse_first_off)) { /* We are inserting the new record (with the to-be-filled child block * number) AND an extra record in the left block and the TP block * chain of the block to be split starts AFTER the new record's offset * in the current block. This means the left block (cse_new) will have a * block chain starting with the newly inserted record's block pointer. */ cse_new->first_off = left_hand_offset; } else { cse_new->first_off = cse_first_off; assert(0 == cse_new->next_off); } if (level_0) /* if no *-key issue stop after, rather than at, a match */ last_possible_left_offset += SIZEOF(off_chain); if (offset_sum < last_possible_left_offset) { /* it's not an immediate hit */ for ( ; ; curr += curr_chain.next_off, GET_LONGP(&curr_chain, curr)) { /* follow chain upto split point */ assert(1 == curr_chain.flag); if (0 == curr_chain.next_off) break; offset_sum += curr_chain.next_off; if (offset_sum >= last_possible_left_offset) break; } /* end of search chain loop */ } assert(curr >= (buffaddr + cse_first_off)); if (level_0) /* restore match point to "normal" */ last_possible_left_offset -= SIZEOF(off_chain); if ((offset_sum == last_possible_left_offset) && !level_0) { /* The last record in the left side of the pre-split block is where * the search stopped. If no extra record copy was done, then this * record will end up BEFORE the inserted record in the post-split * left block. Otherwise this will be AFTER the inserted record. * * In case of copy_extra_record, the extra record will become the *-key * ---|------------v-----------------v * [blk_hdr]...[curr rec( )][new rec ( )] [extra rec (*-key)] * * In case of no extra record copy, the new record will become the *-key * ---|-------------------v * [blk_hdr]...[curr rec( )][new rec (*-key)( )] * * Take this into account during the calculations below. */ assert(cse_first_off <= last_possible_left_offset); if (left_hand_offset) { assert(!ins_chain_offset); if (!extra_record_orig_size && (offset_sum != cse_first_off)) { /* bring curr up to the match */ curr += curr_chain.next_off; GET_LONGP(&curr_chain, curr); } curr_offset = curr - buffaddr; undo_index = 0; if (curr_offset < curr_rec_offset) { /* The chain starts before the curr_rec_offset. Fix * next_off field from the last element in the chain * before this offset. */ prev_chain = curr_chain; assert(extra_record_orig_size || (BSTAR_REC_SIZE == (left_hand_offset - curr_offset))); prev_chain.next_off = left_hand_offset - curr_offset; assert((curr_offset + prev_chain.next_off) <= (new_blk_size_l - SIZEOF(off_chain))); if (dollar_tlevel != cse->t_level) { assert(dollar_tlevel > cse->t_level); assert(!cse->undo_next_off[0] && !cse->undo_offset[0]); assert(!cse->undo_next_off[1] && !cse->undo_offset[1]); cse->undo_next_off[0] = curr_chain.next_off; cse->undo_offset[0] = (block_offset)curr_offset; undo_index = 1; } GET_LONGP(curr, &prev_chain); } if (extra_record_orig_size) { if (offset_sum != cse_first_off) { /* bring curr up to the match */ curr += curr_chain.next_off; curr_offset += curr_chain.next_off; GET_LONGP(&curr_chain, curr); } if (dollar_tlevel != cse->t_level) { assert(dollar_tlevel > cse->t_level); assert(!cse->undo_next_off[undo_index] && !cse->undo_offset[undo_index]); cse->undo_next_off[undo_index] = curr_chain.next_off; cse->undo_offset[undo_index] = (block_offset)curr_offset; } prev_chain = curr_chain; prev_chain.next_off = 0; GET_LONGP(curr, &prev_chain); cse_new->next_off = BSTAR_REC_SIZE; } offset_sum += curr_chain.next_off; } else { undo_index = 0; /* the last record turns into the *-key */ if (offset_sum == cse_first_off) { /* it's all there is */ /* first_off --------------------v * [blk_hdr]...[curr rec (*-key)( )] */ assert(prev_rec_offset >= SIZEOF(blk_hdr)); cse_new->first_off = (block_offset)(prev_rec_offset + SIZEOF(rec_hdr)); } else { /* update the next_off of the previous chain record */ /* ---|--------------------v * [blk_hdr]...[prev rec( )][curr rec (*-key)( )] */ assert((buffaddr + prev_rec_offset) > curr); prev_chain = curr_chain; assert((offset_sum - prev_chain.next_off) /* check old */ == (curr - buffaddr)); /* method equivalent */ prev_chain.next_off = (unsigned int)( (prev_rec_offset + (unsigned int)(SIZEOF(rec_hdr)) - (curr - buffaddr))); assert((curr - buffaddr + prev_chain.next_off) <= ((new_blk_size_l < blk_reserved_size ? new_blk_size_l : blk_reserved_size) - SIZEOF(off_chain))); if (dollar_tlevel != cse->t_level) { assert(dollar_tlevel > cse->t_level); assert(!cse->undo_next_off[0] && !cse->undo_offset[0]); assert(!cse->undo_next_off[1] && !cse->undo_offset[1]); cse->undo_next_off[0] = curr_chain.next_off; cse->undo_offset[0] = (block_offset)(curr - buffaddr); undo_index = 1; } GET_LONGP(curr, &prev_chain); /* bring curr up to the match */ curr += curr_chain.next_off; GET_LONGP(&curr_chain, curr); } offset_sum += curr_chain.next_off; if (dollar_tlevel != cse->t_level) { assert(dollar_tlevel > cse->t_level); assert(!cse->undo_next_off[undo_index] && !cse->undo_offset[undo_index]); cse->undo_next_off[undo_index] = curr_chain.next_off; cse->undo_offset[undo_index] = (block_offset)(curr - buffaddr); } curr_chain.next_off = 0; GET_LONGP(curr, &curr_chain); } } else { /* found the split and no *-key issue: just terminate before the split */ if (offset_sum == cse_first_off) offset_sum += curr_chain.next_off; /* put it in the lead */ old_curr_chain_next_off = curr_chain.next_off; if (left_hand_offset) { /* there's a new chain rec in left */ curr_offset = curr - buffaddr; if (extra_record_orig_size && (curr_offset == last_possible_left_offset)) { assert(level_0); /* else *-key issues */ cse_new->next_off = extra_record_orig_size - next_rec_shrink1; } assert(!ins_chain_offset); /* put the new one at the end of the chain */ /* ---|---------------v * [blk_hdr]...[curr rec( )]...[new rec ( )] */ /* the new rec may or may not be a *-key */ assert((offset_sum - curr_chain.next_off) == curr_offset); assert(left_hand_offset > curr_offset); curr_chain.next_off = (block_offset)(left_hand_offset - curr_offset); } else curr_chain.next_off = 0; assert((curr - buffaddr + curr_chain.next_off) <= ((new_blk_size_l < blk_reserved_size ? new_blk_size_l : blk_reserved_size) - SIZEOF(off_chain))); if (dollar_tlevel != cse->t_level) { assert(dollar_tlevel > cse->t_level); assert(!cse->undo_next_off[0] && !cse->undo_offset[0]); assert(!cse->undo_next_off[1] && !cse->undo_offset[1]); cse->undo_next_off[0] = old_curr_chain_next_off; cse->undo_offset[0] = (block_offset)(curr - buffaddr); } GET_LONGP(curr, &curr_chain); } /* end of *-key or not alternatives */ assert((left_hand_offset + (int)cse_new->next_off) <= ((new_blk_size_l < blk_reserved_size ? new_blk_size_l : blk_reserved_size) - SIZEOF(off_chain))); } /* end of buffer and cse_new adjustments */ prev_first_off = cse_first_off; if (ins_chain_offset) { /* if there is a new chain rec in the old block, put it first */ /* first_off---------v * [blk_hdr][new rec( )]... */ assert(!left_hand_offset); assert(0 == extra_record_orig_size); assert(ins_chain_offset >= (SIZEOF(blk_hdr) + SIZEOF(rec_hdr))); cse->first_off = ins_chain_offset; assert(0 == cse->next_off); if (offset_sum > last_possible_left_offset) { /* there are existing chain records after the split */ /* first_off---------v--------------------v * [blk_hdr][new rec( )]...[existing rec ( )] */ prev_next_off = cse->next_off; cse->next_off = offset_sum - last_possible_left_offset - next_rec_shrink1; assert((int)(cse->next_off + ins_chain_offset) < new_blk_size_r); } } else if (offset_sum <= last_possible_left_offset) { /* the last chain record went left with the split */ cse->first_off = 0; } else { /* just adjust the anchor for the split */ /* first_off------------------v * [blk_hdr]...[existing rec ( )] */ assert(offset_sum >= (int)cse_first_off); cse->first_off = (block_offset)(offset_sum - last_possible_left_offset + rec_cmpc + SIZEOF(blk_hdr) - SIZEOF(off_chain)); assert(cse->first_off >= (SIZEOF(blk_hdr) + SIZEOF(rec_hdr))); } assert((ins_chain_offset + (int)cse->next_off) <= ((new_blk_size_r < blk_reserved_size ? new_blk_size_r : blk_reserved_size) - SIZEOF(off_chain))); } /* end of of split processing */ } /* end of tp only code */ if (!dollar_tlevel) cse = NULL; else { cse_new = si->last_cw_set; assert(!cse_new->high_tlevel); gvcst_blk_build(cse_new, NULL, 0); cse_new->done = TRUE; } /* Record block split heuristic info that will be used in next block split */ if (!new_rec_goes_to_right) { chain1.flag = 1; chain1.cw_index = next_blk_index; chain1.next_off = 0; assert(SIZEOF(gv_target->last_split_blk_num[bh_level]) == SIZEOF(off_chain)); last_split_blk_num[bh_level] = *(block_id *)&chain1; } else last_split_blk_num[bh_level] = blk_num; assert(temp_key == gv_altkey); /* If new_rec_goes_to_right is TRUE, then it almost always implies that the left side of * the block is almost full (i.e. adding the new record there caused it to exceed the fill * factor) therefore direct all future updates to keys in between (which lie between the * last key of the left block and the first key of the right block) to the right block. * * If not, direct those updates to the left block thereby preventing it from staying at a * low capacity for a long period of time. * * This direction of future updates is implemented by controlling what key gets passed for * record addition into the parent index block. For directing all in-between updates to the * right block, pass in the last key of the left block to the parent index block. For directing * all in-between updates to the left block, back off 1 spot from the first key of the right * block and pass that to the parent index block. * * Doing this backoff accurately would imply finding the last non-zero byte in the key and taking * 1 off from it. In case the length of the right key is less than the left key, it is possible * that this backoff causes the new key to be less than even the left key (e.g. if left side has * "C2 13 93 00" as key sequence corresponding to the number 1292 and right side has "C2 14 00" * corresponding to the number 1300, taking one off the right side would give "C2 13 00" which corresponds * to the number 12 and is lesser than the left side). In this case, we would have to start adding in * FF bytes to the key as much as possible until we reached the left key length. In the above example, * we would get "C2 13 FF 00". * * In the end, because of the complexities involved in getting an accurate backoff (see above paragraph), * we instead implement a simplified backoff by examining just the first byte that differs and the * immediately following byte (if needed). If it turns out that we cannot get a backoff with just * those 2 bytes (should be rare), we then let the left key go unmodified. In such cases, we expect * not many intervening possible keys and and therefore it does not matter that much whether we pass * the left or (right-1) key to the parent. * * There are two additional cases in which we let the left key go unmodified: 1) if the backoff would * result in a key larger than max_key_size and 2) if the left key ends in "00 00" and the right key ends * in "00 01 ... ". Backing off the 01 would give a index key with "00 00" in the middle. * * temp_key already holds the key corresponding to the last record of the left block. * bs1[2] and bs1[3] hold the key corresponding to the first record of the right block. */ if (level_0) { /* Determine key for record to pass on to parent index block */ cp1 = temp_key->base; assert(KEY_DELIMITER != *temp_key->base); cp2 = (unsigned char *)bs1[2].addr; bs1_2_len = bs1[2].len; for (i = 0; (i < bs1_2_len) && (*cp2 == *cp1); ++i) { ++cp2; ++cp1; } if (i == bs1_2_len) { cp2 = (unsigned char *)bs1[3].addr; bs1_3_len = bs1[3].len; for (j = 0; (j < bs1_3_len) && (*cp2 == *cp1); ++j) { ++cp2; ++cp1; } } n = (int)((sm_long_t)*cp2 - (sm_long_t)*cp1); if (0 > n) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } else if (1 < n) { temp_key->end = cp1 - temp_key->base + 2; if (temp_key->end < temp_key->top) { *cp1++ += (!new_rec_goes_to_right ? (n - 1) : 1); *cp1++ = 0; *cp1 = 0; } else { temp_key->end = temp_key->prev; assert(temp_key->end < temp_key->top); assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } } else if (1 == n) { cp1++; start_len = cp1 - temp_key->base + 2; if (start_len < temp_key->top) { if (i == (bs1_2_len - 1)) cp2 = (unsigned char *)bs1[3].addr; else cp2++; if (((KEY_DELIMITER != *(cp1 - 1)) || (KEY_DELIMITER != *(cp1 - 2))) && ((STR_SUB_MAXVAL != *cp1) || (KEY_DELIMITER != *cp2)) && (gv_cur_region->max_key_size > start_len)) { if (!new_rec_goes_to_right) { old_ch = *cp2; new_ch = old_ch - 1; *cp1 = new_ch; if (KEY_DELIMITER != old_ch) *(cp1 - 1) = *(cp2 - 1); } else { old_ch = *cp1; new_ch = old_ch + 1; *cp1 = new_ch; if (STR_SUB_MAXVAL == old_ch) *(cp1 - 1) = *(cp2 - 1); } cp1++; if (KEY_DELIMITER == new_ch) temp_key->end--; else *cp1++ = KEY_DELIMITER; *cp1 = KEY_DELIMITER; temp_key->end = cp1 - temp_key->base; } } else { temp_key->end = temp_key->prev; assert(temp_key->end < temp_key->top); assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } } } assert(temp_key->end < temp_key->top); assert(1 <= temp_key->end); assert(KEY_DELIMITER == temp_key->base[temp_key->end]); assert(KEY_DELIMITER == temp_key->base[temp_key->end - 1]); assert((2 > temp_key->end) || (KEY_DELIMITER != temp_key->base[temp_key->end - 2])); bq = bh + 1; if (HIST_TERMINATOR != bq->blk_num) { /* Not root; write blocks and continue */ if (cdb_sc_normal != (status = gvcst_search_blk(temp_key, bq))) GOTO_RETRY; /* It's necessary to disable the indexmod optimization for splits of index blocks. Refer to * GTM-7353, C9B11-001813 (GTM-3984), and C9H12-002934 (GTM-6104). */ cse = t_write(bh, (unsigned char *)bs1, ins_chain_offset, ins_chain_index, bh_level, TRUE, FALSE, (level_0) ? GDS_WRITE_PLAIN : GDS_WRITE_KILLTN); assert(!dollar_tlevel || !cse->high_tlevel); if (cse) { assert(dollar_tlevel); cse->write_type |= GDS_WRITE_BLOCK_SPLIT; } value.len = SIZEOF(block_id); value.addr = (char *)&zeroes; ++bh; ins_chain_index = next_blk_index; } else { /* Create new root */ if ((bh_level + 1) == MAX_BT_DEPTH) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_maxlvl; GOTO_RETRY; } ins_chain_index = t_create(blk_num, (uchar_ptr_t)bs1, ins_chain_offset, ins_chain_index, bh_level); make_it_null = FALSE; if (NULL != cse) { /* adjust block to use the buffer and offsets worked out for the old root */ assert(cse->done); assert(NULL != cse->new_buff); cse_new = si->last_cw_set; assert(!cse_new->high_tlevel); cse_new->blk_target = cse->blk_target; cse_new->first_off = cse->first_off; cse_new->next_off = cse->next_off; /* to be able to incrementally rollback, we need another copy of new_buff, * pointer copying wouldn't suffice */ cse_new->new_buff = (unsigned char *)get_new_free_element(si->new_buff_list); memcpy(cse_new->new_buff, cse->new_buff, ((blk_hdr_ptr_t)cse->new_buff)->bsiz); cse_new->old_block = NULL; make_it_null = TRUE; } /* Build the right child of the new root right now since it is possible that before commit the * root block may have been recycled in the global buffer which wouldn't cause a restart since * it has been built already (see the gvcst_blk_build below). Otherwise, we may be relying * on incorrect data in the root block when we build this right child finally in bg_update. * Note that this needs to be done only in TP since only tp_tend allows for a block with a * cse not to be in the global buffer if a new_buff already exists. */ if (dollar_tlevel) { DEBUG_ONLY(tp_get_cw(si->first_cw_set, ins_chain_index, &cse_new);) assert(cse_new == si->last_cw_set); cse_new = si->last_cw_set; assert(FALSE == cse_new->done); assert(!cse_new->high_tlevel); gvcst_blk_build(cse_new, NULL, 0); cse_new->done = TRUE; } target_key_size = temp_key->end + 1; BLK_INIT(bs_ptr, bs1); BLK_ADDR(curr_rec_hdr, SIZEOF(rec_hdr), rec_hdr); curr_rec_hdr->rsiz = target_key_size + SIZEOF(rec_hdr) + SIZEOF(block_id); SET_CMPC(curr_rec_hdr, 0); BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr, SIZEOF(rec_hdr)); BLK_ADDR(cp1, target_key_size, unsigned char); memcpy(cp1, temp_key->base, target_key_size); BLK_SEG(bs_ptr, cp1, target_key_size); BLK_SEG(bs_ptr, (unsigned char *)&zeroes, SIZEOF(block_id)); BLK_ADDR(next_rec_hdr, SIZEOF(rec_hdr), rec_hdr); next_rec_hdr->rsiz = BSTAR_REC_SIZE; SET_CMPC(next_rec_hdr, 0); BLK_SEG(bs_ptr, (sm_uc_ptr_t)next_rec_hdr, SIZEOF(rec_hdr)); BLK_SEG(bs_ptr, (unsigned char *)&zeroes, SIZEOF(block_id)); if (0 == BLK_FINI(bs_ptr, bs1)) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_mkblk; GOTO_RETRY; } assert(bs1[0].len <= blk_reserved_size); /* Assert that new block has space for reserved bytes */ ins_off1 = (block_offset)(SIZEOF(blk_hdr) + SIZEOF(rec_hdr) + target_key_size); ins_off2 = (block_offset)(SIZEOF(blk_hdr) + (2 * SIZEOF(rec_hdr)) + SIZEOF(block_id) + target_key_size); assert(ins_off1 < ins_off2); /* Since a new root block is not created but two new children are created, this update to the * root block should disable the "indexmod" optimization (C9B11-001813). */ cse = t_write(bh, (unsigned char *)bs1, ins_off1, next_blk_index, bh_level + 1, TRUE, FALSE, GDS_WRITE_KILLTN); if (make_it_null) cse->new_buff = NULL; assert(!dollar_tlevel || !cse->high_tlevel); if (!dollar_tlevel) { /* create a sibling cw-set-element to store ins_off2/ins_chain_index */ t_write_root(ins_off2, ins_chain_index); } else { cse->write_type |= GDS_WRITE_BLOCK_SPLIT; assert(NULL == cse->new_buff); cse->first_off = 0; cse->next_off = ins_off2 - ins_off1; /* the following is the only place where the buffer is not completely built by * gvcst_blk_build. this means that the block chain seen by gvcst_blk_build will * have a bad value (that is fixed below) at the end of the list. therefore the * block chain integrity checking code in gvcst_blk_build will error out normally * in this case. signal that routine to skip checking just this tail element. */ DEBUG_ONLY(skip_block_chain_tail_check = TRUE;) gvcst_blk_build(cse, NULL, 0); DEBUG_ONLY(skip_block_chain_tail_check = FALSE;) curr_chain.flag = 1; curr_chain.cw_index = ins_chain_index; curr_chain.next_off = 0; curr = cse->new_buff + ins_off2; GET_LONGP(curr, &curr_chain); cse->done = TRUE; gv_target->clue.end = 0; } succeeded = TRUE; } } } assert(succeeded); horiz_growth = FALSE; assert((csa->dir_tree == gv_target) || tp_root); RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, DO_GVT_GVKEY_CHECK); /* The only case where gv_target is still csa->dir_tree after the above RESET macro is if op_gvput was invoked * with gv_target being set to cs_addrs->dir_tree. In that case gbl_target_was_set would have been set to TRUE. Assert. */ assert((csa->dir_tree != gv_target) || gbl_target_was_set); /* Format the journal records only once for non-TP (irrespective of number of restarts). * We remember this through the variable "jnl_format_done". If TRUE, we do not redo the jnl_format. * The only exception is if we are in $INCREMENT in which case we need to reformat since the * current value (and hence the post-increment value) of the key might be different in different tries. * In this case, the restart code checks and resets "jnl_format_done" to FALSE. */ if (!dollar_tlevel) { nodeflags = 0; if (skip_dbtriggers) nodeflags |= JS_SKIP_TRIGGERS_MASK; if (duplicate_set) nodeflags |= JS_IS_DUPLICATE; assert(!jnl_format_done || !is_dollar_incr && (JNL_SET == non_tp_jfb_ptr->ja.operation)); if (need_extra_block_split) inctn_opcode = inctn_gvcstput_extra_blk_split; else if (JNL_WRITE_LOGICAL_RECS(csa) && !jnl_format_done) { jfb = jnl_format(JNL_SET, gv_currkey, (!is_dollar_incr ? val_forjnl : post_incr_mval), nodeflags); assert(NULL != jfb); jnl_format_done = TRUE; } succeeded = ((trans_num)0 != t_end(&gv_target->hist, dir_hist, TN_NOT_SPECIFIED)); inctn_opcode = inctn_invalid_op; if (succeeded) { if (NULL != dir_hist) { /* The Global Variable Tree was created in this transaction. So clear its gv_target to be safe. * The directory tree though will have a non-zero value and that can stay as it is since it * was validated in this transaction and was found good enough for us to commit. */ assert(dir_tree != gv_target); gv_target->clue.end = 0; } } else { /* "t_retry" would have already been invoked by "t_end". * So instead of going to "retry:", do only whatever steps from there are necessary here. */ RESTORE_ZERO_GVT_ROOT_ON_RETRY(lcl_root, gv_target, dir_hist, dir_tree); /*if (is_dollar_incr)*/ jnl_format_done = FALSE; /* need to reformat jnl records for $INCR even in case of non-TP */ GTMTRIG_DBG_ONLY(dbg_trace_array[dbg_num_iters].retry_line = __LINE__); goto tn_restart; } } else { status = tp_hist(dir_hist); if (NULL != dir_hist) { /* Note that although "tp_hist" processes the "dir_hist" history, it only adds "gv_target" to gvt_tp_list. * But csa->dir_tree might have had clue, blk-split related info etc. modified as part of this * gvcst_put invocation that might also need cleanup (just like any other gv_target) so add * csa->dir_tree to gvt_tp_list (if not already done). Therefore treat this as if tp_hist is doing * the ADD_TO_GVT_TP_LIST call for dir_tree. */ assert(dir_tree == csa->dir_tree); ADD_TO_GVT_TP_LIST(dir_tree, RESET_FIRST_TP_SRCH_STATUS_FALSE); /* note: above macro updates read_local_tn if necessary */ } if (cdb_sc_normal != status) GOTO_RETRY; jnl_format_done = !needfmtjnl; } if (succeeded) { if (0 == tp_root) { /* Fill in gv_target->root with newly created root block value. * Previously, root remained at 0 at the end of the transaction and it was left to the * NEXT transaction to do a gvcst_root_search and determine the new root block. * This was fine until recently when op_gvrectarg was reworked to NOT do a gvcst_root_search * (to avoid potential TP restarts while unwinding the M stack). This meant that gv_target->root * needed to be kept uptodate as otherwise it was possible for gv_target->root to be stale * after a op_gvrectarg causing incorrect behavior of following M code (see v52000/C9B10001765 * subtest for example where $order(^gvn,$$extrinsic) is done and extrinsic CREATES <^gvn>). */ GTMTRIG_ONLY(assert(!ztval_gvcst_put_redo);) assert(0 == gv_target->root); if (!dollar_tlevel) { tp_root = cw_set[root_blk_cw_index].blk; assert(gds_t_acquired == cw_set[root_blk_cw_index].old_mode); assert(gds_t_committed == cw_set[root_blk_cw_index].mode); assert(!IS_BITMAP_BLK(tp_root)); } else { chain1.flag = 1; chain1.cw_index = root_blk_cw_index; chain1.next_off = 0; /* does not matter what value we set this field to */ assert(SIZEOF(tp_root) == SIZEOF(chain1)); tp_root = *(block_id *)&chain1; } gv_target->root = tp_root; } if (need_extra_block_split) { /* The logical update required an extra block split operation first (which succeeded) so * get back to doing the logical update before doing any trigger invocations etc. */ GTMTRIG_ONLY(skip_hasht_read = (dollar_tlevel) ? TRUE : skip_hasht_read;) goto fresh_tn_start; } for (bh_level = 0; bh_level < split_depth; bh_level++) { blk_num = last_split_blk_num[bh_level]; assert(0 != blk_num); split_targ->last_split_blk_num[bh_level] = blk_num; assert((NEWREC_DIR_FORCED == last_split_direction[bh_level]) || (NEWREC_DIR_LEFT == last_split_direction[bh_level]) || (NEWREC_DIR_RIGHT == last_split_direction[bh_level])); split_targ->last_split_direction[bh_level] = last_split_direction[bh_level]; /* Fix blk_num if it was created in this transaction. In case of non-TP, we have the real block number * corresponding to the created block. In case of TP, we can know that only at tp_clean_up time so defer. */ chain1 = *(off_chain *)&blk_num; if (chain1.flag) { if (!dollar_tlevel) { assert(chain1.cw_index < ARRAYSIZE(cw_set)); split_targ->last_split_blk_num[bh_level] = cw_set[chain1.cw_index].blk; } else split_targ->split_cleanup_needed = TRUE;/* phantom blk# will be fixed at tp_clean_up time */ } } if (dollar_tlevel) { nodeflags = 0; if (skip_dbtriggers) nodeflags |= JS_SKIP_TRIGGERS_MASK; if (duplicate_set) nodeflags |= JS_IS_DUPLICATE; ja_val = (!is_dollar_incr ? val_forjnl : post_incr_mval); write_logical_jnlrecs = JNL_WRITE_LOGICAL_RECS(csa); # ifdef GTM_TRIGGER if (!skip_dbtriggers && parms->enable_trigger_read_and_fire) { /* Since we are about to invoke the trigger, we better have gv_target->gvt_trigger and * the local variable gvt_trigger in sync. The only exception is when we are here because * of a $ztvalue update and redoing the gvcst_put. In this case, it's possible that * the trigger code that was previously executed deleted the trigger and did an update * on the global which would have set gv_target->gvt_trigger to NULL. Assert accordingly. */ assert(ztval_gvcst_put_redo || (gvt_trigger == gv_target->gvt_trigger)); if ((NULL != gvt_trigger) && !ztval_gvcst_put_redo) { assert(dollar_tlevel); /* Format ZTWORM and SET journal records. * "ztworm_jfb", "jfb" and "jnl_format_done" are set by the below macro. */ JNL_FORMAT_ZTWORM_IF_NEEDED(csa, write_logical_jnlrecs, JNL_SET, gv_currkey, ja_val, ztworm_jfb, jfb, jnl_format_done); /* Initialize trigger parms that dont depend on the context of the matching trigger */ trigparms.ztoldval_new = key_exists ? ztold_mval : (mval *)&literal_null; PUSH_MV_STENT(MVST_MVAL); /* protect $ztval from stp_gcol */ ztval_mval = &mv_chain->mv_st_cont.mvs_mval; if (!is_dollar_incr) *ztval_mval = *val_forjnl; else { *ztval_mval = *post_incr_mval; /* Since this is pointing to malloced buffer, we need to repoint it to stringpool * to avoid a nested trigger call (that does a $INCR) from overwriting this buffer. * This way buffers corresponding to $ztvals of nested triggers can coexist. */ s2pool(&ztval_mval->str); } trigparms.ztvalue_new = ztval_mval; trigparms.ztdata_new = key_exists ? &literal_one : &literal_zero; gvtr_parms.gvtr_cmd = GVTR_CMDTYPE_SET; gvtr_parms.gvt_trigger = gvt_trigger; /* Now that we have filled in minimal information, let "gvtr_match_n_invoke" do the rest */ gtm_trig_status = gvtr_match_n_invoke(&trigparms, &gvtr_parms); assert((0 == gtm_trig_status) || (ERR_TPRETRY == gtm_trig_status)); if (ERR_TPRETRY == gtm_trig_status) { /* A restart has been signaled that we need to handle or complete the handling of. * This restart could have occurred reading the trigger in which case no * tp_restart() has yet been done or it could have occurred in trigger code in * which case we need to finish the incomplete tp_restart. In both cases this * must be an implicitly TP wrapped transaction. Our action is to complete the * necessary tp_restart() logic (t_retry is already completed so should be skipped) * and then re-do the gvcst_put logic. */ assert(lcl_implicit_tstart || lcl_span_status); assert(CDB_STAGNATE >= t_tries); status = cdb_sc_normal; /* signal "retry:" to avoid t_retry call */ GOTO_RETRY; } REMOVE_ZTWORM_JFB_IF_NEEDED(ztworm_jfb, jfb, si); if (trigparms.ztvalue_changed) { /* At least one of the invoked triggers changed $ztval. * Redo the gvcst_put with $ztval as the right side of the SET. * Also make sure gtm_trigger calls are NOT done this time around. */ assert(0 < gvtr_parms.num_triggers_invoked); val = trigparms.ztvalue_new; val_forjnl = trigparms.ztvalue_new; MV_FORCE_STR(val); /* in case the updated value happens to be a numeric quantity */ fits = RECORD_FITS_IN_A_BLOCK(val, gv_currkey, blk_size, blk_reserved_bytes); if (!fits) { /* If val is now too big to fit in a block, we need to back out into * gvcst_put and try again with spanning nodes. This means we should * OP_TROLLBACK if lcl_implicit_tstart. */ if (lcl_implicit_tstart) { POP_MVALS_FROM_M_STACK_IF_NEEDED(ztold_mval, save_msp, save_mv_chain); OP_TROLLBACK(-1); assert(!lcl_span_status); parms->span_status = TRUE; } else { parms->ztval_gvcst_put_redo = TRUE; parms->ztval_mval = val; } RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, DO_GVT_GVKEY_CHECK); return; } ztval_gvcst_put_redo = TRUE; skip_hasht_read = TRUE; /* In case, the current gvcst_put invocation was for $INCR, reset the corresponding * global variable that indicates a $INCR is in progress since the redo of the * gvcst_put is a SET command (no longer $INCR). */ is_dollar_incr = FALSE; /* Dont pop the mvals as we want ztval_mval (which points to the mval containing * "val" for the redo iteration) protected-from-stp_gcol/accessible until the * redo is complete. */ goto fresh_tn_start; } } /* We don't want to pop mvals yet if we still need to set chunks of ztval */ POP_MVALS_FROM_M_STACK_IF_REALLY_NEEDED(lcl_span_status, ztold_mval, save_msp, save_mv_chain); /* pop any stacked mvals before op_tcommit as it does its own popping */ } # endif if (write_logical_jnlrecs && !jnl_format_done) { assert(dollar_tlevel); # ifdef GTM_TRIGGER /* Do not replicate implicit update or $ztval redo update */ assert(tstart_trigger_depth <= gtm_trigger_depth); if ((gtm_trigger_depth > tstart_trigger_depth) || ztval_gvcst_put_redo) { /* Ensure that JS_SKIP_TRIGGERS_MASK and JS_NOT_REPLICATED_MASK are mutually exclusive. */ assert(!(nodeflags & JS_SKIP_TRIGGERS_MASK)); nodeflags |= JS_NOT_REPLICATED_MASK; } # endif jfb = jnl_format(JNL_SET, gv_currkey, ja_val, nodeflags); assert(NULL != jfb); jnl_format_done = TRUE; } # ifdef GTM_TRIGGER /* Go ahead with commit of any implicit TP wrapped transaction */ if (lcl_implicit_tstart) { GVTR_OP_TCOMMIT(status); if (cdb_sc_normal != status) GOTO_RETRY; } # endif } assert(!JNL_WRITE_LOGICAL_RECS(csa) || jnl_format_done); /* Now that the SET/$INCR is finally complete, increment the corresponding GVSTAT counter */ if (!lcl_span_status) INCR_GVSTATS_COUNTER(csa, cnl, n_set, 1); DBG_CHECK_VAL_AT_FUN_EXIT; assert(lcl_dollar_tlevel == dollar_tlevel); return; } retry: /* Note that it is possible cs_addrs is not equal to csa at this point in case we restarted due to trigger * invocations and in case those triggers referenced globals in different regions. But this should be fixed * by a call to t_retry/tp_restart below (it does a TP_CHANGE_REG(tp_pointer->gd_reg)). */ # ifdef GTM_TRIGGER if (lcl_implicit_tstart) { assert(!skip_dbtriggers); assert(!skip_INVOKE_RESTART); assert((cdb_sc_normal != status) || (ERR_TPRETRY == gtm_trig_status)); if (cdb_sc_normal != status) skip_INVOKE_RESTART = TRUE; /* causes t_retry to invoke only tp_restart without any rts_error */ /* else: t_retry has already been done by gtm_trigger so no need to do it again for this try */ /* If an implicitly TP wrapped transaction is restarting, restore things to what they were * at entry into gvcst_put. Note that we could have done multiple iterations of gvcst_put for * extra_block_split/retry/ztval_gvcst_put_redo. */ ztval_gvcst_put_redo = FALSE; skip_hasht_read = FALSE; val = lcl_val; val_forjnl = lcl_val_forjnl; /* $increment related fields need to be restored */ is_dollar_incr = lcl_is_dollar_incr; post_incr_mval = lcl_post_incr_mval; increment_delta_mval = lcl_increment_delta_mval; } # endif assert((cdb_sc_normal != status) GTMTRIG_ONLY(|| lcl_implicit_tstart || lcl_span_status)); if (cdb_sc_normal != status) { /* Need to restart. If directory tree was used in this transaction, nullify its clue as well (not normally * done by t_retry). The RESTORE_ZERO_GVT_ROOT_ON_RETRY macro call below takes care of that for us. */ RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, dollar_tlevel ? DO_GVT_GVKEY_CHECK_RESTART : DO_GVT_GVKEY_CHECK); RESTORE_ZERO_GVT_ROOT_ON_RETRY(lcl_root, gv_target, dir_hist, dir_tree); GTMTRIG_ONLY(POP_MVALS_FROM_M_STACK_IF_REALLY_NEEDED(lcl_span_status, ztold_mval, save_msp, save_mv_chain)); t_retry(status); GTMTRIG_ONLY(skip_INVOKE_RESTART = FALSE); } else { /* else: t_retry has already been done so no need to do that again but need to still invoke tp_restart * to complete pending "tprestart_state" related work. * SKIP_GVT_GVKEY_CHECK allows us to skip DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC if a trigger invocation * restarted during GVCST_ROOT_SEARCH, in which case gv_currkey will correspond to ^#t. * The subsequent tp_restart restores gv_currkey/gv_target to an in-sync state. */ RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, SKIP_GVT_GVKEY_CHECK); # ifdef GTM_TRIGGER assert(ERR_TPRETRY == gtm_trig_status); TRIGGER_BASE_FRAME_UNWIND_IF_NOMANSLAND; POP_MVALS_FROM_M_STACK_IF_REALLY_NEEDED(lcl_span_status, ztold_mval, save_msp, save_mv_chain) if (!lcl_implicit_tstart) { /* We started an implicit transaction for spanning nodes in gvcst_put. Invoke restart to return. */ assert(lcl_span_status && !skip_INVOKE_RESTART && (&gvcst_put_ch == ctxt->ch)); INVOKE_RESTART; } # endif rc = tp_restart(1, !TP_RESTART_HANDLES_ERRORS); assert(0 == rc GTMTRIG_ONLY(&& TPRESTART_STATE_NORMAL == tprestart_state)); DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); /* finishs the check skipped above */ RESTORE_ZERO_GVT_ROOT_ON_RETRY(lcl_root, gv_target, dir_hist, dir_tree); } # ifdef GTM_TRIGGER assert(0 < t_tries); assert((cdb_sc_normal != status) || (ERR_TPRETRY == gtm_trig_status)); if (cdb_sc_normal == status) { DEBUG_ONLY(save_cdb_status = status); status = LAST_RESTART_CODE; } assert((cdb_sc_onln_rlbk2 != status) || TREF(dollar_zonlnrlbk)); assert(((cdb_sc_onln_rlbk1 != status) && (cdb_sc_onln_rlbk2 != status)) || !gv_target->root); if ((cdb_sc_onln_rlbk2 == status) && lcl_implicit_tstart) { /* Database was taken back to a different logical state and we are an implicit TP transaction. * Issue DBROLLEDBACK error that the application programmer can catch and do the necessary stuff. */ assert(gtm_trigger_depth == tstart_trigger_depth); rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_DBROLLEDBACK); } /* Note: In case of cdb_sc_onln_rlbk1, the restart logic will take care of doing the root search */ # endif GTMTRIG_ONLY(assert(!skip_INVOKE_RESTART);) /* if set to TRUE a few statements above, should have been reset by t_retry */ /* At this point, we can be in TP only if we implicitly did a tstart in gvcst_put (as part of a trigger update). * Assert that. Since the t_retry/tp_restart would have reset si->update_trans, we need to set it again. * So reinvoke the T_BEGIN call only in case of TP. For non-TP, update_trans is unaffected by t_retry. */ assert(!dollar_tlevel GTMTRIG_ONLY(|| lcl_implicit_tstart)); if (dollar_tlevel) { jnl_format_done = !needfmtjnl; /* need to reformat jnl records unconditionally in case of TP */ tp_set_sgm(); /* set sgm_info_ptr & first_sgm_info for TP start */ T_BEGIN_SETORKILL_NONTP_OR_TP(ERR_GVPUTFAIL); /* set update_trans and t_err for wrapped TP */ } else if (is_dollar_incr) jnl_format_done = !needfmtjnl; /* need to reformat jnl records for $INCR even in case of non-TP */ assert(dollar_tlevel || update_trans); goto tn_restart; } fis-gtm-V6.0-003/sr_port/gvcst_query.c0000644000032200000250000001467612201176157016571 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "cdb_sc.h" #include "filestruct.h" /* needed for jnl.h */ #include "gdscc.h" /* needed for tp.h */ #include "jnl.h" /* needed for tp.h */ #include "gdskill.h" /* needed for tp.h */ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* needed for T_BEGIN_READ_NONTP_OR_TP macro */ #ifdef UNIX /* needed for frame_pointer in GVCST_ROOT_SEARCH_AND_PREP macro */ # include "repl_msg.h" # include "gtmsource.h" # include "rtnhdr.h" # include "stack_frame.h" # include "wbox_test_init.h" #endif #include "t_end.h" #include "t_retry.h" #include "t_begin.h" #include "gvcst_expand_key.h" #include "gvcst_protos.h" /* for gvcst_rtsib,gvcst_search,gvcst_search_blk,gvcst_query prototype */ /* needed for spanning nodes */ #include "op.h" #include "op_tcommit.h" #include "error.h" #include "tp_frame.h" #include "tp_restart.h" #include "gtmimagename.h" LITREF mval literal_batch; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF gd_region *gv_cur_region; GBLREF gv_namehead *gv_target; GBLREF gv_key *gv_currkey, *gv_altkey; GBLREF uint4 dollar_tlevel; GBLREF unsigned int t_tries; error_def(ERR_DBROLLEDBACK); error_def(ERR_GVQUERYFAIL); error_def(ERR_TPRETRY); DEFINE_NSB_CONDITION_HANDLER(gvcst_query_ch) bool gvcst_query(void) { /* Similar to gvcst_order and gvcst_zprevious. In each case we skip over hidden subscripts as needed. * * 1 2 3 NULL <--- order/zprev... * 1 2 3 NULL NULL * 1 2 3 NULL NULL NULL <--- query from here... * 1 2 3 NULL NULL NULL hidden * 1 2 3 NULL NULL hidden * 1 2 3 NULL hidden * 1 2 3 hidden <--- ... skip this guy and go to bottom/top, respectively * 1 2 3 7 <--- ... needs to end up here */ bool found, is_hidden, sn_tpwrapped; boolean_t est_first_pass; char save_currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)]; gv_key *save_gv_currkey; int end, i; int save_dollar_tlevel; DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); found = gvcst_query2(); # ifdef UNIX assert(save_dollar_tlevel == dollar_tlevel); CHECK_HIDDEN_SUBSCRIPT_AND_RETURN(found, gv_altkey, is_hidden); IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(return found); assert(found && is_hidden); SAVE_GV_CURRKEY; if (!dollar_tlevel) { sn_tpwrapped = TRUE; op_tstart((IMPLICIT_TSTART), TRUE, &literal_batch, 0); ESTABLISH_NORET(gvcst_query_ch, est_first_pass); GVCST_ROOT_SEARCH_AND_PREP(est_first_pass); } else sn_tpwrapped = FALSE; for (i = 0; i <= MAX_GVSUBSCRIPTS; i++) { INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_query, (gtm_uint64_t) -1); found = gvcst_query2(); CHECK_HIDDEN_SUBSCRIPT_AND_BREAK(found, gv_altkey, is_hidden); assert(found && is_hidden); /* Replace last subscript to be the highest possible hidden subscript so another * gvcst_query2 will give us the next non-hidden subscript. */ end = gv_altkey->end; gv_currkey->base[end - 4] = 2; gv_currkey->base[end - 3] = 0xFF; gv_currkey->base[end - 2] = 0xFF; gv_currkey->base[end - 1] = 1; gv_currkey->base[end + 0] = 0; gv_currkey->base[end + 1] = 0; gv_currkey->end = end + 1; } if (sn_tpwrapped) { op_tcommit(); REVERT; /* remove our condition handler */ } RESTORE_GV_CURRKEY; assert(save_dollar_tlevel == dollar_tlevel); # endif return found; } bool gvcst_query2(void) { boolean_t found, two_histories; enum cdb_sc status; blk_hdr_ptr_t bp; rec_hdr_ptr_t rp; unsigned char *c1, *c2; srch_blk_status *bh; srch_hist *rt_history; T_BEGIN_READ_NONTP_OR_TP(ERR_GVQUERYFAIL); assert(t_tries < CDB_STAGNATE || cs_addrs->now_crit); /* we better hold crit in the final retry (TP & non-TP) */ for (;;) { two_histories = FALSE; #if defined(DEBUG) && defined(UNIX) if (gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_GVQUERYFAIL == gtm_white_box_test_case_number)) { t_retry(cdb_sc_blknumerr); continue; } #endif if (cdb_sc_normal == (status = gvcst_search(gv_currkey, 0))) { found = TRUE; bh = &gv_target->hist.h[0]; rp = (rec_hdr_ptr_t)(bh->buffaddr + bh->curr_rec.offset); bp = (blk_hdr_ptr_t)bh->buffaddr; if (rp >= (rec_hdr_ptr_t)CST_TOB(bp)) { two_histories = TRUE; rt_history = gv_target->alt_hist; status = gvcst_rtsib(rt_history, 0); if (cdb_sc_endtree == status) /* end of tree */ { found = FALSE; two_histories = FALSE; /* second history not valid */ } else if (cdb_sc_normal != status) { t_retry(status); continue; } else { bh = &rt_history->h[0]; if (cdb_sc_normal != (status = gvcst_search_blk(gv_currkey, bh))) { t_retry(status); continue; } rp = (rec_hdr_ptr_t)(bh->buffaddr + bh->curr_rec.offset); bp = (blk_hdr_ptr_t)bh->buffaddr; } } if (found) { /* !found indicates that the end of tree has been reached (see call to * gvcst_rtsib). If there is no more tree, don't bother doing expansion. */ status = gvcst_expand_key((blk_hdr_ptr_t)bh->buffaddr, (int4)((sm_uc_ptr_t)rp - bh->buffaddr), gv_altkey); if (cdb_sc_normal != status) { t_retry(status); continue; } } if (!dollar_tlevel) { if ((trans_num)0 == t_end(&gv_target->hist, !two_histories ? NULL : rt_history, TN_NOT_SPECIFIED)) continue; } else { status = tp_hist(!two_histories ? NULL : rt_history); if (cdb_sc_normal != status) { t_retry(status); continue; } } assert(cs_data == cs_addrs->hdr); INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_query, 1); if (found) { c1 = &gv_altkey->base[0]; c2 = &gv_currkey->base[0]; for (; *c2;) { if (*c2++ != *c1++) break; } if (!*c2 && !*c1) { return TRUE; } } return FALSE; } t_retry(status); } } fis-gtm-V6.0-003/sr_port/gvcst_queryget.c0000644000032200000250000001507112201176157017257 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "stringpool.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "cdb_sc.h" #include "copy.h" #include "filestruct.h" /* needed for jnl.h */ #include "gdscc.h" /* needed for tp.h */ #include "jnl.h" /* needed for tp.h */ #include "gdskill.h" /* needed for tp.h */ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* needed for T_BEGIN_READ_NONTP_OR_TP macro */ #ifdef UNIX /* needed for frame_pointer in GVCST_ROOT_SEARCH_AND_PREP macro */ # include "repl_msg.h" # include "gtmsource.h" # include "rtnhdr.h" # include "stack_frame.h" # include "wbox_test_init.h" #endif #include "gvcst_protos.h" /* for gvcst_queryget,gvcst_search,gvcst_rtsib,gvcst_search_blk prototype */ #include "gvcst_expand_key.h" #include "t_begin.h" #include "t_retry.h" #include "t_end.h" /* needed for spanning nodes */ #include "op.h" #include "op_tcommit.h" #include "error.h" #include "tp_frame.h" #include "tp_restart.h" #include "gtmimagename.h" LITREF mval literal_batch; LITREF mstr nsb_dummy; GBLREF gd_region *gv_cur_region; GBLREF gv_namehead *gv_target; GBLREF gv_key *gv_currkey, *gv_altkey; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF spdesc stringpool; GBLREF uint4 dollar_tlevel; GBLREF unsigned int t_tries; error_def(ERR_DBROLLEDBACK); error_def(ERR_GVQUERYGETFAIL); error_def(ERR_TPRETRY); DEFINE_NSB_CONDITION_HANDLER(gvcst_queryget_ch) boolean_t gvcst_queryget(mval *val) { bool found, is_hidden, is_dummy = FALSE, sn_tpwrapped; boolean_t est_first_pass; char save_currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)]; gv_key *save_gv_currkey; int save_dollar_tlevel; DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); found = gvcst_queryget2(val, NULL); # ifdef UNIX assert(save_dollar_tlevel == dollar_tlevel); CHECK_HIDDEN_SUBSCRIPT(gv_altkey, is_hidden); if (found && IS_SN_DUMMY(val->str.len, val->str.addr)) is_dummy = TRUE; if (!found || (!is_dummy && !is_hidden)) return found; IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(return found); SAVE_GV_CURRKEY; if (!dollar_tlevel) { sn_tpwrapped = TRUE; op_tstart((IMPLICIT_TSTART), TRUE, &literal_batch, 0); ESTABLISH_NORET(gvcst_queryget_ch, est_first_pass); GVCST_ROOT_SEARCH_AND_PREP(est_first_pass); } else sn_tpwrapped = FALSE; found = gvcst_query(); COPY_KEY(gv_currkey, gv_altkey); /* set gv_currkey to gv_altkey */ found = gvcst_get(val); INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_get, (gtm_uint64_t) -1); /* only counted externally as one get */ INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_query, (gtm_uint64_t) -1); if (sn_tpwrapped) { op_tcommit(); REVERT; /* remove our condition handler */ } RESTORE_GV_CURRKEY; assert(save_dollar_tlevel == dollar_tlevel); # endif return found; } boolean_t gvcst_queryget2(mval *val, unsigned char *sn_ptr) { blk_hdr_ptr_t bp; boolean_t found, two_histories; enum cdb_sc status; int rsiz, key_size, data_len; rec_hdr_ptr_t rp; srch_blk_status *bh; srch_hist *rt_history; unsigned short temp_ushort; int tmp_cmpc; DEBUG_ONLY(unsigned char *save_strp = NULL); T_BEGIN_READ_NONTP_OR_TP(ERR_GVQUERYGETFAIL); assert((CDB_STAGNATE > t_tries) || cs_addrs->now_crit); /* we better hold crit in the final retry (TP & non-TP) */ for (;;) { two_histories = FALSE; #if defined(DEBUG) && defined(UNIX) if (gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_GVQUERYGETFAIL == gtm_white_box_test_case_number)) { status = cdb_sc_blknumerr; t_retry(status); continue; } #endif if (cdb_sc_normal == (status = gvcst_search(gv_currkey, 0))) { found = TRUE; bh = &gv_target->hist.h[0]; rp = (rec_hdr_ptr_t)(bh->buffaddr + bh->curr_rec.offset); bp = (blk_hdr_ptr_t)bh->buffaddr; if (rp >= (rec_hdr_ptr_t)CST_TOB(bp)) { two_histories = TRUE; rt_history = gv_target->alt_hist; status = gvcst_rtsib(rt_history, 0); if (cdb_sc_endtree == status) /* end of tree */ { found = FALSE; two_histories = FALSE; /* second history not valid */ } else if (cdb_sc_normal != status) { t_retry(status); continue; } else { bh = &rt_history->h[0]; if (cdb_sc_normal != (status = gvcst_search_blk(gv_currkey, bh))) { t_retry(status); continue; } rp = (rec_hdr_ptr_t)(bh->buffaddr + bh->curr_rec.offset); bp = (blk_hdr_ptr_t)bh->buffaddr; } } /* !found indicates that the end of tree has been reached (see call to * gvcst_rtsib). If there is no more tree, don't bother doing expansion. */ if (found) { status = gvcst_expand_key((blk_hdr_ptr_t)bh->buffaddr, (int4)((sm_uc_ptr_t)rp - bh->buffaddr), gv_altkey); if (cdb_sc_normal != status) { t_retry(status); continue; } key_size = gv_altkey->end + 1; GET_RSIZ(rsiz, rp); data_len = rsiz + EVAL_CMPC(rp) - SIZEOF(rec_hdr) - key_size; if (data_len < 0 || (sm_uc_ptr_t)rp + rsiz > (sm_uc_ptr_t)bp + ((blk_hdr_ptr_t)bp)->bsiz) { assert(CDB_STAGNATE > t_tries); t_retry(cdb_sc_rmisalign1); continue; } ENSURE_STP_FREE_SPACE(data_len); DEBUG_ONLY ( if (!save_strp) save_strp = stringpool.free); assert(stringpool.top - stringpool.free >= data_len); memcpy(stringpool.free, (sm_uc_ptr_t)rp + rsiz - data_len, data_len); /* Assumption: t_end/tp_hist will never cause stp_gcol() call BYPASSOK */ } if (!dollar_tlevel) { if ((trans_num)0 == t_end(&gv_target->hist, !two_histories ? NULL : rt_history, TN_NOT_SPECIFIED)) continue; } else { status = tp_hist(!two_histories ? NULL : rt_history); if (cdb_sc_normal != status) { t_retry(status); continue; } } if (found) { DEBUG_ONLY(assert(save_strp == stringpool.free)); /* Process val first. Already copied to string pool. */ val->mvtype = MV_STR; val->str.addr = (char *)stringpool.free; val->str.len = data_len; stringpool.free += data_len; INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_get, 1); } return found; } t_retry(status); } } fis-gtm-V6.0-003/sr_port/gvcst_root_search.c0000644000032200000250000002620212201176157017720 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "cdb_sc.h" #include "copy.h" #include "spec_type.h" #include "stringpool.h" #include "filestruct.h" /* needed for jnl.h */ #include "gdscc.h" /* needed for tp.h */ #include "jnl.h" /* needed for tp.h */ #include "gdskill.h" /* needed for tp.h */ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* needed for T_BEGIN_READ_NONTP_OR_TP macro */ #include "t_end.h" /* prototypes */ #include "t_retry.h" #include "t_begin.h" #include "gvcst_protos.h" /* for gvcst_search,gvcst_root_search prototype */ #include "get_spec.h" #include "collseq.h" #ifdef UNIX #include "error.h" #endif GBLREF gv_key *gv_currkey, *gv_altkey; GBLREF int4 gv_keysize; GBLREF gv_namehead *gv_target; GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF uint4 dollar_tlevel; GBLREF uint4 dollar_trestart; GBLREF unsigned int t_tries; GBLREF gv_namehead *reset_gv_target; GBLREF boolean_t mu_reorg_process; GBLREF boolean_t mupip_jnl_recover; #ifdef UNIX # ifdef DEBUG GBLREF boolean_t is_rcvr_server; GBLREF boolean_t is_src_server; GBLDEF unsigned char t_fail_hist_dbg[T_FAIL_HIST_DBG_SIZE]; GBLDEF unsigned int t_tries_dbg; # endif GBLREF jnl_gbls_t jgbl; GBLREF unsigned char t_fail_hist[CDB_MAX_TRIES]; GBLREF trans_num start_tn; GBLREF uint4 update_trans; GBLREF inctn_opcode_t inctn_opcode; GBLREF uint4 t_err; #endif #ifdef GTM_TRIGGER GBLREF boolean_t skip_INVOKE_RESTART; #endif error_def(ERR_GVGETFAIL); static mstr global_collation_mstr; #ifdef GTM_TRIGGER # define TRIG_TP_SET_SGM \ { \ if (dollar_tlevel) \ { \ assert(skip_INVOKE_RESTART); \ tp_set_sgm(); \ } \ } #else # define TRIG_TP_SET_SGM #endif #define T_RETRY_AND_CLEANUP(STATUS, DONOT_RESTART) \ { \ gv_target->clue.end = 0; \ RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, DO_GVT_GVKEY_CHECK); \ if (DONOT_RESTART) \ return status; /* caller will handle the restart */ \ t_retry(STATUS); \ save_targ->root = 0; /* May have been found by gvcst_redo_root_search. \ * Reset and allow gvcst_root_search to find it itself. \ */ \ TRIG_TP_SET_SGM; \ } #ifdef UNIX #define SAVE_ROOTSRCH_ENTRY_STATE \ { \ int idx; \ redo_root_search_context *rootsrch_ctxt_ptr; \ \ rootsrch_ctxt_ptr = &(TREF(redo_rootsrch_ctxt)); \ rootsrch_ctxt_ptr->t_tries = t_tries; \ for (idx = 0; CDB_MAX_TRIES > idx; idx++) \ rootsrch_ctxt_ptr->t_fail_hist[idx] = t_fail_hist[idx]; \ rootsrch_ctxt_ptr->prev_t_tries = TREF(prev_t_tries); \ DEBUG_ONLY( \ rootsrch_ctxt_ptr->t_tries_dbg = t_tries_dbg; \ for (idx = 0; T_FAIL_HIST_DBG_SIZE > idx; idx++) \ rootsrch_ctxt_ptr->t_fail_hist_dbg[idx] = t_fail_hist_dbg[idx]; \ ) \ rootsrch_ctxt_ptr->start_tn = start_tn; \ rootsrch_ctxt_ptr->update_trans = update_trans; \ rootsrch_ctxt_ptr->inctn_opcode = inctn_opcode; \ inctn_opcode = 0; \ rootsrch_ctxt_ptr->t_err = t_err; \ rootsrch_ctxt_ptr->hold_onto_crit = cs_addrs->hold_onto_crit; \ if (CDB_STAGNATE <= t_tries) \ { \ assert(cs_addrs->now_crit); \ cs_addrs->hold_onto_crit = TRUE; \ } \ if (mu_reorg_process) \ { /* In case gv_currkey/gv_target are out of sync. */ \ rootsrch_ctxt_ptr->gv_currkey = (gv_key *)&rootsrch_ctxt_ptr->currkey[0]; \ MEMCPY_KEY(rootsrch_ctxt_ptr->gv_currkey, gv_currkey); \ SET_GV_CURRKEY_FROM_REORG_GV_TARGET; \ } \ } #define RESTORE_ROOTSRCH_ENTRY_STATE \ { \ int idx; \ redo_root_search_context *rootsrch_ctxt_ptr; \ \ rootsrch_ctxt_ptr = &(TREF(redo_rootsrch_ctxt)); \ t_tries = rootsrch_ctxt_ptr->t_tries; \ for (idx = 0; CDB_MAX_TRIES > idx; idx++) \ t_fail_hist[idx] = rootsrch_ctxt_ptr->t_fail_hist[idx]; \ TREF(prev_t_tries) = rootsrch_ctxt_ptr->prev_t_tries; \ DEBUG_ONLY( \ t_tries_dbg = rootsrch_ctxt_ptr->t_tries_dbg; \ for (idx = 0; T_FAIL_HIST_DBG_SIZE > idx; idx++) \ t_fail_hist_dbg[idx] = rootsrch_ctxt_ptr->t_fail_hist_dbg[idx]; \ ) \ start_tn = rootsrch_ctxt_ptr->start_tn; \ update_trans = rootsrch_ctxt_ptr->update_trans; \ inctn_opcode = rootsrch_ctxt_ptr->inctn_opcode; \ t_err = rootsrch_ctxt_ptr->t_err; \ cs_addrs->hold_onto_crit = rootsrch_ctxt_ptr->hold_onto_crit; \ TREF(in_gvcst_redo_root_search) = FALSE; \ if (mu_reorg_process) \ /* Restore gv_currkey */ \ MEMCPY_KEY(gv_currkey, rootsrch_ctxt_ptr->gv_currkey); \ } CONDITION_HANDLER(gvcst_redo_root_search_ch) { START_CH; RESTORE_ROOTSRCH_ENTRY_STATE; NEXTCH; } void gvcst_redo_root_search() { DEBUG_ONLY(boolean_t dbg_now_crit;) uint4 lcl_onln_rlbkd_cycle; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; ESTABLISH(gvcst_redo_root_search_ch); assert(!TREF(in_gvcst_redo_root_search)); /* Should never recurse. However, can be called from non-redo gvcst_root_search, * e.g. from op_gvname. In that case, the results of gvcst_redo_root_search are * discarded and the outer root search correctly sets gv_target->root. */ TREF(in_gvcst_redo_root_search) = TRUE; assert(0 < t_tries); assert(!is_src_server && !is_rcvr_server); assert(!jgbl.onlnrlbk); assert((NULL != gv_target) && !gv_target->root); assert(cs_addrs == gv_target->gd_csa); assert(!dollar_tlevel); DEBUG_ONLY(dbg_now_crit = cs_addrs->now_crit); /* save global variables now that we are going to do the root search in the middle of the current transaction */ SAVE_ROOTSRCH_ENTRY_STATE; lcl_onln_rlbkd_cycle = cs_addrs->db_onln_rlbkd_cycle; GVCST_ROOT_SEARCH; if (lcl_onln_rlbkd_cycle != cs_addrs->nl->db_onln_rlbkd_cycle) TREF(rlbk_during_redo_root) = TRUE; assert(cs_addrs->now_crit == dbg_now_crit); /* ensure crit state remains same AFTER gvcst_root_search */ /* restore global variables now that we are continuing with the original transaction */ RESTORE_ROOTSRCH_ENTRY_STATE; REVERT; } #endif enum cdb_sc gvcst_root_search(boolean_t donot_restart) { srch_blk_status *h0; sm_uc_ptr_t rp; unsigned short rlen, hdr_len; uchar_ptr_t subrec_ptr; enum cdb_sc status; boolean_t gbl_target_was_set; gv_namehead *save_targ; mname_entry *gvent; int altkeylen; int tmp_cmpc; block_id lcl_root; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert((dba_bg == gv_cur_region->dyn.addr->acc_meth) || (dba_mm == gv_cur_region->dyn.addr->acc_meth)); SET_GV_ALTKEY_TO_GBLNAME_FROM_GV_CURRKEY; /* set up gv_altkey to be just the gblname */ save_targ = gv_target; /* Check if "gv_target->gvname" matches "gv_altkey->base". If not, there is a name mismatch (out-of-design situation). * This check is temporary until we catch the situation that caused D9H02-002641. * It's suspected the original situation has been fixed (see D9I08-002695). But the assertpro will remain until * gvcst_redo_root_search has been well-tested. */ /* --- Check BEGIN --- */ gvent = &save_targ->gvname; altkeylen = gv_altkey->end - 1; assertpro(altkeylen && (altkeylen == gvent->var_name.len) && (0 == memcmp(gv_altkey->base, gvent->var_name.addr, gvent->var_name.len))); /* --- Check END --- */ if (INVALID_GV_TARGET != reset_gv_target) gbl_target_was_set = TRUE; else { gbl_target_was_set = FALSE; reset_gv_target = save_targ; } gv_target = cs_addrs->dir_tree; T_BEGIN_READ_NONTP_OR_TP(ERR_GVGETFAIL); /* We better hold crit in the final retry (TP & non-TP). Only exception is journal recovery */ assert((t_tries < CDB_STAGNATE) || cs_addrs->now_crit || mupip_jnl_recover); for (;;) { lcl_root = 0; /* set lcl_root to 0 at the start of every iteration (this way even retry will get fresh value) */ hdr_len = rlen = 0; gv_target = cs_addrs->dir_tree; if (dollar_trestart) gv_target->clue.end = 0; assert(0 == save_targ->root); if (cdb_sc_normal == (status = gvcst_search(gv_altkey, 0))) { if (gv_altkey->end + 1 == gv_target->hist.h[0].curr_rec.match) { h0 = gv_target->hist.h; rp = (h0->buffaddr + h0->curr_rec.offset); hdr_len = SIZEOF(rec_hdr) + gv_altkey->end + 1 - EVAL_CMPC((rec_hdr_ptr_t)rp); GET_USHORT(rlen, rp); if (FALSE == (CHKRECLEN(rp, h0->buffaddr, rlen)) || (rlen < hdr_len + SIZEOF(block_id))) { T_RETRY_AND_CLEANUP(cdb_sc_rmisalign, donot_restart); continue; } GET_LONG(lcl_root, (rp + hdr_len)); if (rlen > hdr_len + SIZEOF(block_id)) { assert(NULL != global_collation_mstr.addr || 0 == global_collation_mstr.len); if (global_collation_mstr.len < rlen - (hdr_len + SIZEOF(block_id))) { if (NULL != global_collation_mstr.addr) free(global_collation_mstr.addr); global_collation_mstr.len = rlen - (hdr_len + SIZEOF(block_id)); global_collation_mstr.addr = (char *)malloc(global_collation_mstr.len); } /* the memcpy needs to be done here instead of out of for loop for * concurrency consideration. We don't use s2pool because the pointer rp is 64 bits */ memcpy(global_collation_mstr.addr, rp + hdr_len + SIZEOF(block_id), rlen - (hdr_len + SIZEOF(block_id))); } if (dollar_tlevel) { status = tp_hist(NULL); if (cdb_sc_normal != status) { T_RETRY_AND_CLEANUP(status, donot_restart); continue; } break; } } if (!dollar_tlevel) { if ((trans_num)0 != t_end(&gv_target->hist, NULL, TN_NOT_SPECIFIED)) break; } else { status = tp_hist(NULL); if (cdb_sc_normal == status) break; T_RETRY_AND_CLEANUP(status, donot_restart); continue; } } else { T_RETRY_AND_CLEANUP(status, donot_restart); continue; } } save_targ->root = lcl_root; /* now that we know the transaction validated fine, set root block in gv_target */ RESET_GV_TARGET_LCL_AND_CLR_GBL(save_targ, DO_GVT_GVKEY_CHECK); if (rlen > hdr_len + SIZEOF(block_id)) { assert(NULL != global_collation_mstr.addr); subrec_ptr = get_spec((uchar_ptr_t)global_collation_mstr.addr, (int)(rlen - (hdr_len + SIZEOF(block_id))), COLL_SPEC); if (subrec_ptr) { gv_target->nct = *(subrec_ptr + COLL_NCT_OFFSET); gv_target->act = *(subrec_ptr + COLL_ACT_OFFSET); gv_target->ver = *(subrec_ptr + COLL_VER_OFFSET); } else { gv_target->nct = 0; gv_target->act = 0; gv_target->ver = 0; } } else { gv_target->nct = 0; gv_target->act = cs_addrs->hdr->def_coll; gv_target->ver = cs_addrs->hdr->def_coll_ver; } if (gv_target->act) act_in_gvt(); assert(gv_target->act || NULL == gv_target->collseq); return cdb_sc_normal; } fis-gtm-V6.0-003/sr_port/gvcst_rtsib.c0000644000032200000250000001004112201176157016525 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "cdb_sc.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "copy.h" /* Include prototypes */ #include "t_qread.h" #include "gvcst_protos.h" /* for gvcst_search_blk,gvcst_rtsib prototype */ /* construct a new array which is the path to the right sibling of the leaf of the old array note: the offset's will be correct, but NOT the 'match' members */ /* WARNING: assumes that the search history for the current target is in gv_target.hist */ GBLREF sgmnt_addrs *cs_addrs; GBLREF gv_namehead *gv_target; GBLREF gv_key *gv_currkey; GBLREF unsigned char rdfail_detail; GBLREF unsigned int t_tries; GBLREF srch_blk_status *first_tp_srch_status; /* overriding value of srch_blk_status given by t_qread in case of TP */ enum cdb_sc gvcst_rtsib(srch_hist *full_hist, int level) { srch_blk_status *old, *new, *old_base, *new_base; rec_hdr_ptr_t rp; enum cdb_sc ret_val; block_id blk; unsigned short rec_size, temp_short; sm_uc_ptr_t buffer_address; int4 cycle; new_base = &full_hist->h[level]; old = old_base = &gv_target->hist.h[level]; for (;;) { old++; if (0 == old->blk_num) return cdb_sc_endtree; if (old->cr && (old->blk_num != old->cr->blk)) { assert(CDB_STAGNATE > t_tries); return cdb_sc_lostcr; } if (cdb_sc_normal != (ret_val = gvcst_search_blk(gv_currkey, old))) return ret_val; buffer_address = old->buffaddr; temp_short = old->curr_rec.offset; rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)buffer_address + temp_short); GET_USHORT(rec_size, &rp->rsiz); if ((sm_uc_ptr_t)rp + rec_size > buffer_address + (unsigned int)((blk_hdr_ptr_t)buffer_address)->bsiz) { assert(CDB_STAGNATE > t_tries); return cdb_sc_rmisalign; } if ((unsigned int)((blk_hdr_ptr_t)buffer_address)->bsiz > (temp_short + rec_size)) break; } /* old now points to the first block which did not have a star key pointer*/ new = new_base + (old - old_base + 1); full_hist->depth = (int)(level + old - old_base); (new--)->blk_num = 0; new->tn = old->tn; new->cse = NULL; new->first_tp_srch_status = old->first_tp_srch_status; assert(new->level == old->level); assert(new->blk_target == old->blk_target); new->blk_num = old->blk_num; new->buffaddr = old->buffaddr; new->prev_rec = old->curr_rec; new->cycle = old->cycle; new->cr = old->cr; temp_short = new->prev_rec.offset; rp = (rec_hdr_ptr_t)(temp_short + new->buffaddr); GET_USHORT(rec_size, &rp->rsiz); temp_short += rec_size; new->curr_rec.offset = temp_short; new->curr_rec.match = 0; if (((blk_hdr_ptr_t)old->buffaddr)->bsiz < temp_short) { assert(CDB_STAGNATE > t_tries); return cdb_sc_rmisalign; } rp = (rec_hdr_ptr_t)(old->buffaddr + temp_short); while (--new >= new_base) { --old; GET_USHORT(rec_size, &rp->rsiz); if ((sm_uc_ptr_t)rp + rec_size > buffer_address + (unsigned int)((blk_hdr_ptr_t)buffer_address)->bsiz) { assert(CDB_STAGNATE > t_tries); return cdb_sc_rmisalign; } GET_LONG(blk, ((sm_int_ptr_t)((sm_uc_ptr_t)rp + rec_size - SIZEOF(block_id)))); new->tn = cs_addrs->ti->curr_tn; new->cse = NULL; if (NULL == (buffer_address = t_qread(blk, &new->cycle, &new->cr))) return((enum cdb_sc)rdfail_detail); new->first_tp_srch_status = first_tp_srch_status; assert(new->level == old->level); assert(new->blk_target == old->blk_target); new->blk_num = blk; new->buffaddr = buffer_address; new->prev_rec.match = 0; new->prev_rec.offset = 0; new->curr_rec.match = 0; new->curr_rec.offset = SIZEOF(blk_hdr); rp = (rec_hdr_ptr_t)(buffer_address + SIZEOF(blk_hdr)); } return cdb_sc_normal; } fis-gtm-V6.0-003/sr_port/gvcst_search.c0000644000032200000250000005040012201176157016652 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "cdb_sc.h" #include "gdsroot.h" #include "gdskill.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "gdscc.h" #include "copy.h" #include "filestruct.h" #include "jnl.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h and cws_insert.h */ #include "tp.h" #include "gvcst_blk_build.h" #include "t_qread.h" #include "longset.h" /* needed for cws_insert.h */ #include "hashtab.h" /* needed for cws_insert.h */ #include "cws_insert.h" #include "gvcst_protos.h" /* for gvcst_search_blk,gvcst_search_tail,gvcst_search prototype */ #include "min_max.h" GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF gv_namehead *gv_target; GBLREF uint4 dollar_tlevel; GBLREF sgmnt_data_ptr_t cs_data; GBLREF unsigned char rdfail_detail; GBLREF sgm_info *sgm_info_ptr; GBLREF unsigned int t_tries; GBLREF srch_blk_status *first_tp_srch_status; /* overriding value of srch_blk_status given by t_qread in case of TP */ GBLREF trans_num local_tn; /* transaction number for THIS PROCESS */ GBLREF boolean_t tp_restart_syslog; /* for the TP_TRACE_HIST_MOD macro */ GBLREF boolean_t mu_reorg_process; GBLREF char gvcst_search_clue; #define SET_GVCST_SEARCH_CLUE(X) gvcst_search_clue = X; enum cdb_sc gvcst_search(gv_key *pKey, /* Key to search for */ srch_hist *pHist) /* History to fill in*/ { unsigned char nLevl; enum cdb_sc status; register int n1; register uchar_ptr_t c1, c2; register sm_uc_ptr_t pRec, pBlkBase; register gv_namehead *pTarg; /* Local copy of gv_target; hope it gets put into register */ register srch_blk_status *pCurr; register srch_blk_status *pNonStar; register srch_hist *pTargHist; int tmp_cmpc; block_id nBlkId; cache_rec_ptr_t cr; int cycle; unsigned short n0, nKeyLen; trans_num tn; cw_set_element *cse; off_chain chain1, chain2; srch_blk_status *tp_srch_status, *srch_status, *leaf_blk_hist; boolean_t already_built, is_mm; ht_ent_int4 *tabent; sm_uc_ptr_t buffaddr; trans_num blkhdrtn, oldest_hist_tn; int hist_size; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; pTarg = gv_target; assert(NULL != pTarg); assert(pTarg->root); assert(pKey != &pTarg->clue); nKeyLen = pKey->end + 1; assert(!dollar_tlevel || ((NULL != sgm_info_ptr) && (cs_addrs->sgm_info_ptr == sgm_info_ptr))); SET_GVCST_SEARCH_CLUE(0); INCR_DB_CSH_COUNTER(cs_addrs, n_gvcst_srches, 1); pTargHist = (NULL == pHist ? &pTarg->hist : pHist); /* If FINAL RETRY and TP then we can safely use clues of gv_targets that have been referenced in this * TP transaction (read_local_tn == local_tn). While that is guaranteed to be true for all updates, it * does not hold good for READs since we allow a lot more reads to be done inside a transaction compared * to the # of updates allowed. We allow the same global to be read multiple times inside the same transaction * using different global buffers for each read. This means that we need to validate any clues from the first * read before using it for the second read even if it is in the final retry. This validation is done inside * the below IF block. As for gv_targets which are referenced for the very first time in this TP transaction, * we have no easy way of determining if their clues are still uptodate (i.e. using the clue will guarantee us * no restart) and since we are in the final retry, we dont want to take a risk. So dont use the clue in that case. * * If FINAL RETRY and Non-TP, we will be dealing with only ONE gv_target so its clue would have been reset as * part of the penultimate restart so we dont have any of the above issue in the non-tp case. The only exception * is if we are in gvcst_kill in which case, gvcst_search will be called twice and the clue could be non-zero * for the second invocation. In this case, the clue is guaranteed to be uptodate since it was set just now * as part of the first invocation. So no need to do anything about clue in final retry for Non-TP. */ if ((0 != pTarg->clue.end) && ((CDB_STAGNATE > t_tries) || !dollar_tlevel || (pTarg->read_local_tn == local_tn))) { /* Have non-zero clue. Check if it is usable for the current search key. If so validate clue then and use it. */ /* In t_end, we skipped validating the clue in case of reorg due to the assumption that reorg never uses the clue * i.e. it nullifies the clue before calling gvcst_search. However, it doesn't reset the clue for directory tree * and so continue using the clue if called for root search. Assert accordingly. */ assert(!mu_reorg_process UNIX_ONLY(|| (pTarg->gd_csa->dir_tree == pTarg))); INCR_DB_CSH_COUNTER(cs_addrs, n_gvcst_srch_clues, 1); status = cdb_sc_normal; /* clue is usable unless proved otherwise */ if (NULL != pHist) { /* Copy the full srch_hist and set loop terminator flag in unused srch_blk_status entry. * If in TP and if leaf block in history has cse, we are guaranteed that it is built by the * immediately previous call to "gvcst_search" (called by gvcst_kill which does two calls to * gvcst_search of which this invocation is the second) so no need to build the block like * is done for the (NULL == pHist) case below. Assert that and some more. */ hist_size = HIST_SIZE(pTarg->hist); memcpy(pHist, &pTarg->hist, hist_size); ((srch_blk_status *)((char *)pHist + hist_size))->blk_num = 0; # ifdef DEBUG if (dollar_tlevel) { leaf_blk_hist = &pHist->h[0]; assert(0 == leaf_blk_hist->level); chain1 = *(off_chain *)&leaf_blk_hist->blk_num; if (chain1.flag == 1) { assert((int)chain1.cw_index < sgm_info_ptr->cw_set_depth); tp_get_cw(sgm_info_ptr->first_cw_set, (int)chain1.cw_index, &cse); } else { tp_srch_status = leaf_blk_hist->first_tp_srch_status; ASSERT_IS_WITHIN_TP_HIST_ARRAY_BOUNDS(tp_srch_status, sgm_info_ptr); cse = (NULL != tp_srch_status) ? tp_srch_status->cse : NULL; } assert((NULL == cse) || cse->done); } # endif } else if (dollar_tlevel) { /* First nullify first_tp_srch_status member in gv_target history if out-of-date. This is logically done * at tp_clean_up time but delayed until the time this gv_target is used next in a transaction. This way * it saves some CPU cycles. pTarg->read_local_tn tells us whether this is the first usage of this * gv_target in this TP transaction and if so we need to reset the out-of-date field. */ if (pTarg->read_local_tn != local_tn) GVT_CLEAR_FIRST_TP_SRCH_STATUS(pTarg); /* TP & going to use clue. check if clue path contains a leaf block with a corresponding unbuilt * cse from the previous traversal. If so build it first before gvcst_search_blk/gvcst_search_tail. */ tp_srch_status = NULL; leaf_blk_hist = &pTarg->hist.h[0]; assert(leaf_blk_hist->blk_target == pTarg); assert(0 == leaf_blk_hist->level); chain1 = *(off_chain *)&leaf_blk_hist->blk_num; if (chain1.flag == 1) { if ((int)chain1.cw_index >= sgm_info_ptr->cw_set_depth) { assert(sgm_info_ptr->tp_csa == cs_addrs); assert(FALSE == cs_addrs->now_crit); return cdb_sc_blknumerr; } tp_get_cw(sgm_info_ptr->first_cw_set, (int)chain1.cw_index, &cse); } else { nBlkId = (block_id)leaf_blk_hist->blk_num; tp_srch_status = leaf_blk_hist->first_tp_srch_status; if ((NULL == tp_srch_status) && (NULL != (tabent = lookup_hashtab_int4(sgm_info_ptr->blks_in_use, (uint4 *)&leaf_blk_hist->blk_num)))) tp_srch_status = tabent->value; ASSERT_IS_WITHIN_TP_HIST_ARRAY_BOUNDS(tp_srch_status, sgm_info_ptr); cse = (NULL != tp_srch_status) ? tp_srch_status->cse : NULL; } assert(!cse || !cse->high_tlevel); if ((NULL == tp_srch_status) || (tp_srch_status->blk_target == pTarg)) { /* Either the leaf level block in clue is not already present in the current TP transaction's * hashtable OR it is already present and the corresponding globals match. If they dont match * we know for sure the clue is out-of-date (i.e. using it will lead to a transaction restart) * and hence needs to be discarded. */ leaf_blk_hist->first_tp_srch_status = tp_srch_status; if (NULL != cse) { if (!cse->done) { /* there's a private copy and it's not up to date */ already_built = (NULL != cse->new_buff); gvcst_blk_build(cse, cse->new_buff, 0); /* Validate the block's search history right after building a private copy. * This is not needed in case gvcst_search is going to reuse the clue's search * history and return (because tp_hist will do the validation of this block). * But if gvcst_search decides to do a fresh traversal (because the clue does not * cover the path of the current input key etc.) the block build that happened now * will not get validated in tp_hist since it will instead be given the current * key's search history path (a totally new path) for validation. Since a private * copy of the block has been built, tp_tend would also skip validating this block * so it is necessary that we validate the block right here. Since it is tricky to * accurately differentiate between the two cases, we do the validation * unconditionally here (besides it is only a few if checks done per block build * so it is considered okay performance-wise). */ if (!already_built && !chain1.flag) { /* is_mm is calculated twice, but this is done so as to speed up the * most-frequent path, i.e. when there is a clue and either no cse or * cse->done is TRUE */ is_mm = (dba_mm == cs_data->acc_meth); buffaddr = tp_srch_status->buffaddr; cr = tp_srch_status->cr; assert(tp_srch_status && (is_mm || cr) && buffaddr); blkhdrtn = ((blk_hdr_ptr_t)buffaddr)->tn; if (TP_IS_CDB_SC_BLKMOD3(cr, tp_srch_status, blkhdrtn)) { assert(CDB_STAGNATE > t_tries); TP_TRACE_HIST_MOD(leaf_blk_hist->blk_num, gv_target, tp_blkmod_gvcst_srch, cs_data, tp_srch_status->tn, blkhdrtn, ((blk_hdr_ptr_t)buffaddr)->levl); return cdb_sc_blkmod; } if (!is_mm && ((tp_srch_status->cycle != cr->cycle) || (tp_srch_status->blk_num != cr->blk))) { assert(CDB_STAGNATE > t_tries); return cdb_sc_lostcr; } } cse->done = TRUE; leaf_blk_hist->cr = 0; leaf_blk_hist->cycle = CYCLE_PVT_COPY; leaf_blk_hist->buffaddr = cse->new_buff; } else { /* Keep leaf_blk_hist->buffaddr and cse->new_buff in sync. If a TP transaction * updates two different globals and the second update invoked t_qread for a leaf * block corresponding to the first global and ended up constructing a private block * then leaf_blk_hist->buffaddr of the first global will be out-of-sync with the * cse->new_buff. However, the transaction validation done in tp_hist/tp_tend * should detect this and restart. Set donot_commit to verify that a restart happens */ # ifdef DEBUG if (leaf_blk_hist->buffaddr != cse->new_buff) TREF(donot_commit) |= DONOTCOMMIT_GVCST_SEARCH_LEAF_BUFFADR_NOTSYNC; # endif leaf_blk_hist->buffaddr = cse->new_buff; /* sync the buffers in pro, just in case */ } } } else { /* Two different gv_targets point to same block; discard out-of-date clue. */ # ifdef DEBUG if ((pTarg->read_local_tn >= local_tn) && (NULL != leaf_blk_hist->first_tp_srch_status)) { /* Since the clue was used in *this* transaction, it cannot successfully complete. Set * donot_commit to verify that a restart happens (either in tp_hist or tp_tend) */ assert(pTarg->read_local_tn == local_tn); TREF(donot_commit) |= DONOTCOMMIT_GVCST_SEARCH_BLKTARGET_MISMATCH; } # endif status = cdb_sc_lostcr; } } /* Validate EVERY level in the clue before using it for ALL retries. This way we avoid unnecessary restarts. * This is NECESSARY for the final retry (e.g. in a TP transaction that does LOTS of reads of different globals, * it is possible that one global's clue is invalidated by a later read of another global) and is DESIRABLE (for * performance reasons) in the other tries. The cost of a restart (particularly in TP) is very high that it is * considered okay to take the hit of validating the entire clue before using it even if it is not the final retry. */ if (cdb_sc_normal == status) { is_mm = (dba_mm == cs_data->acc_meth); if (!is_mm) oldest_hist_tn = OLDEST_HIST_TN(cs_addrs); for (srch_status = &pTargHist->h[0]; HIST_TERMINATOR != srch_status->blk_num; srch_status++) { assert(srch_status->level == srch_status - &pTargHist->h[0]); assert(is_mm || (NULL == srch_status->cr) || (NULL != srch_status->buffaddr)); cr = srch_status->cr; assert(!is_mm || (NULL == cr)); if (TP_IS_CDB_SC_BLKMOD(cr, srch_status)) { status = cdb_sc_blkmod; break; } if (NULL != cr) { assert(NULL != srch_status->buffaddr); if (srch_status->cycle != cr->cycle) { status = cdb_sc_lostcr; break; } if ((CDB_STAGNATE <= t_tries) || mu_reorg_process) { CWS_INSERT(cr->blk); if ((CDB_STAGNATE <= t_tries) && (srch_status->tn <= oldest_hist_tn)) { /* The tn at which the history was last validated is before the earliest * transaction in the BT. The clue can no longer be relied upon. */ status = cdb_sc_losthist; break; } } cr->refer = TRUE; } } } if (cdb_sc_normal == status) { /* Now that we are ready to use the clue, put more-likely case earlier in the if then else sequence. * For sequential reads of globals, we expect the tail of the clue to be much more used than the head. * For random reads, both are equally probable and hence it doesn't matter. * The case (0 == n1) is not expected a lot (relatively) since the application may be able to optimize * a number of reads of the same key into one read by using a local-variable to store the value. */ if (0 < (n1 = memcmp(pKey->base, pTarg->clue.base, nKeyLen))) { if (memcmp(pKey->base, pTarg->last_rec->base, nKeyLen) <= 0) { SET_GVCST_SEARCH_CLUE(1); status = gvcst_search_tail(pKey, pTargHist->h, &pTarg->clue); if (NULL == pHist) { /* Implies the search history is being filled in pTarg->hist so we can * safely update pTarg->clue to reflect the new search key. It is important * that this clue update be done AFTER the gvcst_search_tail invocation * (as that needs to pass the previous clue key). */ COPY_CURRKEY_TO_GVTARGET_CLUE(pTarg, pKey); } INCR_DB_CSH_COUNTER(cs_addrs, n_clue_used_tail, 1); return status; } } else if (0 > n1) { if (memcmp(pKey->base, pTarg->first_rec->base, nKeyLen) >= 0) { SET_GVCST_SEARCH_CLUE(3); status = gvcst_search_blk(pKey, pTargHist->h); if (NULL == pHist) { /* Implies the search history is being filled in pTarg->hist so we can * safely update pTarg->clue to reflect the new search key. It does not * matter if we update the clue BEFORE or AFTER the gvcst_search_blk * invocation but for consistency with the gvcst_search_tail invocation * we keep it AFTER. */ COPY_CURRKEY_TO_GVTARGET_CLUE(pTarg, pKey); } INCR_DB_CSH_COUNTER(cs_addrs, n_clue_used_head, 1); return status; } } else { SET_GVCST_SEARCH_CLUE(2); INCR_DB_CSH_COUNTER(cs_addrs, n_clue_used_same, 1); return cdb_sc_normal; } } } nBlkId = pTarg->root; tn = cs_addrs->ti->curr_tn; if (NULL == (pBlkBase = t_qread(nBlkId, (sm_int_ptr_t)&cycle, &cr))) return (enum cdb_sc)rdfail_detail; nLevl = ((blk_hdr_ptr_t)pBlkBase)->levl; if (MAX_BT_DEPTH < (int)nLevl) { assert(CDB_STAGNATE > t_tries); return cdb_sc_maxlvl; } if (0 == (int)nLevl) { assert(CDB_STAGNATE > t_tries); return cdb_sc_badlvl; } is_mm = (dba_mm == cs_data->acc_meth); pTargHist->depth = (int)nLevl; pCurr = &pTargHist->h[nLevl]; (pCurr + 1)->blk_num = 0; pCurr->tn = tn; pCurr->first_tp_srch_status = first_tp_srch_status; pCurr->cycle = cycle; pCurr->cr = cr; pNonStar = NULL; for (;;) { assert(pCurr->level == nLevl); pCurr->cse = NULL; pCurr->blk_num = nBlkId; pCurr->buffaddr = pBlkBase; if (cdb_sc_normal != (status = gvcst_search_blk(pKey, pCurr))) return status; if (0 == nLevl) break; if ((n0 = pCurr->curr_rec.offset) >= ((blk_hdr_ptr_t)pBlkBase)->bsiz) n0 = pCurr->prev_rec.offset; pRec = pBlkBase + n0; GET_USHORT(n0, &((rec_hdr_ptr_t)pRec)->rsiz); if (FALSE == CHKRECLEN(pRec, pBlkBase, n0)) { assert(CDB_STAGNATE > t_tries); return cdb_sc_rmisalign; } GET_LONG(nBlkId, (pRec + n0 - SIZEOF(block_id))); if (is_mm) { PUT_LONG(&chain2, nBlkId); if ((0 == chain2.flag) && (nBlkId > cs_addrs->total_blks)) { /* private copy should be taken care of by .flag */ if (cs_addrs->total_blks < cs_addrs->ti->total_blks) return cdb_sc_helpedout; else return cdb_sc_blknumerr; } } if (BSTAR_REC_SIZE != n0) pNonStar = pCurr; pCurr--; pCurr->tn = cs_addrs->ti->curr_tn; if (NULL == (pBlkBase = t_qread(nBlkId, (sm_int_ptr_t)&pCurr->cycle, &pCurr->cr))) return (enum cdb_sc)rdfail_detail; pCurr->first_tp_srch_status = first_tp_srch_status; if (((blk_hdr_ptr_t)pBlkBase)->levl != --nLevl) { assert(CDB_STAGNATE > t_tries); return cdb_sc_badlvl; } } if (NULL == pHist) { if ((pCurr->curr_rec.offset < SIZEOF(blk_hdr)) || ((pCurr->curr_rec.offset == SIZEOF(blk_hdr)) && (pCurr->curr_rec.match < nKeyLen))) { /* Clue less than first rec, invalidate */ pTarg->clue.end = 0; return cdb_sc_normal; } pRec = pBlkBase + SIZEOF(blk_hdr); GET_USHORT(n0, &((rec_hdr_ptr_t)pRec)->rsiz); if (FALSE == CHKRECLEN(pRec, pBlkBase, n0)) { assert(CDB_STAGNATE > t_tries); return cdb_sc_rmisalign; } c1 = pRec + SIZEOF(rec_hdr); c2 = pTarg->first_rec->base; if (n0 > (pTarg->first_rec->top)) { n0 = pTarg->first_rec->top; status = cdb_sc_keyoflow; } else status = cdb_sc_rmisalign; if (0 != n0) { do { --n0; if ((0 == (*c2++ = *c1++)) && (0 == *c1)) break; } while (n0); } if (0 == n0) { assert(CDB_STAGNATE > t_tries); return status; } assert(c2 < &pTarg->first_rec->base[pTarg->first_rec->top]); /* make sure we don't exceed allocated bounds */ *c2 = *c1; DEBUG_ONLY(pTarg->first_rec->end = c2 - pTarg->first_rec->base;) if (NULL == pNonStar) { *((short *)pTarg->last_rec->base) = GVT_CLUE_LAST_REC_MAXKEY; DEBUG_ONLY(pTarg->last_rec->end = SIZEOF(short);) } else { pRec = pNonStar->buffaddr + pNonStar->curr_rec.offset; GET_USHORT(n0, &((rec_hdr_ptr_t)pRec)->rsiz); c1 = pNonStar->buffaddr; if (FALSE == CHKRECLEN(pRec, c1, n0)) { assert(CDB_STAGNATE > t_tries); return cdb_sc_rmisalign; } EVAL_CMPC2((rec_hdr_ptr_t)pRec, n1); if (pNonStar->curr_rec.match < n1) { assert(CDB_STAGNATE > t_tries); return cdb_sc_rmisalign; } if (n1 > (int)(pTarg->last_rec->top)) { assert(CDB_STAGNATE > t_tries); return cdb_sc_keyoflow; } c2 = pTarg->last_rec->base; if (0 != n1) memcpy(c2, pKey->base, n1); c2 = (sm_uc_ptr_t)c2 + n1; c1 = pRec + SIZEOF(rec_hdr); if ((int)n0 > (int)(pTarg->last_rec->top) - n1) { n0 = pTarg->last_rec->top - n1; status = cdb_sc_keyoflow; } else status = cdb_sc_rmisalign; if (0 != n0) { do { --n0; if ((0 == (*c2++ = *c1++)) && (0 == *c1)) break; } while (n0); } if (0 == n0) { assert(CDB_STAGNATE > t_tries); return status; } assert(c2 < &pTarg->last_rec->base[pTarg->last_rec->top]); /* make sure we don't exceed allocated bounds */ *c2 = *c1; DEBUG_ONLY(pTarg->last_rec->end = c2 - pTarg->last_rec->base;) } COPY_CURRKEY_TO_GVTARGET_CLUE(pTarg, pKey); } return cdb_sc_normal; } fis-gtm-V6.0-003/sr_port/gvcst_tp_init.c0000644000032200000250000001073012201176157017055 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gdscc.h" #include "gdskill.h" #include "jnl.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "hashtab.h" #include "tp.h" #include "tp_timeout.h" #include "gvcst_protos.h" /* for gvcst_tp_init prototype */ /* Initialize the TP structures we will be using for the successive TP operations */ void gvcst_tp_init(gd_region *greg) { sgm_info *si; sgmnt_addrs *csa; csa = (sgmnt_addrs *)&FILE_INFO(greg)->s_addrs; if (NULL == csa->sgm_info_ptr) { si = csa->sgm_info_ptr = (sgm_info *)malloc(SIZEOF(sgm_info)); assert(32768 > SIZEOF(sgm_info)); memset(si, 0, SIZEOF(sgm_info)); si->tp_hist_size = TP_MAX_MM_TRANSIZE; si->cur_tp_hist_size = INIT_CUR_TP_HIST_SIZE; /* should be very much less than si->tp_hist_size */ assert(si->cur_tp_hist_size <= si->tp_hist_size); si->blks_in_use = (hash_table_int4 *)malloc(SIZEOF(hash_table_int4)); init_hashtab_int4(si->blks_in_use, BLKS_IN_USE_INIT_ELEMS, HASHTAB_COMPACT, HASHTAB_SPARE_TABLE); /* See comment in tp.h about cur_tp_hist_size for details */ si->first_tp_hist = si->last_tp_hist = (srch_blk_status *)malloc(SIZEOF(srch_blk_status) * si->cur_tp_hist_size); si->cw_set_list = (buddy_list *)malloc(SIZEOF(buddy_list)); initialize_list(si->cw_set_list, SIZEOF(cw_set_element), CW_SET_LIST_INIT_ALLOC); si->tlvl_cw_set_list = (buddy_list *)malloc(SIZEOF(buddy_list)); initialize_list(si->tlvl_cw_set_list, SIZEOF(cw_set_element), TLVL_CW_SET_LIST_INIT_ALLOC); si->tlvl_info_list = (buddy_list *)malloc(SIZEOF(buddy_list)); initialize_list(si->tlvl_info_list, SIZEOF(tlevel_info), TLVL_INFO_LIST_INIT_ALLOC); si->new_buff_list = (buddy_list *)malloc(SIZEOF(buddy_list)); initialize_list(si->new_buff_list, SIZEOF(que_ent) + csa->hdr->blk_size, NEW_BUFF_LIST_INIT_ALLOC); si->recompute_list = (buddy_list *)malloc(SIZEOF(buddy_list)); initialize_list(si->recompute_list, SIZEOF(key_cum_value), RECOMPUTE_LIST_INIT_ALLOC); /* The size of the si->cr_array can go up to TP_MAX_MM_TRANSIZE, but usually is quite less. * Therefore, initially allocate a small array and expand as needed later. */ if (dba_bg == greg->dyn.addr->acc_meth) { si->cr_array_size = si->cur_tp_hist_size; si->cr_array = (cache_rec_ptr_ptr_t)malloc(SIZEOF(cache_rec_ptr_t) * si->cr_array_size); } else { si->cr_array_size = 0; si->cr_array = NULL; } si->tp_set_sgm_done = FALSE; } else si = csa->sgm_info_ptr; si->gv_cur_region = greg; si->tp_csa = csa; si->tp_csd = csa->hdr; si->start_tn = csa->ti->curr_tn; if (JNL_ALLOWED(csa)) { si->total_jnl_rec_size = csa->min_total_tpjnl_rec_size; /* Reinitialize total_jnl_rec_size */ /* Since the following jnl-mallocs are independent of any dynamically-changeable parameter of the * database, we can as well use the existing malloced jnl structures if at all they exist. */ if (NULL == si->jnl_tail) { si->jnl_tail = &si->jnl_head; si->jnl_list = (buddy_list *)malloc(SIZEOF(buddy_list)); initialize_list(si->jnl_list, SIZEOF(jnl_format_buffer), JNL_LIST_INIT_ALLOC); si->format_buff_list = (buddy_list *)malloc(SIZEOF(buddy_list)); /* Minimum value of elemSize is 8 due to alignment requirements of the returned memory location. * Therefore, we request an elemSize of 8 bytes for the format-buffer and will convert as much * bytes as we need into as many 8-byte multiple segments (see code in jnl_format). */ initialize_list(si->format_buff_list, JFB_ELE_SIZE, DIVIDE_ROUND_UP(JNL_FORMAT_BUFF_INIT_ALLOC, JFB_ELE_SIZE)); } } else if (NULL != si->jnl_tail) { /* journaling is currently disallowed although it was allowed (non-zero si->jnl_tail) * during the prior use of this region. Free up unnecessary region-specific structures now. */ FREEUP_BUDDY_LIST(si->jnl_list); FREEUP_BUDDY_LIST(si->format_buff_list); si->jnl_tail = NULL; } } fis-gtm-V6.0-003/sr_port/gvcst_zprevious.c0000644000032200000250000001523012201176157017455 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "cdb_sc.h" #include "filestruct.h" /* needed for jnl.h */ #include "gdscc.h" /* needed for tp.h */ #include "jnl.h" /* needed for tp.h */ #include "gdskill.h" /* needed for tp.h */ #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" /* needed for T_BEGIN_READ_NONTP_OR_TP macro */ #ifdef UNIX /* needed for frame_pointer in GVCST_ROOT_SEARCH_AND_PREP macro */ # include "repl_msg.h" # include "gtmsource.h" # include "rtnhdr.h" # include "stack_frame.h" #endif #include "t_end.h" /* prototypes */ #include "t_retry.h" #include "t_begin.h" #include "gvcst_expand_key.h" #include "gvcst_protos.h" /* for gvcst_lftsib,gvcst_search,gvcst_search_blk,gvcst_zprevious prototype */ /* needed for spanning nodes */ #include "op.h" #include "op_tcommit.h" #include "error.h" #include "tp_frame.h" #include "tp_restart.h" #include "gtmimagename.h" LITREF mval literal_batch; GBLREF sgmnt_data_ptr_t cs_data; GBLREF sgmnt_addrs *cs_addrs; GBLREF gd_region *gv_cur_region; GBLREF gv_namehead *gv_target; GBLREF gv_key *gv_currkey, *gv_altkey; GBLREF int4 gv_keysize; GBLREF uint4 dollar_tlevel; GBLREF unsigned int t_tries; error_def(ERR_DBROLLEDBACK); error_def(ERR_GVORDERFAIL); error_def(ERR_TPRETRY); DEFINE_NSB_CONDITION_HANDLER(gvcst_zprevious_ch) bool gvcst_zprevious(void) { /* See gvcst_query.c */ bool found, is_hidden, sn_tpwrapped; boolean_t est_first_pass; char save_currkey[SIZEOF(gv_key) + DBKEYSIZE(MAX_KEY_SZ)]; gv_key *save_gv_currkey; int end, prev, oldend; int save_dollar_tlevel; DEBUG_ONLY(save_dollar_tlevel = dollar_tlevel); found = gvcst_zprevious2(); # ifdef UNIX assert(save_dollar_tlevel == dollar_tlevel); CHECK_HIDDEN_SUBSCRIPT_AND_RETURN(found, gv_altkey, is_hidden); assert(found && is_hidden); IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(return found); SAVE_GV_CURRKEY_LAST_SUBSCRIPT(gv_currkey, prev, oldend); if (!dollar_tlevel) { sn_tpwrapped = TRUE; op_tstart((IMPLICIT_TSTART), TRUE, &literal_batch, 0); ESTABLISH_NORET(gvcst_zprevious_ch, est_first_pass); GVCST_ROOT_SEARCH_AND_PREP(est_first_pass); } else sn_tpwrapped = FALSE; INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_zprev, (gtm_uint64_t) -1); found = gvcst_zprevious2(); if (found) { CHECK_HIDDEN_SUBSCRIPT(gv_altkey, is_hidden); if (is_hidden) { /* Replace last subscript to be the lowest possible hidden subscript so another * gvcst_zprevious2 will give us the previous non-hidden subscript. */ end = gv_altkey->end; gv_currkey->base[end - 4] = 2; gv_currkey->base[end - 3] = 1; gv_currkey->base[end - 2] = 1; gv_currkey->base[end - 1] = 0; gv_currkey->base[end + 0] = 0; gv_currkey->end = end; /* fix up since it should only be externally counted as one $zprevious */ INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_zprev, (gtm_uint64_t) -1); found = gvcst_zprevious2(); } } if (sn_tpwrapped) { op_tcommit(); REVERT; /* remove our condition handler */ } RESTORE_GV_CURRKEY_LAST_SUBSCRIPT(gv_currkey, prev, oldend); assert(save_dollar_tlevel == dollar_tlevel); # endif return found; } bool gvcst_zprevious2(void) { static gv_key *zprev_temp_key; static int4 zprev_temp_keysize = 0; blk_hdr_ptr_t bp; bool found, two_histories; enum cdb_sc status; rec_hdr_ptr_t rp; unsigned char *c1, *c2, *ctop; srch_blk_status *bh; srch_hist *lft_history; T_BEGIN_READ_NONTP_OR_TP(ERR_GVORDERFAIL); for (;;) { assert(t_tries < CDB_STAGNATE || cs_addrs->now_crit); /* we better hold crit in the final retry (TP & non-TP) */ two_histories = FALSE; if (cdb_sc_normal == (status = gvcst_search(gv_currkey, NULL))) { found = TRUE; bh = gv_target->hist.h; if (0 == bh->prev_rec.offset) { two_histories = TRUE; lft_history = gv_target->alt_hist; status = gvcst_lftsib(lft_history); if (cdb_sc_normal == status) { bh = lft_history->h; if (cdb_sc_normal != (status = gvcst_search_blk(gv_currkey, bh))) { t_retry(status); continue; } } else if (cdb_sc_endtree == status) { found = FALSE; two_histories = FALSE; /* second history not valid */ } else { t_retry(status); continue; } } if (found) { /* store new subscipt */ assert(gv_altkey->top == gv_currkey->top); assert(gv_altkey->top == gv_keysize); assert(gv_currkey->end < gv_currkey->top); rp = (rec_hdr_ptr_t)(bh->buffaddr + bh->prev_rec.offset); bp = (blk_hdr_ptr_t)bh->buffaddr; c1 = gv_altkey->base; memcpy(c1, gv_currkey->base, bh->prev_rec.match); c1 += bh->prev_rec.match; assert(zprev_temp_keysize <= gv_keysize); if (zprev_temp_keysize < gv_keysize) { zprev_temp_keysize = gv_keysize; GVKEY_INIT(zprev_temp_key, zprev_temp_keysize); } assert(zprev_temp_key->top >= gv_currkey->top); if (cdb_sc_normal != (status = gvcst_expand_key((blk_hdr_ptr_t)bh->buffaddr, bh->prev_rec.offset, zprev_temp_key))) { t_retry(status); continue; } if ((zprev_temp_key->end < gv_currkey->end) && (zprev_temp_key->end <= gv_currkey->prev)) found = FALSE; else { c2 = zprev_temp_key->base + bh->prev_rec.match; ctop = zprev_temp_key->base + zprev_temp_key->end; for (;;) { if (c2 >= ctop) { assert(CDB_STAGNATE > t_tries); status = cdb_sc_rmisalign; goto restart; /* goto needed because of nested FOR loop */ } if (0 == (*c1++ = *c2++)) { *c1 = 0; break; } } } gv_altkey->end = c1 - gv_altkey->base; assert(gv_altkey->end < gv_altkey->top); } if (!dollar_tlevel) { if ((trans_num)0 == t_end(&gv_target->hist, two_histories ? lft_history : NULL, TN_NOT_SPECIFIED)) continue; } else { status = tp_hist(two_histories ? lft_history : NULL); if (cdb_sc_normal != status) { t_retry(status); continue; } } assert(cs_data == cs_addrs->hdr); INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_zprev, 1); return (found && (bh->prev_rec.match >= gv_currkey->prev)); } restart: t_retry(status); } } fis-gtm-V6.0-003/sr_port/gvincr_compute_post_incr.c0000644000032200000250000000723712201176157021315 0ustar librarygtc/**************************************************************** * * * Copyright 2004, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "cdb_sc.h" #include "gdsroot.h" #include "gtm_facility.h" #include "gdskill.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "filestruct.h" #include "gdscc.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "jnl.h" #include "copy.h" #include "op.h" /* for op_add prototype */ #define GVINCR_PRE_INCR_MIN_BUFFLEN MAX_NUM_SIZE /* starting size of the malloced buffer to store pre_increment value */ /* since the increment will mostly be a number, start with MAX_NUM_SIZE */ static char *gvincr_pre_incr_buff; /* buffer to hold the pre-$INCR string value before converting to numeric */ static int gvincr_pre_incr_bufflen = 0; /* length of the currently allocated buffer, updated if expansion occurs */ GBLREF mval *post_incr_mval; GBLREF gv_key *gv_currkey; GBLREF mval increment_delta_mval; /* mval holding the increment value, set by op_gvincr */ GBLREF unsigned int t_tries; /* compute post_incr_mval from the current value of gv_currkey that was just now searched down the tree */ enum cdb_sc gvincr_compute_post_incr(srch_blk_status *bh) { int4 cur_blk_size; sm_uc_ptr_t buffaddr; rec_hdr_ptr_t rp; unsigned short rec_size; int4 target_key_size, data_len; uint4 gvincr_malloc_len; mval pre_incr_mval; int tmp_cmpc; buffaddr = bh->buffaddr; cur_blk_size = ((blk_hdr_ptr_t)buffaddr)->bsiz; rp = (rec_hdr_ptr_t)(buffaddr + bh->curr_rec.offset); GET_USHORT(rec_size, &rp->rsiz); target_key_size = bh->curr_rec.match; assert(target_key_size == gv_currkey->end + 1); data_len = rec_size + EVAL_CMPC(rp) - SIZEOF(rec_hdr) - target_key_size; if ((0 > data_len) || (((sm_uc_ptr_t)rp + rec_size) > ((sm_uc_ptr_t)buffaddr + cur_blk_size))) { assert(CDB_STAGNATE > t_tries); return cdb_sc_rmisalign; } if (data_len > gvincr_pre_incr_bufflen) { if (NULL != gvincr_pre_incr_buff) free(gvincr_pre_incr_buff); gvincr_malloc_len = (data_len > GVINCR_PRE_INCR_MIN_BUFFLEN) ? data_len : GVINCR_PRE_INCR_MIN_BUFFLEN; gvincr_pre_incr_buff = (char *)malloc(gvincr_malloc_len); gvincr_pre_incr_bufflen = gvincr_malloc_len; } /* malloced buffer is used for pre_incr_mval instead of stringpool because this is memory that is * inherently used only by $INCREMENT and is needed only during the lifetime of the increment. * keeping it in the stringpool causes it to stay until the next garbage collection which adds * to unnecessary overheads. */ pre_incr_mval.mvtype = MV_STR; pre_incr_mval.str.addr = (char *)gvincr_pre_incr_buff; pre_incr_mval.str.len = data_len; memcpy(pre_incr_mval.str.addr, (sm_uc_ptr_t)rp + rec_size - data_len, data_len); op_add(&pre_incr_mval, &increment_delta_mval, post_incr_mval); assert(MV_IS_NUMERIC(post_incr_mval)); /* "post_incr_mval" is of numeric type, convert it to a string type so it can be used by the caller to set "value" */ MV_FORCE_STR(post_incr_mval); /* will use stringpool to store string representation */ /* "post_incr_mval" is a copy of the mval pointer passed to "op_gvincr" and hence is on the M-stack * and therefore is known to the garbage collector (stp_gcol). hence it is ok for it to use the stringpool */ return cdb_sc_normal; } fis-gtm-V6.0-003/sr_port/gvincr_recompute_upd_array.c0000644000032200000250000002211012201176157021615 0ustar librarygtc/**************************************************************** * * * Copyright 2004, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "cdb_sc.h" #include "gdsroot.h" #include "gtm_facility.h" #include "gdskill.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "filestruct.h" #include "gdscc.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "jnl.h" #include "copy.h" #include "gvcst_protos.h" /* for gvcst_search_blk prototypes */ #include "op.h" /* for add_mvals prototype */ #include "jnl_get_checksum.h" GBLREF uint4 dollar_tlevel; GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF mval *post_incr_mval; /* mval pointing to the post-$INCR value */ GBLREF jnl_format_buffer *non_tp_jfb_ptr; GBLREF jnl_gbls_t jgbl; GBLREF char *update_array, *update_array_ptr; GBLREF int gv_fillfactor, rc_set_fragment; /* Contains offset within data at which data fragment starts */ GBLREF unsigned char cw_set_depth; GBLREF gv_key *gv_currkey; GBLREF unsigned int t_tries; GBLREF uint4 update_array_size; GBLREF gv_namehead *gv_target; /* -------------------------------------------------------------------------------------------- * This code is very similar to the code in gvcst_put for the non-block-split case as well as * the code in recompute_upd_array in tp_tend.c. All of these need to be maintained in sync. * -------------------------------------------------------------------------------------------- */ enum cdb_sc gvincr_recompute_upd_array(srch_blk_status *bh, struct cw_set_element_struct *cse, cache_rec_ptr_t cr) { blk_segment *bs1, *bs_ptr; char *va; enum cdb_sc status; int4 blk_size, blk_fill_size, cur_blk_size, blk_seg_cnt, delta, tail_len, new_rec_size; int4 target_key_size, data_len; int tmp_cmpc; mstr value; rec_hdr_ptr_t curr_rec_hdr, rp; sm_uc_ptr_t cp1, buffaddr; unsigned short rec_size; jnl_format_buffer *jfb; blk_hdr_ptr_t old_block; sgmnt_addrs *csa; csa = cs_addrs; assert(!dollar_tlevel); /* this recomputation is currently supported only for non-TP */ /* To support this for TP would require addressing a lot more issues. Examples are * a) Currently we format jnl records only for explicit updates and not for implicit updates (updates in trigger code). * All such triggers updates currently happen inside of a TP (even if the explicit update is non-TP, there * is an implicit TP wrapper). Therefore we need to record more information as to whether this update * to the database needs a corresponding format of the logical journal record or not. */ assert(0 == cse->level); /* better be a leaf-level block */ assert(csa->now_crit); assert(!cse->level && (gds_t_write == cse->mode) && (NULL == cse->new_buff) && (GDS_WRITE_PLAIN == cse->write_type)); blk_size = cs_data->blk_size; /* "blk_size" is also used by the BLK_FINI macro below */ blk_fill_size = (blk_size * gv_fillfactor) / 100 - cs_data->reserved_bytes; /* clues for gv_target involved in recomputation need not be nullified since only the value changes (not the key) */ assert(CR_NOTVALID != (sm_long_t)cr); if (NULL == cr || CR_NOTVALID == (sm_long_t)cr || (0 <= cr->read_in_progress)) { assert(CDB_STAGNATE > t_tries); return cdb_sc_lostcr; } if (cr->in_tend) { /* Possible if this cache-record is being modified concurrently by another process in bg_update_phase2. * Normally t_qread would have waited for this to complete before returning. But it is possible in some * cases to bypass t_qread (e.g. gv_target->clue.end is non-zero). In this case we have two options. * a) Signal a restart. This will cause clue.end to get reset to 0 and will now go through t_qread. * b) Wait for in_tend to become non-zero and then proceed. This will save a restart. * Since we are not in TP the overhead of restarting is not that bad. * Since we hold crit at this point, we decide not to wait. We choose (a). */ assert(CDB_STAGNATE > t_tries); return cdb_sc_blkmod; } buffaddr = bh->buffaddr; target_key_size = gv_currkey->end + 1; if (cdb_sc_normal != (status = gvcst_search_blk(gv_currkey, bh))) { assert(CDB_STAGNATE > t_tries); return status; } if (target_key_size != bh->curr_rec.match) /* key does not exist, nothing doable here, restart transaction */ { assert(CDB_STAGNATE > t_tries); return cdb_sc_blkmod; } cur_blk_size = ((blk_hdr_ptr_t)buffaddr)->bsiz; rp = (rec_hdr_ptr_t)(buffaddr + bh->curr_rec.offset); GET_USHORT(rec_size, &rp->rsiz); data_len = rec_size + EVAL_CMPC(rp) - SIZEOF(rec_hdr) - target_key_size; if (cdb_sc_normal != (status = gvincr_compute_post_incr(bh))) { assert(CDB_STAGNATE > t_tries); return status; } assert(MV_IS_STRING(post_incr_mval)); /* gvincr_recompute_post_incr should have set it to be a of type MV_STR */ value = post_incr_mval->str; new_rec_size = rec_size - data_len + value.len; delta = new_rec_size - rec_size; if ((cur_blk_size + delta) > blk_fill_size) { assert(CDB_STAGNATE > t_tries); return cdb_sc_blksplit; } if (0 != rc_set_fragment) { assert(CDB_STAGNATE > t_tries); return cdb_sc_mkblk; /* let gvcst_put do the recomputation out of crit in case of rc_set */ } /* Note that a lot of the code below relies on the fact that we are in non-TP. For TP we need to do extra stuff */ assert(NULL != update_array); assert(NULL != update_array_ptr); assert(0 != update_array_size); assert(update_array + update_array_size >= update_array_ptr); assert(1 == cw_set_depth); /* since cw_set_depth is guaranteed to be 1 (by the above assert), we can be sure that the only update array space we would * have used is for the current (and only) cw_set_element "cse" and hence can reuse the space by resetting update_array_ptr */ assert(ROUND_UP2((INTPTR_T)update_array, UPDATE_ELEMENT_ALIGN_SIZE) == (INTPTR_T)cse->upd_addr); RESET_UPDATE_ARRAY; /* do not use CHECK_AND_RESET_UPDATE_ARRAY since we are knowingly resetting an active update array */ BLK_INIT(bs_ptr, bs1); BLK_SEG(bs_ptr, buffaddr + SIZEOF(blk_hdr), bh->curr_rec.offset - SIZEOF(blk_hdr)); BLK_ADDR(curr_rec_hdr, SIZEOF(rec_hdr), rec_hdr); curr_rec_hdr->rsiz = new_rec_size; SET_CMPC(curr_rec_hdr, bh->prev_rec.match); BLK_SEG(bs_ptr, (sm_uc_ptr_t)curr_rec_hdr, SIZEOF(rec_hdr)); BLK_ADDR(cp1, target_key_size - bh->prev_rec.match, unsigned char); memcpy(cp1, gv_currkey->base + bh->prev_rec.match, target_key_size - bh->prev_rec.match); BLK_SEG(bs_ptr, cp1, target_key_size - bh->prev_rec.match); assert(0 != value.len); BLK_ADDR(va, value.len, char); memcpy(va, value.addr, value.len); BLK_SEG(bs_ptr, (unsigned char *)va, value.len); rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)rp + rec_size); tail_len = (int4)(cur_blk_size - ((sm_uc_ptr_t)rp - buffaddr)); assert(tail_len >= 0); /* else gvincr_recompute_post_incr would have returned cdb_sc_rmisalign and we will not be here */ if (tail_len > 0) { BLK_SEG(bs_ptr, (sm_uc_ptr_t)rp, tail_len); } if (0 == BLK_FINI(bs_ptr, bs1)) { assert(CDB_STAGNATE > t_tries); return cdb_sc_mkblk; } cse->upd_addr = (unsigned char *)bs1; /* assert that cse->old_block is indeed pointing to the buffer that the cache-record is pointing to. * this is necessary to ensure that we are copying "ondsk_blkver" from the correct cache-record. * there is a possibility that this assert might not hold true which is if we are in a restartable situation. * but in that case do the same check that t_end will perform to determine this. */ assert((cse->old_block == (sm_uc_ptr_t)GDS_REL2ABS(cr->buffaddr)) || (bh->cycle != cr->cycle) || (bh->cr != cr)); cse->ondsk_blkver = cr->ondsk_blkver; cse->done = FALSE; /* Reformat the logical SET jnl-record if we need to write logical records. But recompute checksums for PBLK record * ONLY IF journaling is enabled. Do not need to do this in the case REPL_WAS_ENABLED(csa) is TRUE as replication * only cares about logical records. Hence the separation of the code below into two "if" blocks. */ if (JNL_WRITE_LOGICAL_RECS(csa)) jfb = jnl_format(JNL_SET, gv_currkey, post_incr_mval, 0); /* Re-format the logical SET jnl-record */ if (JNL_ENABLED(csa)) { /* Recompute checksums in case necessary */ if (csa->jnl_before_image && (NULL != cse->old_block)) { old_block = (blk_hdr_ptr_t)cse->old_block; if (old_block->tn < csa->jnl->jnl_buff->epoch_tn) cse->blk_checksum = jnl_get_checksum((uint4 *)old_block, csa, old_block->bsiz); else cse->blk_checksum = 0; } } assert(NULL != gv_target); /* If clue is known to be non-zero, we have the potential for the first_rec part of it to be unreliable. * Reset it to be safe. See comment in similar section in tp_hist for details on why. */ if (gv_target->clue.end) GVT_CLUE_INVALIDATE_FIRST_REC(gv_target); return cdb_sc_normal; } fis-gtm-V6.0-003/sr_port/gvinit.c0000644000032200000250000000240412201176157015500 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "dpgbldir.h" GBLREF gd_addr *gd_header; void gvinit(void) { mval v; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; /* if gd_header is null then get the current one, and update the gd_map */ if (!gd_header) { SET_GD_HEADER(v); SET_GD_MAP; } DEBUG_ONLY(else GD_HEADER_ASSERT); /* May get in here after an extended ref call OR in mupip journal recover forward processing (with * function call graph "mur_output_record/gvcst_put/gvtr_init/gvtr_db_tpwrap/op_tstart"). * In either case it is possible that gv_currkey has already been set up, so dont lose any preexisting keys. */ GVKEYSIZE_INCREASE_IF_NEEDED(DBKEYSIZE(gd_header->regions->max_key_size)); } fis-gtm-V6.0-003/sr_port/gvn.c0000644000032200000250000001020312201176157014766 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "mdq.h" #include "advancewindow.h" #include "fullbool.h" #include "show_source_line.h" GBLREF boolean_t run_time; error_def(ERR_EXPR); error_def(ERR_EXTGBLDEL); error_def(ERR_GBLNAME); error_def(ERR_GVNAKEDEXTNM); error_def(ERR_MAXNRSUBSCRIPTS); error_def(ERR_RPARENMISSING); error_def(ERR_SIDEEFFECTEVAL); int gvn(void) { boolean_t parse_status, shifting, vbar; char x; opctype ox; oprtype *sb1, *sb2, subscripts[MAX_GVSUBSCRIPTS]; triple *oldchain, *ref, *s, tmpchain, *triptr; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(TK_CIRCUMFLEX == TREF(window_token)); advancewindow(); sb1 = sb2 = subscripts; ox = 0; if (shifting = (TREF(shift_side_effects) && (!TREF(saw_side_effect) || (GTM_BOOL == TREF(gtm_fullbool) && (OLD_SE == TREF(side_effect_handling)))))) { /* NOTE assignment above */ dqinit(&tmpchain, exorder); oldchain = setcurtchain(&tmpchain); } if ((TK_LBRACKET == TREF(window_token)) || (TK_VBAR == TREF(window_token))) { vbar = (TK_VBAR == TREF(window_token)); advancewindow(); if (vbar) parse_status = expr(sb1++, MUMPS_EXPR); else parse_status = expratom(sb1++); if (!parse_status) { stx_error(ERR_EXPR); if (shifting) setcurtchain(oldchain); return FALSE; } if (TK_COMMA == TREF(window_token)) { advancewindow(); if (vbar) parse_status = expr(sb1++, MUMPS_EXPR); else parse_status = expratom(sb1++); if (!parse_status) { stx_error(ERR_EXPR); if (shifting) setcurtchain(oldchain); return FALSE; } } else *sb1++ = put_str(0,0); if ((!vbar && (TK_RBRACKET != TREF(window_token))) || (vbar && (TK_VBAR != TREF(window_token)))) { stx_error(ERR_EXTGBLDEL); if (shifting) setcurtchain(oldchain); return FALSE; } advancewindow(); ox = OC_GVEXTNAM; } if (TK_IDENT == TREF(window_token)) { if (!ox) ox = OC_GVNAME; *sb1++ = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); advancewindow(); } else { if (ox) { stx_error(ERR_GVNAKEDEXTNM); if (shifting) setcurtchain(oldchain); return FALSE; } if (TK_LPAREN != TREF(window_token)) { stx_error(ERR_GBLNAME); if (shifting) setcurtchain(oldchain); return FALSE; } ox = OC_GVNAKED; } if (TK_LPAREN == TREF(window_token)) { for (;;) { if (sb1 >= ARRAYTOP(subscripts)) { stx_error(ERR_MAXNRSUBSCRIPTS); if (shifting) setcurtchain(oldchain); return FALSE; } advancewindow(); if (EXPR_FAIL == expr(sb1, MUMPS_EXPR)) { if (shifting) setcurtchain(oldchain); return FALSE; } assert(TRIP_REF == sb1->oprclass); s = sb1->oprval.tref; if (OC_LIT == s->opcode) *sb1 = make_gvsubsc(&s->operand[0].oprval.mlit->v); sb1++; if (TK_RPAREN == (x = TREF(window_token))) /* NOTE assignment */ { advancewindow(); break; } if (TK_COMMA != x) { stx_error(ERR_RPARENMISSING); if (shifting) setcurtchain(oldchain); return FALSE; } } } ref = newtriple(ox); ref->operand[0] = put_ilit((mint)(sb1 - sb2)); SUBS_ARRAY_2_TRIPLES(ref, sb1, sb2, subscripts, 0); if (shifting) { if (TREF(saw_side_effect) && ((GTM_BOOL != TREF(gtm_fullbool)) || (OLD_SE != TREF(side_effect_handling)))) { /* saw a side effect in a subscript - time to stop shifting */ setcurtchain(oldchain); triptr = (TREF(curtchain))->exorder.bl; dqadd(triptr, &tmpchain, exorder); } else { newtriple(OC_GVSAVTARG); setcurtchain(oldchain); dqadd(TREF(expr_start), &tmpchain, exorder); TREF(expr_start) = tmpchain.exorder.bl; triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(TREF(expr_start)); } } return TRUE; } fis-gtm-V6.0-003/sr_port/gvname_env_restore.c0000644000032200000250000000430512201176157020072 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdskill.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gdscc.h" #include "copy.h" #include "jnl.h" #include "buddy_list.h" #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "gtm_string.h" #include "gvname_info.h" GBLREF gv_key *gv_currkey; GBLREF gd_region *gv_cur_region; GBLREF gv_namehead *gv_target; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF uint4 dollar_tlevel; GBLREF sgm_info *sgm_info_ptr; void gvname_env_restore(gvname_info *curr_gvname_info) { DEBUG_ONLY(boolean_t is_bg_or_mm;) gv_target = curr_gvname_info->s_gv_target; gv_cur_region = curr_gvname_info->s_gv_cur_region; DEBUG_ONLY(is_bg_or_mm = (dba_bg == gv_cur_region->dyn.addr->acc_meth || dba_mm == gv_cur_region->dyn.addr->acc_meth);) cs_addrs = curr_gvname_info->s_cs_addrs; assert((is_bg_or_mm && cs_addrs) || dba_cm == gv_cur_region->dyn.addr->acc_meth || dba_usr == gv_cur_region->dyn.addr->acc_meth); if (cs_addrs) /* cs_addrs might be NULL for dba_cm/dba_usr region */ cs_data = cs_addrs->hdr; assert(gv_currkey->top <= curr_gvname_info->s_gv_currkey->top); gv_currkey->end = curr_gvname_info->s_gv_currkey->end; gv_currkey->prev = curr_gvname_info->s_gv_currkey->prev; memcpy(gv_currkey->base, curr_gvname_info->s_gv_currkey->base, curr_gvname_info->s_gv_currkey->end + 1); sgm_info_ptr = curr_gvname_info->s_sgm_info_ptr; assert((is_bg_or_mm && ((dollar_tlevel && sgm_info_ptr) || (!dollar_tlevel && !sgm_info_ptr))) || (dba_cm == gv_cur_region->dyn.addr->acc_meth) || (dba_usr == gv_cur_region->dyn.addr->acc_meth)); DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); } fis-gtm-V6.0-003/sr_port/gvname_env_save.c0000644000032200000250000000413712201176157017350 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdskill.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "gdscc.h" #include "copy.h" #include "jnl.h" #include "buddy_list.h" #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "gtm_string.h" #include "gvname_info.h" GBLREF gv_key *gv_currkey; GBLREF gd_region *gv_cur_region; GBLREF gv_namehead *gv_target; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF uint4 dollar_tlevel; GBLREF sgm_info *sgm_info_ptr; void gvname_env_save(gvname_info * curr_gvname_info) { DEBUG_ONLY(boolean_t is_bg_or_mm;) DEBUG_ONLY(is_bg_or_mm = (dba_mm == gv_cur_region->dyn.addr->acc_meth || dba_bg == gv_cur_region->dyn.addr->acc_meth);) curr_gvname_info->s_gv_target = gv_target; curr_gvname_info->s_gv_cur_region = gv_cur_region; assert((is_bg_or_mm && cs_addrs->hdr == cs_data) || dba_cm == gv_cur_region->dyn.addr->acc_meth || dba_usr == gv_cur_region->dyn.addr->acc_meth); curr_gvname_info->s_cs_addrs = cs_addrs; DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); assert(gv_currkey->top <= curr_gvname_info->s_gv_currkey->top); curr_gvname_info->s_gv_currkey->end = gv_currkey->end; curr_gvname_info->s_gv_currkey->prev = gv_currkey->prev; memcpy(curr_gvname_info->s_gv_currkey->base, gv_currkey->base, gv_currkey->end + 1); curr_gvname_info->s_sgm_info_ptr = sgm_info_ptr; assert((is_bg_or_mm && ((dollar_tlevel && sgm_info_ptr) || (!dollar_tlevel && !sgm_info_ptr))) || dba_cm == gv_cur_region->dyn.addr->acc_meth || dba_usr == gv_cur_region->dyn.addr->acc_meth); } fis-gtm-V6.0-003/sr_port/gvname_info.h0000644000032200000250000000241112201176157016473 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* gvname_info.h * ------------- * * Following structure is to save result of a call to op_gvname(). * Specially in merge we do not need to call op_gvname again and again. * Just call once and save result. * Also note that it is not easy to call op_gvname with variable arguments again and again. */ #ifndef MERGE_GLOBAL_DEFINED typedef struct gvname_info_struct { gv_key *s_gv_currkey; gv_namehead *s_gv_target; gd_region *s_gv_cur_region; sgmnt_addrs *s_cs_addrs; sgm_info *s_sgm_info_ptr; } gvname_info; typedef gvname_info *gvname_info_ptr; /* Function Prototypes for M global variable functions of MERGE */ void gvname_env_restore(gvname_info *curr_gvname_info); void gvname_env_save(gvname_info * curr_gvname_info); #define MERGE_GLOBAL_DEFINED #endif fis-gtm-V6.0-003/sr_port/gvstats_rec.c0000644000032200000250000000620312201176157016525 0ustar librarygtc/**************************************************************** * * * Copyright 2008, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gvstats_rec.h" void gvstats_rec_csd2cnl(sgmnt_addrs *csa) { memcpy(&csa->nl->gvstats_rec, &csa->hdr->gvstats_rec, SIZEOF(gvstats_rec_t)); } void gvstats_rec_cnl2csd(sgmnt_addrs *csa) { memcpy(&csa->hdr->gvstats_rec, &csa->nl->gvstats_rec, SIZEOF(gvstats_rec_t)); } void gvstats_rec_upgrade(sgmnt_addrs *csa) { node_local_ptr_t cnl; sgmnt_data_ptr_t csd; int index; csd = csa->hdr; cnl = csa->nl; /* csd still contains gvstats info in old place. Copy over to new location */ cnl->gvstats_rec.n_nontp_retries_0 = csd->filler_n_retries[0]; cnl->gvstats_rec.n_nontp_retries_1 = csd->filler_n_retries[1]; cnl->gvstats_rec.n_nontp_retries_2 = csd->filler_n_retries[2]; cnl->gvstats_rec.n_nontp_retries_3 = csd->filler_n_retries[3]; cnl->gvstats_rec.n_set = csd->filler_n_puts; cnl->gvstats_rec.n_kill = csd->filler_n_kills; cnl->gvstats_rec.n_query = csd->filler_n_queries; cnl->gvstats_rec.n_get = csd->filler_n_gets; cnl->gvstats_rec.n_order = csd->filler_n_order; cnl->gvstats_rec.n_zprev = csd->filler_n_zprevs; cnl->gvstats_rec.n_data = csd->filler_n_data; /* No longer maintained : csd->filler_n_puts_duplicate */ cnl->gvstats_rec.n_tp_readwrite = csd->filler_n_tp_updates; /* No longer maintained : csd->filler_n_tp_updates_duplicate */ cnl->gvstats_rec.n_tp_tot_retries_0 = csd->filler_n_tp_retries[0]; cnl->gvstats_rec.n_tp_tot_retries_1 = csd->filler_n_tp_retries[1]; cnl->gvstats_rec.n_tp_tot_retries_2 = csd->filler_n_tp_retries[2]; cnl->gvstats_rec.n_tp_tot_retries_3 = csd->filler_n_tp_retries[3]; cnl->gvstats_rec.n_tp_tot_retries_4 = csd->filler_n_tp_retries[4]; for (index = 5; index < 12; index++) cnl->gvstats_rec.n_tp_tot_retries_4 += csd->filler_n_tp_retries[index]; cnl->gvstats_rec.n_tp_cnflct_retries_0 = csd->filler_n_tp_retries_conflicts[0]; cnl->gvstats_rec.n_tp_cnflct_retries_1 = csd->filler_n_tp_retries_conflicts[1]; cnl->gvstats_rec.n_tp_cnflct_retries_2 = csd->filler_n_tp_retries_conflicts[2]; cnl->gvstats_rec.n_tp_cnflct_retries_3 = csd->filler_n_tp_retries_conflicts[3]; cnl->gvstats_rec.n_tp_cnflct_retries_4 = csd->filler_n_tp_retries_conflicts[4]; for (index = 5; index < 12; index++) cnl->gvstats_rec.n_tp_cnflct_retries_4 += csd->filler_n_tp_retries_conflicts[index]; /* Nullify statistics that were formerly in use but no longer so */ csd->unused_dsk_reads.curr_count = 0; csd->unused_dsk_reads.cumul_count = 0; csd->unused_dsk_writes.curr_count = 0; csd->unused_dsk_writes.cumul_count = 0; } fis-gtm-V6.0-003/sr_port/gvstats_rec.h0000644000032200000250000000226512201176157016536 0ustar librarygtc/**************************************************************** * * * Copyright 2008, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GVSTATS_REC_H_INCLUDED #define GVSTATS_REC_H_INCLUDED /* Note gvstats_rec exists in both sgmnt_data (file header) and in node_local. The reason * for this is so that gvstats can be updated by read-only processes which would not be * able to update the read-only file header. The gvstats in node_local are the ones that * get updated and are peridically copied back to the fileheader and during fileheader * flushes to keep them up to date. */ #define TAB_GVSTATS_REC(A,B,C) A, enum gvstats_rec_type { #include "tab_gvstats_rec.h" n_gvstats_rec_types }; #undef TAB_GVSTATS_REC typedef struct gvstats_rec_struct { #define TAB_GVSTATS_REC(A,B,C) gtm_uint64_t A; #include "tab_gvstats_rec.h" } gvstats_rec_t; #undef TAB_GVSTATS_REC #endif fis-gtm-V6.0-003/sr_port/gvstrsub.c0000644000032200000250000000323012201176157016055 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "collseq.h" #include "gdsfhead.h" #include "do_xform.h" #include "gvstrsub.h" #include "zshow.h" GBLREF gv_namehead *gv_target; unsigned char *gvstrsub(unsigned char *src, unsigned char *target) { int length, n, target_len; char buf[MAX_KEY_SZ + 1], buf1[MAX_KEY_SZ + 1], *ptr; unsigned char *str; mstr mstr_x; mstr mstr_tmp; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; ptr = buf; for (n = 0, str = src; *str; ++n, ++str) { if (1 == *str) { str++; *ptr++ = *str - 1; } else *ptr++ = *str; } if (TREF(transform) && gv_target && gv_target->collseq) { mstr_x.len = n; mstr_x.addr = buf; mstr_tmp.len = SIZEOF(buf1); mstr_tmp.addr = buf1; do_xform(gv_target->collseq, XBACK, &mstr_x, &mstr_tmp, &length); n = length; str = (unsigned char *)mstr_tmp.addr; /* mstr_tmp.addr is used just in case it is reallocated in the XBACK routine */ } else str = (unsigned char *)buf; format2zwr((sm_uc_ptr_t)str, n, target, &target_len); return target + target_len; } fis-gtm-V6.0-003/sr_port/gvstrsub.h0000644000032200000250000000112712201176157016065 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GVSTRSUB_INCLUDED #define GVSTRSUB_INCLUDED unsigned char *gvstrsub(unsigned char *src, unsigned char *target); #endif /* GVSTRSUB_INCLUDED */ fis-gtm-V6.0-003/sr_port/gvsub2str.c0000644000032200000250000001173512201176157016150 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* * ----------------------------------------------------- * Convert a string subscript to MUMPS string * ----------------------------------------------------- */ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "copy.h" #include "collseq.h" #include "do_xform.h" #include "gvstrsub.h" #include "gvsub2str.h" #define LARGE_EXP 10000 GBLREF gv_namehead *gv_target; LITREF unsigned short dpos[], dneg[]; /* * ----------------------------------------------------- * Convert a string subscript to MUMPS string * Save result in a buffer pointed by targ. * * Entry: * sub - input string in subscript format * targ - output string buffer * xlat_flg- translate flag. * If true convert string to MUMPS format * Return: * (pointer to the last char. * converted in the targ string) + 1. * ----------------------------------------------------- */ unsigned char *gvsub2str(unsigned char *sub, unsigned char *targ, boolean_t xlat_flg) { unsigned char buf1[MAX_KEY_SZ + 1], ch, *ptr, trail_ch; unsigned short *tbl_ptr; int num, rev_num, trail_zero; span_subs *subs_ptr; int expon, in_length, length, tmp; mstr mstr_ch, mstr_targ; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; ch = *sub++; if (STR_SUB_PREFIX == ch || (SUBSCRIPT_STDCOL_NULL == ch && KEY_DELIMITER == *sub)) { /* If this is a string */ if (xlat_flg) return gvstrsub(sub, targ); else { in_length = 0; ptr = targ; while ((ch = *sub++)) { /* Copy string to targ, xlating each char */ in_length++; if (STR_SUB_ESCAPE == ch) /* if this is an escape, demote next char */ ch = (*sub++ - 1); *targ++ = ch; } if (TREF(transform) && gv_target && gv_target->collseq) { mstr_ch.len = in_length; mstr_ch.addr = (char *)ptr; mstr_targ.len = SIZEOF(buf1); mstr_targ.addr = (char *)buf1; do_xform(gv_target->collseq, XBACK, &mstr_ch, &mstr_targ, &length); memcpy(ptr, mstr_targ.addr, length); /* mstr_targ.addr is used just in case it is * reallocated by the XBACK routine */ targ = ptr + length; } } } else { /* Number */ if (SUBSCRIPT_ZERO == ch) *targ++ = '0'; else if(SPANGLOB_SUB_ESCAPE == ch) { ASGN_SPAN_PREFIX(targ); targ += SPAN_PREFIX_LEN; subs_ptr = (span_subs *)(sub - 1); /* Internal to the database, the spanning node blocks counting starts with 0 i.e. first spanning * node block has ID '0' but while displaying first block of spanning node is displayed as '1' * Hence the below adjustment in the 'num'. */ num = SPAN_GVSUBS2INT(subs_ptr) + 1; sub = (sub - 1) + SPAN_SUBS_LEN; for (trail_zero = 0; (num % DECIMAL_BASE) == 0; trail_zero++, num /= DECIMAL_BASE) ; for (rev_num = 0; num > 0; rev_num = (rev_num * DECIMAL_BASE + num % DECIMAL_BASE), num /= DECIMAL_BASE) ; for (; rev_num > 0; *targ++ = (rev_num % DECIMAL_BASE + ASCII_0), rev_num /= DECIMAL_BASE) ; for (; trail_zero > 0 ; *targ++ = '0', trail_zero--); if (*sub != 0) *targ++ = '*'; } else { tbl_ptr = (unsigned short *)&dpos[0] - 1; trail_ch = KEY_DELIMITER; if (0 <= (signed char)ch) { /* Bit 7 of the exponent is set for positive numbers; must be negative */ trail_ch = NEG_MNTSSA_END; tbl_ptr = (unsigned short *)dneg; ch = ~ch; *targ++ = '-'; } ch -= (SUBSCRIPT_BIAS - 1); /* Unbias the exponent */ expon = ch; if (0 >= (signed char)ch) { /* number is a fraction */ ch = -(signed char)ch; /* Save decimal point */ *targ++ = '.'; /* generate leading 0's */ do *targ++ = '0'; while ((signed char)ch-- > 0) ; /* make expon. really large to avoid * generating extra dots */ expon = LARGE_EXP; } while ((ch = *sub++) && ch != trail_ch) { /* Convert digits loop */ /* adjust dcm. point */ if (0 >= (expon -= 2)) { if (0 != expon) { *targ++ = '.'; expon = LARGE_EXP; PUT_USHORT(targ, tbl_ptr[ch]); targ += SIZEOF(short); } else { /* Insert dot between digits */ PUT_USHORT(targ, tbl_ptr[ch]); targ += SIZEOF(short); *targ = *(targ - 1); *(targ - 1) = '.'; targ++; expon = LARGE_EXP; } } else { PUT_USHORT(targ, tbl_ptr[ch]); targ += SIZEOF(short); } } if ((LARGE_EXP - 100) < expon) { if ('0' == *(targ - 1)) targ--; if ('.' == *(targ - 1)) targ--; } else while (--expon > 0) *targ++ = '0'; } } return (targ); } fis-gtm-V6.0-003/sr_port/gvsub2str.h0000644000032200000250000000116412201176157016150 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GVSUB2STR_INCLUDED #define GVSUB2STR_INCLUDED unsigned char *gvsub2str(unsigned char *sub, unsigned char *targ, boolean_t xlat_flg); #endif /* GVSUB2STR_INCLUDED */ fis-gtm-V6.0-003/sr_port/gvusr.h0000644000032200000250000000170512201176157015356 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GVUSR_INCLUDED #define GVUSR_INCLUDED int gvusr_data(void); int gvusr_get(mval *v); int gvusr_lock(uint4 lock_len, unsigned char *lock_key, gd_region *reg); int gvusr_order(void); int gvusr_query(mval *v); int gvusr_zprevious(void); void gvusr_init(gd_region *reg, gd_region **creg, gv_key **ckey, gv_key **akey); void gvusr_kill(bool do_subtree); void gvusr_put(mval *v); void gvusr_rundown(void); void gvusr_unlock(uint4 lock_len, unsigned char *lock_key, gd_region *reg); #endif /* GVUSR_INCLUDED */ fis-gtm-V6.0-003/sr_port/gvusr_queryget.h0000644000032200000250000000111612201176157017277 0ustar librarygtc/**************************************************************** * * * Copyright 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef GVUSR_QUERYGET_H_INCLUDED #define GVUSR_QUERYGET_H_INCLUDED boolean_t gvusr_queryget(mval *v); #endif /* GVUSR_QUERYGET_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/gvzwr_arg.c0000644000032200000250000000301412201176157016206 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "zwrite.h" GBLREF gvzwrite_datablk *gvzwrite_block; void gvzwr_arg(int t, mval *a1, mval *a2) { int i; i = gvzwrite_block->subsc_count++; /* it would be good to guard the array i < sizeof... */ if (a1) { MV_FORCE_DEFINED(a1); if (MV_IS_CANONICAL(a1)) MV_FORCE_NUMD(a1); MV_FORCE_STRD(a1); if ((ZWRITE_VAL != t) && (0 == a1->str.len)) /* value is real - leave it alone */ a1 = NULL; } if (a2) { MV_FORCE_DEFINED(a2); if (MV_IS_CANONICAL(a2)) MV_FORCE_NUMD(a2); MV_FORCE_STRD(a2); if (0 == a2->str.len) /* can never be value */ a2 = NULL; } ((zwr_sub_lst *)gvzwrite_block->sub)->subsc_list[i].subsc_type = t; ((zwr_sub_lst *)gvzwrite_block->sub)->subsc_list[i].first = a1; ((zwr_sub_lst *)gvzwrite_block->sub)->subsc_list[i].second = a2; if ((ZWRITE_ASTERISK != t) && (ZWRITE_ALL != t)) gvzwrite_block->mask |= 1 << i; if (ZWRITE_VAL != t) gvzwrite_block->fixed = FALSE; return; } fis-gtm-V6.0-003/sr_port/gvzwr_fini.c0000644000032200000250000000703612201176157016372 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "mlkdef.h" #include "zshow.h" #include "zwrite.h" #include "error.h" #include "op.h" #include "change_reg.h" #include "patcode.h" #include "sgnl.h" #include "gvzwrite_clnup.h" #include "mvalconv.h" GBLDEF zshow_out *zwr_output; GBLREF gv_namehead *gv_target; GBLREF gv_namehead *reset_gv_target; GBLREF gv_key *gv_currkey; GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF gvzwrite_datablk *gvzwrite_block; GBLREF gd_binding *gd_map; GBLREF gd_binding *gd_map_top; error_def(ERR_GVNAKED); void gvzwr_fini(zshow_out *out, int pat) { char m[SIZEOF(mident_fixed)]; mval local, data; gv_key *old; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (!gv_currkey) gvinit(); ESTABLISH(gvzwrite_ch); zwr_output = out; assert(INVALID_GV_TARGET == reset_gv_target); reset_gv_target = gv_target; DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); gvzwrite_block->gd_reg = gv_cur_region; gvzwrite_block->old_targ = (unsigned char *)gv_target; old = (gv_key *)malloc(SIZEOF(gv_key) + gv_currkey->end); gvzwrite_block->old_key = (unsigned char *)old; memcpy(gvzwrite_block->old_key, gv_currkey, SIZEOF(gv_key) + gv_currkey->end); gvzwrite_block->old_map = gd_map; gvzwrite_block->old_map_top = gd_map_top; gvzwrite_block->gv_last_subsc_null = TREF(gv_last_subsc_null); gvzwrite_block->gv_some_subsc_null = TREF(gv_some_subsc_null); if (!pat) { local = *gvzwrite_block->pat; if (local.str.len) /* New reference. Will get new gv_target.. */ { gv_target = NULL; gv_currkey->base[0] = '\0'; op_gvname(VARLSTCNT(1) &local); op_gvdata(&data); if (!(MV_FORCE_INTD(&data))) sgnl_gvundef(); else { gvzwrite_block->fixed = (gvzwrite_block->fixed ? TRUE : FALSE); gvzwr_var(MV_FORCE_INTD(&data), 0); } } else /* Old (naked) reference. Keep previous gv_target reference */ { if (gv_currkey->prev == 0) rts_error(VARLSTCNT(1) ERR_GVNAKED); gv_currkey->end = gv_currkey->prev; gv_currkey->base[ gv_currkey->end ] = 0; gv_currkey->prev = 0; op_gvdata(&data); if (!(MV_FORCE_INTD(&data))) sgnl_gvundef(); else { gvzwrite_block->fixed = (gvzwrite_block->fixed ? TRUE : FALSE); gvzwr_var((int4)MV_FORCE_INTD(&data), 0); } } } else { gv_target = NULL; gv_currkey->base[0] = '\0'; local.mvtype = MV_STR; local.str.addr = &m[0]; local.str.len = 1; m[0] = '%'; gvzwrite_block->fixed = FALSE; for (; ;) { op_gvname(VARLSTCNT(1) &local); if (do_pattern(&local, gvzwrite_block->pat)) { op_gvdata(&data); if ((MV_FORCE_INTD(&data))) { gvzwr_var((int4)MV_FORCE_INTD(&data), 0); } } op_gvorder(&local); if (local.str.len) { assert(local.str.len <= MAX_MIDENT_LEN + 1); local.str.addr++; local.str.len--; memcpy(&m[0], local.str.addr, local.str.len); local.str.addr = &m[0]; } else break; } } gvzwrite_clnup(); /* this routine is called by gvzwrite_ch() too */ REVERT; return; } fis-gtm-V6.0-003/sr_port/gvzwr_init.c0000644000032200000250000000221412201176157016401 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "zwrite.h" #include "subscript.h" GBLREF gvzwrite_datablk *gvzwrite_block; void gvzwr_init(unsigned short t, mval *val, int4 pat) { if (NULL == gvzwrite_block) { gvzwrite_block = malloc(SIZEOF(gvzwrite_datablk)); memset(gvzwrite_block, 0, SIZEOF(gvzwrite_datablk)); } MV_FORCE_STR(val); gvzwrite_block->type = pat; if (NULL == gvzwrite_block->sub) gvzwrite_block->sub = (zwr_sub_lst *)malloc(SIZEOF(zwr_sub_lst) * MAX_GVSUBSCRIPTS); gvzwrite_block->pat = val; gvzwrite_block->mask = gvzwrite_block->subsc_count = 0; gvzwrite_block->fixed = TRUE; return; } fis-gtm-V6.0-003/sr_port/gvzwr_out.c0000644000032200000250000000245612201176157016255 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2008 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "zshow.h" #include "op.h" #include "format_targ_key.h" #include "mlkdef.h" #include "zwrite.h" GBLREF gv_key *gv_currkey; GBLREF zshow_out *zwr_output; void gvzwr_out(void) { int n; mval val; mval outdesc; mstr one; char buff[MAX_ZWR_KEY_SZ], *end; if ((end = (char *)format_targ_key((uchar_ptr_t)&buff[0], MAX_ZWR_KEY_SZ, gv_currkey, TRUE)) == 0) end = &buff[MAX_ZWR_KEY_SZ - 1]; op_gvget(&val); if (!MV_DEFINED(&val)) return; MV_FORCE_STRD(&val); outdesc.mvtype = MV_STR; outdesc.str.addr = &buff[0]; outdesc.str.len = INTCAST(end - outdesc.str.addr); zshow_output(zwr_output,&outdesc.str); buff[0] = '='; one.addr = &buff[0]; one.len = 1; zshow_output(zwr_output,&one); mval_write(zwr_output,&val,TRUE); } fis-gtm-V6.0-003/sr_port/gvzwr_var.c0000644000032200000250000001475412201176157016242 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "zwrite.h" #include "op.h" #include "outofband.h" #include "numcmp.h" #include "patcode.h" #include "sgnl.h" #include "mvalconv.h" #include "follow.h" #include "gtm_string.h" #define eb_less(u, v) (numcmp(u, v) < 0) GBLREF gv_key *gv_currkey; GBLREF gvzwrite_datablk *gvzwrite_block; GBLREF int4 outofband; GBLREF gd_region *gv_cur_region; LITREF mval literal_null; void gvzwr_var(uint4 data, int4 n) { mval mv, subdata; unsigned short end, prev, end1, prev1; bool save_gv_last_subsc_null; boolean_t do_lev; char seen_null; zwr_sub_lst *zwr_sub; int loop_condition = 1; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (outofband) outofband_action(FALSE); zwr_sub = (zwr_sub_lst *)gvzwrite_block->sub; if ((0 == gvzwrite_block->subsc_count) && (0 == n)) zwr_sub->subsc_list[n].subsc_type = ZWRITE_ASTERISK; if ((1 == data || 11 == data) && (!gvzwrite_block->subsc_count || (ZWRITE_ASTERISK == zwr_sub->subsc_list[n].subsc_type) || (n && !(gvzwrite_block->mask >> n)))) gvzwr_out(); if ((1 >= data) || (gvzwrite_block->subsc_count && (n >= gvzwrite_block->subsc_count) && (ZWRITE_ASTERISK != zwr_sub->subsc_list[gvzwrite_block->subsc_count - 1].subsc_type))) return; assert(1 < data); end = gv_currkey->end; prev = gv_currkey->prev; if ((n < gvzwrite_block->subsc_count) && (ZWRITE_VAL == zwr_sub->subsc_list[n].subsc_type)) { mval2subsc(zwr_sub->subsc_list[n].first, gv_currkey); op_gvdata(&subdata); if (MV_FORCE_INTD(&subdata) && ((10 != (int4)MV_FORCE_INTD(&subdata)) || n < gvzwrite_block->subsc_count - 1)) { save_gv_last_subsc_null = TREF(gv_last_subsc_null); gvzwr_var((int4)MV_FORCE_INTD(&subdata), n + 1); TREF(gv_last_subsc_null) = save_gv_last_subsc_null; } else if (gvzwrite_block->fixed) sgnl_gvundef(); } else { seen_null = 0; if (n < gvzwrite_block->subsc_count && zwr_sub->subsc_list[n].first && ZWRITE_PATTERN != zwr_sub->subsc_list[n].subsc_type) { mv = *zwr_sub->subsc_list[n].first; mval2subsc(&mv, gv_currkey); if ((mv.mvtype & MV_STR) && !mv.str.len) seen_null = 1; op_gvdata(&subdata); } else { mval2subsc((mval *)&literal_null, gv_currkey); TREF(gv_last_subsc_null) = TRUE; if (0 == gv_cur_region->std_null_coll) { op_gvorder(&mv); /* This will return the first subscript */ if (0 == mv.str.len) { if (NEVER == gv_cur_region->null_subs || seen_null) loop_condition = 0; else { seen_null = 1; /* set flag to indicate processing null sub */ op_gvnaked(VARLSTCNT(1) &mv); op_gvdata(&subdata); if (!MV_FORCE_INTD(&subdata)) loop_condition = 0; } } else { op_gvnaked(VARLSTCNT(1) &mv); op_gvdata(&subdata); } } else /* for standard null collation */ { /* determine whether $data(^gbl("") == 1 or 11, if yes, first process that */ if (NEVER == gv_cur_region->null_subs) { op_gvorder(&mv); assert(0 != mv.str.len); /* We are looking for the first subscript at a given level and so, we do not expect to have hit at the end of the list */ op_gvnaked(VARLSTCNT(1) &mv); op_gvdata(&subdata); } else { op_gvdata(&subdata); if (MV_FORCE_INTD(&subdata)) seen_null = 1; } } } while (loop_condition) { do_lev = (MV_FORCE_INTD(&subdata) ? TRUE : FALSE); if (n < gvzwrite_block->subsc_count) { if (ZWRITE_PATTERN == zwr_sub->subsc_list[n].subsc_type) { if (!do_pattern(&mv, zwr_sub->subsc_list[n].first)) do_lev = FALSE; } else if (ZWRITE_ALL != zwr_sub->subsc_list[n].subsc_type) { if (do_lev && zwr_sub->subsc_list[n].first) { if (MV_IS_CANONICAL(&mv)) { if (!MV_IS_CANONICAL(zwr_sub->subsc_list[n].first) || eb_less(&mv, zwr_sub->subsc_list[n].first)) do_lev = FALSE; } else { if (!MV_IS_CANONICAL(zwr_sub->subsc_list[n].first) && (!follow(&mv, zwr_sub->subsc_list[n].first) && (mv.str.len != zwr_sub->subsc_list[n].first->str.len || memcmp(mv.str.addr, zwr_sub->subsc_list[n].first->str.addr, mv.str.len)))) do_lev = FALSE; } } if (do_lev && zwr_sub->subsc_list[n].second) { if (MV_IS_CANONICAL(&mv)) { if (MV_IS_CANONICAL(zwr_sub->subsc_list[n].second) && eb_less(zwr_sub->subsc_list[n].second, &mv)) do_lev = FALSE; } else { if (MV_IS_CANONICAL(zwr_sub->subsc_list[n].second) || (!follow(zwr_sub->subsc_list[n].second, &mv) && (mv.str.len != zwr_sub->subsc_list[n].second->str.len || memcmp(mv.str.addr, zwr_sub->subsc_list[n].second->str.addr, mv.str.len)))) do_lev = FALSE; } if (!do_lev) break; } } } if (do_lev) { end1 = gv_currkey->end; prev1 = gv_currkey->prev; save_gv_last_subsc_null = TREF(gv_last_subsc_null); gvzwr_var((int4)MV_FORCE_INTD(&subdata), n + 1); TREF(gv_last_subsc_null) = save_gv_last_subsc_null; gv_currkey->end = end1; gv_currkey->prev = prev1; gv_currkey->base[end1] = 0; } if (1 == seen_null) { assert(TREF(gv_last_subsc_null)); TREF(gv_last_subsc_null) = FALSE; seen_null = 2; /* set flag to indicate null sub processed */ } op_gvorder(&mv); /* When null subscript is in the middle, but with standard collation null subscripts can not be in the middle, so don't need to be worried */ if (0 == mv.str.len) { if (NEVER == gv_cur_region->null_subs || seen_null || gv_cur_region->std_null_coll) break; else { seen_null = 1; /* set flag to indicate processing null sub */ op_gvnaked(VARLSTCNT(1) &mv); op_gvdata(&subdata); if (!MV_FORCE_INTD(&subdata)) break; } } else { op_gvnaked(VARLSTCNT(1) &mv); op_gvdata(&subdata); } } } gv_currkey->end = end; gv_currkey->prev = prev; gv_currkey->base[end] = 0; } fis-gtm-V6.0-003/sr_port/gvzwrite_ch.c0000644000032200000250000000117512201176157016537 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "error.h" #include "gvzwrite_clnup.h" CONDITION_HANDLER(gvzwrite_ch) { START_CH; gvzwrite_clnup(); /* this routine is called by gvzwr_fini() too */ NEXTCH; } fis-gtm-V6.0-003/sr_port/gvzwrite_clnup.c0000644000032200000250000000346312201176157017270 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "zwrite.h" #include "error.h" #include "change_reg.h" #include "gvzwrite_clnup.h" #include "filestruct.h" #include "gdscc.h" #include "jnl.h" GBLREF gv_namehead *gv_target; GBLREF gv_namehead *reset_gv_target; GBLREF gv_key *gv_currkey; GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF gvzwrite_datablk *gvzwrite_block; GBLREF gd_binding *gd_map; GBLREF gd_binding *gd_map_top; void gvzwrite_clnup(void) { gv_key *old; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; gv_cur_region = gvzwrite_block->gd_reg; change_reg(); assert(reset_gv_target == ((gv_namehead *)gvzwrite_block->old_targ)); if (NULL != gvzwrite_block->old_key) { old = (gv_key *)gvzwrite_block->old_key; memcpy(&gv_currkey->base[0], &old->base[0], old->end + 1); gv_currkey->end = old->end; gv_currkey->prev = old->prev; gd_map = gvzwrite_block->old_map; gd_map_top = gvzwrite_block->old_map_top; free(gvzwrite_block->old_key); gvzwrite_block->old_key = gvzwrite_block->old_targ = (unsigned char *)NULL; gvzwrite_block->subsc_count = 0; TREF(gv_last_subsc_null) = gvzwrite_block->gv_last_subsc_null; TREF(gv_some_subsc_null) = gvzwrite_block->gv_some_subsc_null; } RESET_GV_TARGET(DO_GVT_GVKEY_CHECK); } fis-gtm-V6.0-003/sr_port/gvzwrite_clnup.h0000644000032200000250000000103412201176157017265 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __GVZWRITE_CLNUP_H__ #define __GVZWRITE_CLNUP_H__ void gvzwrite_clnup(void); #endif fis-gtm-V6.0-003/sr_port/h.mpt0000644000032200000250000000352712201176157015014 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1987, 2003 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %H ;GT.M %H utility - date and time conversions to and from $H format ;invoke with %DT in $H day format at %CDS to set %DAT mm/dd/yyyy ;invoke with %TM in $H time format at %CTS to set %TIM hh:mm:ss ;invoke with %DT in mm/dd/yy[yy] format at %CDN to set %DAT to $H form ;invoke with %TM in hh:mm:ss format at %CTN to set %TIM to $H format ;the labels without the % are corresponding functions q %CDS S %DAT=$$CDS(%DT) q CDS(dt) i dt'<0,dt<94658 q +$zd(dt,"MM")_"/"_+$zd(dt,"DD")_$zd(dt,"/YEAR") q "" ; %CTS s %TIM=$$CTS(%TM) q CTS(tm) i tm'<0,tm<86400 q $zd(","_tm,"24:60:SS") q "" ; %CDN s %DAT=$$CDN(%DT) q CDN(dt) n cc,dat,dd,mm,yy,dh,zd s mm=+dt,dd=$p(dt,"/",2),yy=$p(dt,"/",3),dat="" i mm<1 q "" i mm>13 q "" i dd<1 q "" s zd=$ZDATEFORM i $l(yy)<3 d . s dh=$H . s yy=yy+(100*$S('zd:19,(zd>1840)&($L(zd)=4):($E(zd,1,2)+$S($E(zd,3,4)'>yy:0,1:1)),1:$E($ZDATE(dh,"YEAR"),1,2))) ; 20th rolling current century i dd>$s(+mm'=2:$e(303232332323,mm)+28,yy#4:28,yy#100:29,yy#400:28,1:29) q "" s dat=yy-1841,mm=mm-1,cc=1 i dat<0 s dd=dd-1,cc=-1 s dat=dat\4*1461+(dat#4-$s(dat'<0:0,1:4)*365)+(mm*30)+$e(10112234455,mm)+dd-(yy-1800\100-(yy-1600\400)) i yy#4,mm>1 s dat=dat-cc i yy#100=0,mm<2,yy#400 s dat=dat+cc q dat ; %CTN s %TIM=$$CTN(%TM) q CTN(tm) n h,m,s s h=+tm,m=$p(tm,":",2),s=$p(tm,":",3) i h'<0,h<24,m'<0,m<60,s'<0,s<60 q h*60+m*60+s q "" fis-gtm-V6.0-003/sr_port/hashtab.h0000644000032200000250000001211512201176157015617 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef HASHTAB_COMMON_H #define HASHTAB_COMMON_H #define HASHTAB_COMPACT FALSE #define HASHTAB_NO_COMPACT TRUE #define HASHTAB_SPARE_TABLE FALSE #define HASHTAB_NO_SPARE_TABLE TRUE #define HT_VALUE_DUMMY ((void *) 1L) /* It is required not to have 0 or -1 for this macro. * This is passed when hashtable callers want to use hash table just for the keys. * Say, database code wants to create a list of blocks being read for a transactions. * There is no corresponding value associated. For that case HT_VALUE_DUMMY will be passed as "value". */ #define HT_DELETED_ENTRY ((void *) -1L) /* Note: We may need to change the above during 64-bit port */ #define HTENT_MARK_DELETED(tabent) (HT_DELETED_ENTRY == (tabent)->value) #define HT_LOAD_FACTOR 50 #define HT_REHASH_FACTOR (HT_LOAD_FACTOR/2) #define HT_REHASH_TABLE_SIZE(table) MIN(table->size, table->count * 4) #define INSERT_HTENT(table, tabent, hkey, value) \ { \ if (HT_DELETED_ENTRY == (tabent)->value) \ (table)->del_count--; \ (tabent)->key = *hkey; \ (tabent)->value = value; \ (table)->count++; \ } #define COMPACT_NEEDED(table) ((!(table)->dont_compact) && (((table)->del_count > (table)->cmp_trigger_size) || \ (((table)->initial_size < (table)->size ) && ((table)->count < ((table)->cmp_trigger_size / 2))))) /* * This macro is used by callers outside of the hash table implementation to indicate * whether they will request the free of the hash table base at a later point in time or * if it should be released by the hash table implementation during an expansion/compaction. * They must call FREE_BASE_HASHTAB() later to release the base otherwise the memory * will be leaked. */ #define DEFER_BASE_REL_HASHTAB(table, deferit) \ { \ (table)->defer_base_release = deferit; \ } /* * This macro is used by callers outside of the hash table implementation to indicate * that they are no longer using the hash table base. This function only provides a "hint" to the * hash table implementation, i.e., the base can now be freed when appropriate. This can * mean when this function is called if we are not keeping spare bases or at a potentially * much later time if we are using a spare base. */ #define FREE_BASE_HASHTAB(table, base) \ { \ if ((table)->dont_keep_spare_table) \ free(base); \ } /* Different Hash Computation Macros for Strings: All these were experminted and result is given in the design document of V5.0-000 longname project. For now we decided to use ELF_HASH. Do not remove the commented out section below which has all the hash functions. We can remove them when we are certain that ELF_HASH is the best choice for us. */ #define STR_HASH ELF_HASH #define ELF_HASH(sptr, len, hash, init_hashval) \ { \ uint4 tempint; \ char *curr, *top; \ uint4 hcode; \ for (hcode = init_hashval, curr = sptr, top = sptr + len; curr < top; curr++) \ { \ hcode = (hcode << 4) + *curr; \ if (tempint = (hcode & 0xF0000000)) \ hcode ^= tempint >> 24; \ hcode &= ~tempint; \ } \ hash = hcode; \ } /* #define CHAR_BITS 8 #define BITS_IN_int (SIZEOF(int) * CHAR_BITS) #define THREE_QUARTERS (BITS_IN_int * 3 / 4) #define ONE_EIGHTH (BITS_IN_int / 8) #define HIGH_BITS (~((unsigned int)(~0) >> ONE_EIGHTH )) #define PJW_HASH(sptr, len, hash, init_hashval) \ { \ uint4 tempint; \ char *curr, *top; \ hash = init_hashval; \ for (curr = sptr, top = sptr + len; curr < top; curr++) \ { \ hash = ( hash << ONE_EIGHTH ) + *curr; \ if ((tempint = hash & HIGH_BITS ) != 0 ) \ hash = ( hash ^ ( tempint >> THREE_QUARTERS )) & ~HIGH_BITS;\ } \ } #define MISC1_HASH(sptr, len, hash, init_hashval) \ { \ char *curr; \ curr = sptr; \ int indx; \ hash = init_hashval; \ for (indx = 0; indx < len; indx++, curr++) \ hash += (*curr * (len - indx)); \ } #define MISC2_HASH(sptr, len, hash, init_hashval) \ { \ char *curr; \ curr = sptr; \ int indx; \ hash = init_hashval; \ for (indx = 0; indx < len; indx++, curr++) \ hash = hash*31 + *curr; \ } #define CURR_HASH(sptr, len, hash, init_hashval) \ { \ char *ptr, tchar[MAXLEN]; \ int indx; \ uint4 temp1 = 0; \ uint4 temp2 = 0; \ memset(tchar, 0, MAXLEN); \ memcpy(tchar, sptr, len); \ ptr = &tchar[0]; \ for ( indx = 0; indx < 4; indx++, ptr++) \ temp1 = temp1 * 256 + *ptr ; \ for ( ; indx < 8; indx++, ptr++) \ temp2 = temp2 * 256 + *ptr ; \ hash = (temp1 << 1) ^ (temp2) ; \ } */ #endif fis-gtm-V6.0-003/sr_port/hashtab_addr.c0000644000032200000250000000136412201176157016610 0ustar librarygtc/**************************************************************** * * * Copyright 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "min_max.h" #include "gtm_string.h" #include "error.h" #include "send_msg.h" #include "gtmmsg.h" #include "hashtab.h" #include "hashtab_addr.h" #define ADDR_HASH /* The below include generates the hash table routines for the "addr" hash type */ #include "hashtab_implementation.h" fis-gtm-V6.0-003/sr_port/hashtab_addr.h0000644000032200000250000000620712201176157016616 0ustar librarygtc/**************************************************************** * * * Copyright 2009, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef HASHTAB_ADDR_H #define HASHTAB_ADDR_H typedef struct { char *key; /* Note this is the actual key, not its address */ void *value; } ht_ent_addr; typedef struct hash_table_addr_struct { ht_ent_addr *base; /* base of array of hent_* entries */ ht_ent_addr *top; /* top of array of hent_* entries */ unsigned int size; /* Hash table size */ unsigned int initial_size; /* Hash table initial size */ ht_ent_addr *spare_base; /* spare array of hent_* entries */ unsigned int spare_base_size;/* size of spare array */ boolean_t dont_compact; /* if set, never perform compaction */ boolean_t dont_keep_spare_table; /* if set, don't keep a spare table */ boolean_t defer_base_release; /* if set don't release base, caller will free_base...() later */ unsigned int count; /* Number of valid entries */ unsigned int del_count; /* Number of entries marked deleted. */ unsigned int exp_trigger_size;/* When exp_trigger_size entried are used, expand table */ unsigned int cmp_trigger_size;/* When cmp_trigger_size reached compact table */ sm_uc_ptr_t entry_passed_thru;/* Bit vector used to determine whether a particular */ /* ht_ent has been involved in a collision (meaning that */ /* this value can't be marked empty on delete */ } hash_table_addr; #define HTENT_EMPTY_ADDR(tabent, type, htvalue) (!(htvalue = (type *)(tabent)->value)) #define HTENT_MARK_EMPTY_ADDR(tabent) (tabent)->value = (void *) 0L #define HTENT_VALID_ADDR(tabent, type, htvalue) ((!HTENT_EMPTY_ADDR(tabent, type, htvalue)) && (HT_DELETED_ENTRY != htvalue)) /* Do not downcast when INT8_HASH, 8 byte int, is defined */ #ifdef INT8_HASH #define HASHTAB_UINTCAST(X) X #else #define HASHTAB_UINTCAST(X) UINTCAST(X) #endif #ifdef GTM64 # define COMPUTE_HASH_ADDR(hkey, hash) \ hash = HASHTAB_UINTCAST(((((gtm_uint64_t)(*hkey)) & 0xFFFFFFFF) ^ (((gtm_uint64_t)(*hkey)) >> 31))) #else # define COMPUTE_HASH_ADDR(hkey, hash) hash = ((uint4)(*hkey)) #endif /* Prototypes for addr hash routines. See hashtab_implementation.h for detail interface and implementation */ void init_hashtab_addr(hash_table_addr *table, int minsize, boolean_t dont_compact, boolean_t dont_keep_spare_table); void expand_hashtab_addr(hash_table_addr *table, int minsize); boolean_t add_hashtab_addr(hash_table_addr *table, char **key, void *value, ht_ent_addr **tabentptr); void *lookup_hashtab_addr(hash_table_addr *table, char **key); void delete_hashtab_ent_addr(hash_table_addr *table, ht_ent_addr *tabent); boolean_t delete_hashtab_addr(hash_table_addr *table, char **key); void free_hashtab_addr(hash_table_addr *table); void reinitialize_hashtab_addr(hash_table_addr *table); void compact_hashtab_addr(hash_table_addr *table); #endif /* HASHTAB_ADDR_H */ fis-gtm-V6.0-003/sr_port/hashtab_implementation.h0000644000032200000250000006243612201176157020737 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* Uniform Hash Implementation Hash table code supports the following data types as key: a) int4 b) int8 c) UINTPTR_T d) object code e) variable name. f) local process address (supported via define using either int4 or int8 as type Using pre-processor following four C files will expand five sets of routines. a) hashtab_int4.c b) hashtab_int8.c c) hashtab_addr.c d) hashtab_mname.c e) hashtab_objcode.c Restrictions : We assumed that no user of hash needs to add "key, value" pair where both are null. We examined that GT.M does not need to have such cases. We can add 0 as valid data for int4 and int8, however, it must always have non-zero value. We can add 0 length string as "key" in objcode, however, it must always have non-zero length value. We know object code cannot be 0 length, so even object source (key) is of 0 length, we are fine. GT.M cannot have 0 length mname. So "key" for mname cannot be 0 length. (If we want to remove above restriction, an extra field is needed for HT_ENT) */ #include "mdef.h" #include "gtm_malloc.h" /* For raise_gtmmemory_error() definition */ #include "bit_set.h" #include "gtmio.h" #include "have_crit.h" LITREF int ht_sizes[]; #define DEBUGHASHTABLE 0 #if defined(INT4_HASH) # define HT_KEY_T uint4 # define HT_ENT ht_ent_int4 # define HASH_TABLE hash_table_int4 # define HTENT_KEY_MATCH(tabent, hkey) ((tabent)->key == (*hkey)) # define FIND_HASH(hkey, hash) COMPUTE_HASH_INT4(hkey, hash) # define HTENT_EMPTY HTENT_EMPTY_INT4 # define HTENT_MARK_EMPTY HTENT_MARK_EMPTY_INT4 # define HTENT_VALID HTENT_VALID_INT4 # define INIT_HASHTAB init_hashtab_int4 # define INIT_HASHTAB_INTL init_hashtab_intl_int4 # define EXPAND_HASHTAB expand_hashtab_int4 # define ADD_HASHTAB add_hashtab_int4 # define ADD_HASHTAB_INTL add_hashtab_intl_int4 # define LOOKUP_HASHTAB lookup_hashtab_int4 # define DELETE_HASHTAB_ENT delete_hashtab_ent_int4 # define DELETE_HASHTAB delete_hashtab_int4 # define FREE_HASHTAB free_hashtab_int4 # define REINITIALIZE_HASHTAB reinitialize_hashtab_int4 # define COMPACT_HASHTAB compact_hashtab_int4 #elif defined(INT8_HASH) # define HT_KEY_T gtm_uint64_t # define HT_ENT ht_ent_int8 # define HASH_TABLE hash_table_int8 # define HTENT_KEY_MATCH(tabent, hkey) ((tabent)->key == (*hkey)) # define FIND_HASH(hkey, hash) COMPUTE_HASH_INT8(hkey, hash) # define HTENT_EMPTY HTENT_EMPTY_INT8 # define HTENT_MARK_EMPTY HTENT_MARK_EMPTY_INT8 # define HTENT_VALID HTENT_VALID_INT8 # define INIT_HASHTAB init_hashtab_int8 # define INIT_HASHTAB_INTL init_hashtab_intl_int8 # define EXPAND_HASHTAB expand_hashtab_int8 # define ADD_HASHTAB add_hashtab_int8 # define ADD_HASHTAB_INTL add_hashtab_intl_int8 # define LOOKUP_HASHTAB lookup_hashtab_int8 # define DELETE_HASHTAB_ENT delete_hashtab_ent_int8 # define DELETE_HASHTAB delete_hashtab_int8 # define FREE_HASHTAB free_hashtab_int8 # define REINITIALIZE_HASHTAB reinitialize_hashtab_int8 # define COMPACT_HASHTAB compact_hashtab_int8 #elif defined(ADDR_HASH) # define HT_KEY_T char * # define HT_ENT ht_ent_addr # define HASH_TABLE hash_table_addr # define HTENT_KEY_MATCH(tabent, hkey) ((tabent)->key == (*hkey)) # define FIND_HASH(hkey, hash) COMPUTE_HASH_ADDR(hkey, hash) # define HTENT_EMPTY HTENT_EMPTY_ADDR # define HTENT_MARK_EMPTY HTENT_MARK_EMPTY_ADDR # define HTENT_VALID HTENT_VALID_ADDR # define INIT_HASHTAB init_hashtab_addr # define INIT_HASHTAB_INTL init_hashtab_intl_addr # define EXPAND_HASHTAB expand_hashtab_addr # define ADD_HASHTAB add_hashtab_addr # define ADD_HASHTAB_INTL add_hashtab_intl_addr # define LOOKUP_HASHTAB lookup_hashtab_addr # define DELETE_HASHTAB_ENT delete_hashtab_ent_addr # define DELETE_HASHTAB delete_hashtab_addr # define FREE_HASHTAB free_hashtab_addr # define REINITIALIZE_HASHTAB reinitialize_hashtab_addr # define COMPACT_HASHTAB compact_hashtab_addr #elif defined(MNAME_HASH) # define HT_KEY_T mname_entry # define HT_ENT ht_ent_mname # define HASH_TABLE hash_table_mname # define HTENT_KEY_MATCH(tabent, hkey) \ ( ((tabent)->key.hash_code == (hkey)->hash_code) \ && ((tabent)->key.var_name.len == (hkey)->var_name.len) \ && (0 == memcmp((tabent)->key.var_name.addr, (hkey)->var_name.addr, (hkey)->var_name.len)) \ ) # define FIND_HASH(hkey, hash) {assert((hkey)->hash_code); hash = (hkey)->hash_code;} /* Note: FIND_HASH for mname does not compute hash_code. Callers must make sure it is already computed. * FIND_HASH for objcode or int4 or int8 computes hash code * for every function call of add or lookup or delete. */ # define HTENT_EMPTY HTENT_EMPTY_MNAME # define HTENT_MARK_EMPTY HTENT_MARK_EMPTY_MNAME # define HTENT_VALID HTENT_VALID_MNAME # define INIT_HASHTAB init_hashtab_mname # define INIT_HASHTAB_INTL init_hashtab_intl_mname # define EXPAND_HASHTAB expand_hashtab_mname # define ADD_HASHTAB add_hashtab_mname # define ADD_HASHTAB_INTL add_hashtab_intl_mname # define LOOKUP_HASHTAB lookup_hashtab_mname # define DELETE_HASHTAB_ENT delete_hashtab_ent_mname # define DELETE_HASHTAB delete_hashtab_mnamen # define FREE_HASHTAB free_hashtab_mname # define REINITIALIZE_HASHTAB reinitialize_hashtab_mname # define COMPACT_HASHTAB compact_hashtab_mname #elif defined(STRING_HASH) # define HT_KEY_T stringkey # define HT_ENT ht_ent_str # define HASH_TABLE hash_table_str # define HTENT_KEY_MATCH(tabent, hkey) \ (((tabent)->key.hash_code == (hkey)->hash_code) \ && ((tabent)->key.str.len == (hkey)->str.len) \ && (0 == memcmp((tabent)->key.str.addr, (hkey)->str.addr, (hkey)->str.len)) \ ) # define FIND_HASH(hkey, hash) hash = (hkey)->hash_code /* Note: FIND_HASH for str does not compute hash_code. Callers must make sure it is already computed */ # define HTENT_EMPTY HTENT_EMPTY_STR # define HTENT_MARK_EMPTY HTENT_MARK_EMPTY_STR # define HTENT_VALID HTENT_VALID_STR # define INIT_HASHTAB init_hashtab_str # define INIT_HASHTAB_INTL init_hashtab_intl_str # define EXPAND_HASHTAB expand_hashtab_str # define ADD_HASHTAB add_hashtab_str # define ADD_HASHTAB_INTL add_hashtab_intl_str # define LOOKUP_HASHTAB lookup_hashtab_str # define DELETE_HASHTAB_ENT delete_hashtab_ent_str # define DELETE_HASHTAB delete_hashtab_str # define FREE_HASHTAB free_hashtab_str # define REINITIALIZE_HASHTAB reinitialize_hashtab_str # define COMPACT_HASHTAB compact_hashtab_str #elif defined (OBJCODE_HASH) # define HT_KEY_T icode_str # define HT_ENT ht_ent_objcode # define HASH_TABLE hash_table_objcode # define HTENT_KEY_MATCH(tabent, hkey) \ (((tabent)->key.code == (hkey)->code) \ && ((tabent)->key.str.len == (hkey)->str.len) \ && (0 == memcmp((tabent)->key.str.addr, (hkey)->str.addr, (hkey)->str.len)) \ ) # define FIND_HASH(hkey, hash) COMPUTE_HASH_OBJCODE(hkey, hash) # define HTENT_EMPTY HTENT_EMPTY_OBJCODE # define HTENT_MARK_EMPTY HTENT_MARK_EMPTY_OBJCODE # define HTENT_VALID HTENT_VALID_OBJCODE # define INIT_HASHTAB init_hashtab_objcode # define INIT_HASHTAB_INTL init_hashtab_intl_objcode # define EXPAND_HASHTAB expand_hashtab_objcode # define ADD_HASHTAB add_hashtab_objcode # define ADD_HASHTAB_INTL add_hashtab_intl_objcode # define LOOKUP_HASHTAB lookup_hashtab_objcode # define DELETE_HASHTAB_ENT delete_hashtab_ent_objcode # define DELETE_HASHTAB delete_hashtab_objcode # define FREE_HASHTAB free_hashtab_objcode # define REINITIALIZE_HASHTAB reinitialize_hashtab_objcode # define COMPACT_HASHTAB compact_hashtab_objcode #else #error undefined hash #endif #if DEBUGHASHTABLE /* Debug FPRINTF with pre and post requisite flushing of appropriate streams */ #define DBGHASHTAB(x) {flush_pio(); FPRINTF x; FFLUSH(stderr);} #else #define DBGHASHTAB(x) #endif /* We use DOUBLE HASHING algorithm. After first collision we calculate * rehash factor (rhfact) that is a function of the hash value (even though for * correctness purposes any number from 1 to prime-1 should be fine) to * avoid primary and secondary clustering. * The SET_REHASH_INDEX is actually equivalent to ht_index = (ht_index + rhfact) % prime; */ #define SET_REHASH_FACTOR(rhfact, hash, prime) (rhfact) = (1 + ((hash) % ((prime) - 1))) #define SET_REHASH_INDEX(ht_index, rhfact, prime) \ assert((rhfact) < (prime)); \ assert((ht_index) < (prime)); \ (ht_index) += (rhfact); \ if ((ht_index) >= (prime)) \ (ht_index) -= (prime); #define RETURN_IF_ADDED(table, tabent, hkey, value) \ { \ void *dummy; \ if (HTENT_EMPTY(tabent, void, dummy)) \ { \ if (NULL != first_del_ent) \ tabent = first_del_ent; \ INSERT_HTENT(table, tabent, hkey, value); \ return TRUE; \ } \ if (!HTENT_MARK_DELETED(tabent)) \ { \ if (HTENT_KEY_MATCH(tabent, hkey)) \ return FALSE; /* valid and matched */ \ } else if (NULL == first_del_ent) \ first_del_ent = tabent; \ } #define RETURN_IF_LOOKUP_DONE(tabent, hkey) \ { \ void *dummy; \ if (HTENT_EMPTY(tabent, void, dummy)) \ return NULL; \ if (!HTENT_MARK_DELETED(tabent) && HTENT_KEY_MATCH(tabent, hkey)) \ return tabent; /* valid and matched */ \ } #define DELETE_HTENT(table, tabent) \ { \ uint4 entry_num; \ sm_uc_ptr_t ptr; \ \ entry_num = (uint4)((tabent) - (table)->base); \ /* Compute offset into bitmap for this entry */ \ ptr = (table)->entry_passed_thru + (entry_num / BITS_PER_UCHAR); \ if ((1 << (entry_num & 7)) & *ptr) \ { \ (tabent)->value = HT_DELETED_ENTRY; \ (table)->del_count++; \ } else \ HTENT_MARK_EMPTY(tabent); \ (table)->count--; \ assert(((table)->count + (table)->del_count) <= (table)->size); \ } #define RETURN_IF_DELETED(table, tabent, hkey) \ { \ void *dummy; \ if (HTENT_EMPTY(tabent, void, dummy)) \ return FALSE; \ if (!HTENT_MARK_DELETED(tabent) && HTENT_KEY_MATCH(tabent, hkey)) \ { \ DELETE_HTENT(table, tabent); \ if (COMPACT_NEEDED(table)) \ COMPACT_HASHTAB(table); \ return TRUE; \ } \ } #define HT_FIELDS_COMMON_INIT(table) \ table->exp_trigger_size = (double)table->size * HT_LOAD_FACTOR / 100.0; \ table->cmp_trigger_size = (double)table->size * HT_REHASH_FACTOR / 100.0; \ table->count = table->del_count = 0; /* Prototypes */ void INIT_HASHTAB(HASH_TABLE *table, int minsize, boolean_t dont_compact, boolean_t dont_keep_spare_table); STATICFNDCL void INIT_HASHTAB_INTL(HASH_TABLE *table, int minsize, HASH_TABLE *old_table); void EXPAND_HASHTAB(HASH_TABLE *table, int minsize); boolean_t ADD_HASHTAB(HASH_TABLE *table, HT_KEY_T *key, void *value, HT_ENT **tabentptr); STATICFNDCL boolean_t ADD_HASHTAB_INTL(HASH_TABLE *table, HT_KEY_T *key, void *value, HT_ENT **tabentptr, boolean_t changing_table_size); void *LOOKUP_HASHTAB(HASH_TABLE *table, HT_KEY_T *key); void DELETE_HASHTAB_ENT(HASH_TABLE *table, HT_ENT *tabent); boolean_t DELETE_HASHTAB(HASH_TABLE *table, HT_KEY_T *key); void FREE_HASHTAB(HASH_TABLE *table); void REINITIALIZE_HASHTAB(HASH_TABLE *table); void COMPACT_HASHTAB(HASH_TABLE *table); error_def(ERR_HTOFLOW); error_def(ERR_HTSHRINKFAIL); /* This is used by external callers to initially setup the hash table. */ void INIT_HASHTAB(HASH_TABLE *table, int minsize, boolean_t dont_compact, boolean_t dont_keep_spare_table) { int index; for (index = 0, table->initial_size = ht_sizes[index]; table->initial_size && table->initial_size < minsize; index++) table->initial_size = ht_sizes[index]; table->initial_size = table->initial_size ? table->initial_size : minsize; table->dont_compact = dont_compact; table->dont_keep_spare_table = dont_keep_spare_table; table->defer_base_release = FALSE; INIT_HASHTAB_INTL(table, minsize, NULL); } /* This routine initializes hash table. It must be called once before hashing can be used. Note that the ht_sizes array is defined in mtables.c. A NULL old_table pointer means that the table is being setup for the first time. */ STATICFNDEF void INIT_HASHTAB_INTL(HASH_TABLE *table, int minsize, HASH_TABLE *old_table) { unsigned int cur_ht_size, prior_size; int index; boolean_t dont_keep_spare_table; DBGHASHTAB((stderr, "INIT_HASHTAB:table(%lx) minsize(%d) old_table(%lx)\n", table, minsize, old_table)); /* If this is the first time the hash table is being initialized (old_table == NULL), then look up the * actual hash table size in ht_sizes based on the requested size (minsize). * * We dont want the hash table to shrink too fast so if we are changing the size of an existing hash table: * 1) if the requested size is not smaller than half of the previous size: * a) pick the actual size from ht_sizes based on the requested size. * 2) if the requested size is smaller than half of the previous size: * b) pick the previous entry (from the previous size (old_table->size) in ht_sizes. */ if ((NULL == old_table) || (minsize > (old_table->size / 2))) { for (index = 0, cur_ht_size = ht_sizes[index]; cur_ht_size && cur_ht_size < minsize; index++) cur_ht_size = ht_sizes[index]; } else /* don't shrink too fast ! */ { prior_size = ht_sizes[0]; for (index = 1, cur_ht_size = ht_sizes[index]; cur_ht_size && cur_ht_size < old_table->size; index++) { cur_ht_size = ht_sizes[index]; prior_size = ht_sizes[index-1]; } cur_ht_size = prior_size; cur_ht_size = (cur_ht_size > old_table->initial_size) ? cur_ht_size : old_table->initial_size; } if (cur_ht_size) { DBGHASHTAB((stderr, "INIT_HASHTAB:table size will be (%d) for table(%lx)\n", cur_ht_size, old_table?old_table:table)); table->base = NULL; table->spare_base = NULL; table->spare_base_size = 0; /* a fresh new hash table */ /* If this is is an initialization from a caller outside of the hash table implementation then * old_table == NULL since there is no previous hash table. In this case the external versions of * INIT_HASHTAB will setup table with values for dont_compact and dont_keep_spare_table. Otherwise, * we can use them from the old_table. */ dont_keep_spare_table = old_table ? old_table->dont_keep_spare_table:table->dont_keep_spare_table; if (!dont_keep_spare_table) { DBGHASHTAB((stderr, "INIT_HASHTAB: old_table(%lx)\n", old_table)); if (NULL != old_table) { DBGHASHTAB((stderr, "INIT_HASHTAB: cur_ht_size(%d), spare_base_size(%d)\n", cur_ht_size, old_table->spare_base_size)); if (old_table->spare_base_size == cur_ht_size) { /* We can use the spare table since it is the size we would have malloc'd */ table->base = old_table->spare_base; DBGHASHTAB((stderr, "INIT_HASHTAB: use spare table: base(%lx)\n", table->base)); /* We no longer have a spare */ old_table->spare_base = NULL; old_table->spare_base_size = 0; } else /* no luck on the reuse thing */ if (NULL != old_table->spare_base) /* so free it if it exists */ { DBGHASHTAB((stderr, "INIT_HASHTAB: table(%lx): free spare_base(%lx)\n", old_table, old_table->spare_base)); free(old_table->spare_base); old_table->spare_base = NULL; old_table->spare_base_size = 0; } } } if (NULL == table->base) { /* Let's make sure we have a HT_ENT table. We are here either thru dont_keep_spare_table, old_table == NULL, or wrong-sized spare */ table->base = (void *)malloc((cur_ht_size * SIZEOF(HT_ENT)) + ROUND_UP(cur_ht_size, BITS_PER_UCHAR)); DBGHASHTAB((stderr, "INIT_HASHTAB: malloc a new table: table(%lx) base(%lx)\n", old_table?old_table:table, table->base)); } memset((char *)table->base, 0, (cur_ht_size * SIZEOF(HT_ENT)) + ROUND_UP(cur_ht_size, BITS_PER_UCHAR)); table->size = cur_ht_size; if (NULL != old_table) { table->initial_size = old_table->initial_size; table->dont_compact = old_table->dont_compact; table->dont_keep_spare_table = old_table->dont_keep_spare_table; table->defer_base_release = old_table->defer_base_release; } table->top = table->base + cur_ht_size; table->entry_passed_thru = (sm_uc_ptr_t) table->top; DBGHASHTAB((stderr, "INIT_HASHTAB: entry_passed_thru points to (%lx)\n", table->entry_passed_thru)); HT_FIELDS_COMMON_INIT(table); } else { DBGHASHTAB((stderr, "INIT_HASHTAB:HTOFLOW: minsize(%d) cur_ht_size(%d)\n", minsize, cur_ht_size)); send_msg(VARLSTCNT(3) ERR_HTOFLOW, 1, minsize); rts_error(VARLSTCNT(3) ERR_HTOFLOW, 1, minsize); } } /* Description: Expand the hash table with at least minsize. This can do either expansion or compaction, which depends on old table size and minsize passed. It creates a new table and move old element to new table. It deallocate old table entries */ void EXPAND_HASHTAB(HASH_TABLE *table, int minsize) { HASH_TABLE newtable, temptab; HT_ENT *tabent, *topent, *dummy; boolean_t added; void *htval; CONDITION_HANDLER(hashtab_rehash_ch); ESTABLISH(hashtab_rehash_ch); DBGHASHTAB((stderr, "EXPAND_HASHTAB:ENTER: table: table(%lx) base (%lx), spare_base(%lx), spare_base_size(%d), \n", table, table->base, table->spare_base, table->spare_base_size)); /* The next line keeps the HP-UX Itanium compiler in pro happy. This initialization is done is INIT_HASHTAB_INTL* * but this line is placed here to appease the compiler. */ newtable.dont_keep_spare_table = table->dont_keep_spare_table; INIT_HASHTAB_INTL(&newtable, minsize, table); REVERT; if (0 < table->count) /* if no active entries then nothing to move */ for (tabent = table->base, topent = table->top; tabent < topent; tabent++) { if (HTENT_VALID(tabent, void, htval)) { /* Place location of new ht_ent entry into value location of existing ht entry */ added = ADD_HASHTAB_INTL(&newtable, &tabent->key, htval, (HT_ENT **)&tabent->value, TRUE); assert(added); } } if (!table->defer_base_release && table->dont_keep_spare_table) { DBGHASHTAB((stderr, "EXPAND_HASHTAB:free base (%lx) \n", table->base)); free(table->base); /* Deallocate old table entries */ } if (!table->dont_keep_spare_table) { temptab.spare_base = table->base; /* let's keep a spare in case we just have to clear the DELETED entries */ temptab.spare_base_size = table->size; } *table = newtable; if (table->dont_keep_spare_table) { table->spare_base = NULL; table->spare_base_size = 0; } else { table->spare_base = temptab.spare_base; /* let's keep a spare in case we just have to clear the DELETED entries */ table->spare_base_size = temptab.spare_base_size; } DBGHASHTAB((stderr, "EXPAND_HASHTAB:EXIT: table: table(%lx ) base (%lx), spare_base(%lx), spare_base_size(%d) \n", table, table->base, table->spare_base, table->spare_base_size)); } /* Description: Adds a key and corresponding value in hash table. If key is already present, return false. If key is not present, it adds the entry and returns true. As a side-effect tabent points to the matched entry or added entry */ /* This flavor is used by external caller (outside of the hash table implementation */ boolean_t ADD_HASHTAB(HASH_TABLE *table, HT_KEY_T *key, void *value, HT_ENT **tabentptr) { return ADD_HASHTAB_INTL(table, key, value, tabentptr, FALSE); } /* This flavor is used by internal callers, for example when adding entries during a change of hash table size. */ STATICFNDEF boolean_t ADD_HASHTAB_INTL(HASH_TABLE *table, HT_KEY_T *key, void *value, HT_ENT **tabentptr, boolean_t changing_table_size) { #ifdef INT8_HASH gtm_uint64_t hash, ht_index, save_ht_index, prime, rhfact; #else uint4 hash, ht_index, save_ht_index, prime, rhfact; #endif /* INT8_HASH */ HT_ENT *oldbase, *first_del_ent, *tabbase; if (!changing_table_size && (table->count >= table->exp_trigger_size)) { oldbase = table->base; EXPAND_HASHTAB(table, table->size + 1); if (oldbase == table->base) /* expansion failed */ { if (table->exp_trigger_size >= table->size) /* Note this error routine will use the memory error parameters recorded when the memory error was first raised by EXPAND_HASHTAB() above so the error will appear as if it had occurred during that expansion attempt. */ raise_gtmmemory_error(); table->exp_trigger_size = table->size; } } first_del_ent = NULL; tabbase = &table->base[0]; prime = table->size; FIND_HASH(key, hash); ht_index = (int) (hash % prime); *tabentptr = tabbase + ht_index; RETURN_IF_ADDED(table, *tabentptr, key, value); /* We are here because collision happened. Do collision resolution */ # ifdef INT8_HASH assert(MAXUINT4 > ht_index); # endif bit_set(ht_index, table->entry_passed_thru); save_ht_index = ht_index; SET_REHASH_FACTOR(rhfact, hash, prime); SET_REHASH_INDEX(ht_index, rhfact, prime); do { *tabentptr = tabbase + ht_index; RETURN_IF_ADDED(table, *tabentptr, key, value); # ifdef INT8_HASH assert(MAXUINT4 > ht_index); # endif bit_set(ht_index, table->entry_passed_thru); SET_REHASH_INDEX(ht_index, rhfact, prime); } while(ht_index != save_ht_index); /* All entries either deleted or used. No empty frame found */ if (NULL != first_del_ent) { /* There was a deleted one we could use - reuse the deleted frame */ *tabentptr = first_del_ent; INSERT_HTENT(table, *tabentptr, key, value); return TRUE; } GTMASSERT; return FALSE; /* to prevent warnings */ } /* * Returns pointer to the value corresponding to key, if found. * Otherwise, it returns null. */ void *LOOKUP_HASHTAB(HASH_TABLE *table, HT_KEY_T *key) { # ifdef INT8_HASH gtm_uint64_t hash, ht_index, save_ht_index, prime, rhfact; # else uint4 hash, ht_index, save_ht_index, prime, rhfact; # endif /* INT8_HASH */ HT_ENT *tabent, *tabbase; tabbase = &table->base[0]; prime = table->size; FIND_HASH(key, hash); ht_index = hash % prime; tabent = tabbase + ht_index; RETURN_IF_LOOKUP_DONE(tabent, key); /* We are here because collision happened. Do collision resolution */ save_ht_index = ht_index; SET_REHASH_FACTOR(rhfact, hash, prime); SET_REHASH_INDEX(ht_index, rhfact, prime); do { tabent = tabbase + ht_index; RETURN_IF_LOOKUP_DONE(tabent, key); SET_REHASH_INDEX(ht_index, rhfact, prime); } while(ht_index != save_ht_index); return (void *)NULL; } /* Description: Deletes hash table entry from hash table (whether it was active or not). The function version is for callers outside of the hash table implementation. */ void DELETE_HASHTAB_ENT(HASH_TABLE *table, HT_ENT *tabent) { DELETE_HTENT(table, tabent); } /* * Returns TRUE if * 1) key is found and deleted successfully * or * 2) already key was marked deleted. * Otherwise, it returns FALSE * Deletion is done by marking value to HT_DELETED_ENTRY. * If there are too many deleted entry, we call expand_hashtab() to do the * compaction eliminating entries marked HT_DELETED_ENTRY * Compaction will save memory and also cause LOOKUP_HASHTAB to run faster. */ boolean_t DELETE_HASHTAB(HASH_TABLE *table, HT_KEY_T *key) { # ifdef INT8_HASH gtm_uint64_t hash, ht_index, save_ht_index, prime, rhfact; # else uint4 hash, ht_index, save_ht_index, prime, rhfact; # endif /* INT8_HASH */ HT_ENT *tabent, *tabbase; tabbase = &table->base[0]; prime = table->size; FIND_HASH(key, hash); ht_index = hash % prime; tabent = tabbase + ht_index; RETURN_IF_DELETED(table, tabent, key); /* We are here because collision happened. Do collision resolution */ save_ht_index = ht_index; SET_REHASH_FACTOR(rhfact, hash, prime); SET_REHASH_INDEX(ht_index, rhfact, prime); do { tabent = tabbase + ht_index; RETURN_IF_DELETED(table, tabent, key); SET_REHASH_INDEX(ht_index, rhfact, prime); } while(ht_index != save_ht_index); return FALSE; } /* * free memory occupied by hash table. */ void FREE_HASHTAB(HASH_TABLE *table) { if (table->base) { DBGHASHTAB((stderr, "FREE_HASHTAB:free table(%lx): base (%lx)\n", table, table->base)); free(table->base); } table->base = NULL; if (table->spare_base) { DBGHASHTAB((stderr, "FREE_HASHTAB:free table(%lx): spare_base (%lx)\n", table, table->spare_base)); free(table->spare_base); } table->spare_base = NULL; table->spare_base_size = 0; } /* * Returns TRUE, if key found and deleted successfully or already deleted. */ void REINITIALIZE_HASHTAB(HASH_TABLE *table) { memset((char *)table->base, 0, (table->size * SIZEOF(HT_ENT)) + ((table->size / BITS_PER_UCHAR) + 1)); HT_FIELDS_COMMON_INIT(table); } /* * Compact hashtable removing entries marked deleted. Note that this is necessary because * of the search algorithm in ADD_HASHTAB which needs to find if a key exists before it can * add a new entry. It keeps searching until it either finds the key, finds an empty (never * used) entry or until it searches the entire table. So we need to replentish the supply of * never used nodes. */ void COMPACT_HASHTAB(HASH_TABLE *table) { HT_ENT *oldbase; DBGHASHTAB((stderr, "COMPACT_HASHTAB: table(%lx)\n", table)); if (!table->dont_compact) { oldbase = (table)->base; EXPAND_HASHTAB(table, HT_REHASH_TABLE_SIZE(table)); if (oldbase == (table)->base) /* rehash failed */ { /* We will continue but performance will likely suffer */ send_msg(VARLSTCNT(1) ERR_HTSHRINKFAIL); (table)->cmp_trigger_size = (table)->size; } } } fis-gtm-V6.0-003/sr_port/hashtab_int4.c0000644000032200000250000000124412201176157016551 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2004 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "min_max.h" #include "gtm_string.h" #include "error.h" #include "send_msg.h" #include "gtmmsg.h" #include "hashtab.h" #include "hashtab_int4.h" #define INT4_HASH #include "hashtab_implementation.h" fis-gtm-V6.0-003/sr_port/hashtab_int4.h0000644000032200000250000000556412201176157016567 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef HASHTAB_INT4_H #define HASHTAB_INT4_H /* Note that hashtab_addr has #define references to all items in this header file. Changes/additions should be reflected there as well. */ typedef struct { uint4 key; void *value; } ht_ent_int4; typedef struct hash_table_int4_struct { ht_ent_int4 *base; /* base of array of hent_* entries */ ht_ent_int4 *top; /* top of array of hent_* entries */ unsigned int size; /* Hash table size */ unsigned int initial_size; /* Hash table initial size */ ht_ent_int4 *spare_base; /* spare array of hent_* entries */ unsigned int spare_base_size;/* size of spare array */ boolean_t dont_compact; /* if set, never perform compaction */ boolean_t dont_keep_spare_table; /* if set, don't keep a spare table */ boolean_t defer_base_release; /* if set don't release base, caller will free_base...() later */ unsigned int count; /* Number of valid entries */ unsigned int del_count; /* Number of entries marked deleted. */ unsigned int exp_trigger_size;/* When exp_trigger_size entried are used, expand table */ unsigned int cmp_trigger_size;/* When cmp_trigger_size reached compact table */ sm_uc_ptr_t entry_passed_thru;/* Bit vector used to determine whether a particular */ /* ht_ent has been involved in a collision (meaning that */ /* this value can't be marked empty on delete */ } hash_table_int4; #define HTENT_EMPTY_INT4(tabent, type, htvalue) (!(htvalue = (type *)(tabent)->value)) #define HTENT_MARK_EMPTY_INT4(tabent) (tabent)->value = (void *)0L #define HTENT_VALID_INT4(tabent, type, htvalue) (!(HTENT_EMPTY_INT4(tabent, type, htvalue)) && (HT_DELETED_ENTRY != htvalue)) #define COMPUTE_HASH_INT4(hkey, hash) hash = (*hkey) /* Prototypes for int4 hash routines. See hashtab_implementation.h for detail interface and implementation */ void init_hashtab_int4(hash_table_int4 *table, int minsize, boolean_t dont_compact, boolean_t dont_keep_spare_table); void expand_hashtab_int4(hash_table_int4 *table, int minsize); boolean_t add_hashtab_int4(hash_table_int4 *table, uint4 *key, void *value, ht_ent_int4 **tabentptr); void *lookup_hashtab_int4(hash_table_int4 *table, uint4 *key); void delete_hashtab_ent_int4(hash_table_int4 *table, ht_ent_int4 *tabent); boolean_t delete_hashtab_int4(hash_table_int4 *table, uint4 *key); void free_hashtab_int4(hash_table_int4 *table); void reinitialize_hashtab_int4(hash_table_int4 *table); void compact_hashtab_int4(hash_table_int4 *table); #endif fis-gtm-V6.0-003/sr_port/hashtab_int8.c0000644000032200000250000000124412201176157016555 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2004 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "min_max.h" #include "gtm_string.h" #include "error.h" #include "send_msg.h" #include "gtmmsg.h" #include "hashtab.h" #include "hashtab_int8.h" #define INT8_HASH #include "hashtab_implementation.h" fis-gtm-V6.0-003/sr_port/hashtab_int8.h0000644000032200000250000000601112201176157016557 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef HASHTAB_INT8_H #define HASHTAB_INT8_H /* Note that hashtab_addr has #define references to all items in this header file. Changes/additions should be reflected there as well. */ typedef struct { gtm_uint64_t key; void *value; NON_GTM64_ONLY(uint4 filler;) /* To make it 16 byte for all platforms and aligned */ } ht_ent_int8; typedef struct hash_table_int8_struct { ht_ent_int8 *base; /* base of array of hent_* entries */ ht_ent_int8 *top; /* top of array of hent_* entries */ unsigned int size; /* Hash table size */ unsigned int initial_size; /* Hash table initial size */ ht_ent_int8 *spare_base; /* spare array of hent_* entries */ unsigned int spare_base_size;/* size of spare array */ boolean_t dont_compact; /* if set, never perform compaction */ boolean_t dont_keep_spare_table; /* if set, don't keep a spare table */ boolean_t defer_base_release; /* if set don't release base, caller will free_base...() later */ unsigned int count; /* Number of valid entries */ unsigned int del_count; /* Number of entries marked deleted. */ unsigned int exp_trigger_size;/* When exp_trigger_size entried are used, expand table */ unsigned int cmp_trigger_size;/* When cmp_trigger_size reached compact table */ sm_uc_ptr_t entry_passed_thru;/* Bit vector used to determine whether a particular */ /* ht_ent has been involved in a collision (meaning that */ /* this value can't be marked empty on delete */ } hash_table_int8; #define HTENT_EMPTY_INT8(tabent, type, htvalue) (!(htvalue = (type *)(tabent)->value)) #define HTENT_MARK_EMPTY_INT8(tabent) (tabent)->value = (void *)0L #define HTENT_VALID_INT8(tabent, type, htvalue) ((!HTENT_EMPTY_INT8(tabent, type, htvalue)) && (HT_DELETED_ENTRY != htvalue)) #define COMPUTE_HASH_INT8(hkey, hash) hash = (((*hkey) & 0xFFFFFFFF) ^ (*hkey) >> 31) /* Prototypes for int8 hash routines. See hashtab_implementation.h for detail interface and implementation */ void init_hashtab_int8(hash_table_int8 *table, int minsize, boolean_t dont_compact, boolean_t dont_keep_spare_table); void expand_hashtab_int8(hash_table_int8 *table, int minsize); boolean_t add_hashtab_int8(hash_table_int8 *table, gtm_uint64_t *key, void *value, ht_ent_int8 **tabentptr); void *lookup_hashtab_int8(hash_table_int8 *table, gtm_uint64_t *key); void delete_hashtab_ent_int8(hash_table_int8 *table, ht_ent_int8 *tabent); boolean_t delete_hashtab_int8(hash_table_int8 *table, gtm_uint64_t *key); void free_hashtab_int8(hash_table_int8 *table); void reinitialize_hashtab_int8(hash_table_int8 *table); void compact_hashtab_int8(hash_table_int8 *table); #endif fis-gtm-V6.0-003/sr_port/hashtab_mname.c0000644000032200000250000000532412201176176016774 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "min_max.h" #include "gtm_string.h" #include "error.h" #include "send_msg.h" #include "gtmmsg.h" #include #include "hashtab_mname.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "alias.h" GBLREF symval *curr_symval; #define MNAME_HASH /* The below include generates the hash table routines for the "mname" hash type */ #include "hashtab_implementation.h" /* While the above include creates the bulk of the routines in this modules, for the mname hash type we add one more routine that is a wrapper for the add_hashtab_mname created above. The situation this wrapper (add_hashtab_mname_symval) covers is if the hash table was expanded, it goes back through the stack and fixes the stack references kept in l_symval entries in each stackframe. Note that there are currently no direct callers of expand_hashtab_mname() (except in op_view) that we don't already protect or of delete_hashtab_mname() or they would need similar wrappers here. */ boolean_t add_hashtab_mname_symval(hash_table_mname *table, mname_entry *key, void *value, ht_ent_mname **tabentptr) { boolean_t retval; int table_size_orig; ht_ent_mname *table_base_orig; /* Currently only two values we expect here shown below. If calls are added with other values, they need to be taken care of here and in EXPAND_HASHTAB in hashtab_implementation.h */ assert(table == &curr_symval->h_symtab || table == &curr_symval->last_tab->h_symtab); assert(FALSE == key->marked); /* remember table we started with */ table_base_orig = table->base; table_size_orig = table->size; /* We'll do the base release once we do the reparations */ DEFER_BASE_REL_HASHTAB(table, TRUE); /* Call real table function */ retval = add_hashtab_mname(table, key, value, tabentptr); /* If the hash table has not changed, we are done */ if (table_base_orig == table->base) { DEFER_BASE_REL_HASHTAB(table, FALSE); return retval; } /* Otherwise we have some work to do to repair the l_symtab entries in the stack */ als_lsymtab_repair(table, table_base_orig, table_size_orig); /* We're done with the previous base */ FREE_BASE_HASHTAB(table, table_base_orig); DEFER_BASE_REL_HASHTAB(table, FALSE); return retval; } fis-gtm-V6.0-003/sr_port/hashtab_mname.h0000644000032200000250000000623612201176157017003 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef HASHTAB_MNAME_H #define HASHTAB_MNAME_H #include "hashtab.h" /* needed for STR_HASH (in COMPUTE_HASH_MNAME) */ typedef struct { mname_entry key; void *value; } ht_ent_mname; typedef struct hash_table_mname_struct { ht_ent_mname *base; /* base of array of hent_* entries */ ht_ent_mname *top; /* top of array of hent_* entries */ unsigned int size; /* Hash table size */ unsigned int initial_size; /* Hash table initial size */ ht_ent_mname *spare_base; /* spare array of hent_* entries */ unsigned int spare_base_size;/* size of spare array */ boolean_t dont_compact; /* if set, never perform compaction */ boolean_t dont_keep_spare_table; /* if set, don't keep a spare table */ boolean_t defer_base_release; /* if set don't release base, caller will free_base...() later */ unsigned int count; /* Number of valid entries */ unsigned int del_count; /* Number of entries marked deleted. */ unsigned int exp_trigger_size;/* When exp_trigger_size entried are used, expand table */ unsigned int cmp_trigger_size;/* When cmp_trigger_size reached compact table */ sm_uc_ptr_t entry_passed_thru;/* Bit vector used to determine whether a particular */ /* ht_ent has been involved in a collision (meaning that */ /* this value can't be marked empty on delete */ } hash_table_mname; #define HTENT_EMPTY_MNAME(tabent, type, htvalue) (!(tabent)->key.var_name.len) #define HTENT_MARK_EMPTY_MNAME(tabent) (tabent)->key.var_name.len = 0 #define HTENT_VALID_MNAME(tabent, type, htvalue) ((!HTENT_EMPTY_MNAME(tabent, type, htvalue)) && \ (HT_DELETED_ENTRY != (htvalue = (type *)(tabent)->value))) #define COMPUTE_HASH_MNAME(hkey) \ { \ assert((0 < (hkey)->var_name.len) && (MAX_MIDENT_LEN >= (hkey)->var_name.len)); \ STR_HASH((hkey)->var_name.addr, (hkey)->var_name.len, ((hkey)->hash_code), 0); \ } /* Prototypes for mname hash routines. See hashtab_implementation.h for detail interface and implementation */ void init_hashtab_mname(hash_table_mname *table, int minsize, boolean_t dont_compact, boolean_t dont_keep_spare_table); void expand_hashtab_mname(hash_table_mname *table, int minsize); boolean_t add_hashtab_mname(hash_table_mname *table, mname_entry *key, void *value, ht_ent_mname **tabentptr); boolean_t add_hashtab_mname_symval(hash_table_mname *table, mname_entry *key, void *value, ht_ent_mname **tabentptr); void *lookup_hashtab_mname(hash_table_mname *table, mname_entry *key); void delete_hashtab_ent_mname(hash_table_mname *table, ht_ent_mname *tabent); boolean_t delete_hashtab_mname(hash_table_mname *table, mname_entry *key); void free_hashtab_mname(hash_table_mname *table); void reinitialize_hashtab_mname(hash_table_mname *table); void compact_hashtab_mname(hash_table_mname *table); #endif fis-gtm-V6.0-003/sr_port/hashtab_objcode.c0000644000032200000250000000125112201176157017276 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "min_max.h" #include "gtm_string.h" #include "error.h" #include "send_msg.h" #include "gtmmsg.h" #include "cache.h" #include "hashtab_objcode.h" #define OBJCODE_HASH #include "hashtab_implementation.h" fis-gtm-V6.0-003/sr_port/hashtab_objcode.h0000644000032200000250000000661612201176157017315 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef HASHTAB_OBJCODE_H #define HASHTAB_OBJCODE_H #include "hashtab.h" /* needed for STR_HASH (in COMPUTE_HASH_MNAME) */ typedef struct { icode_str key; void *value; } ht_ent_objcode; typedef struct hash_table_objcode_struct { ht_ent_objcode *base; /* base of array of hent_* entries */ ht_ent_objcode *top; /* top of array of hent_* entries */ unsigned int size; /* Hash table size */ unsigned int initial_size; /* Hash table initial size */ ht_ent_objcode *spare_base; /* spare array of hent_* entries */ unsigned int spare_base_size;/* size of spare array */ boolean_t dont_compact; /* if set, never perform compaction */ boolean_t dont_keep_spare_table; /* if set, don't keep a spare table */ boolean_t defer_base_release; /* if set don't release base, caller will free_base...() later */ unsigned int count; /* Number of valid entries */ unsigned int del_count; /* Number of entries marked deleted. */ unsigned int exp_trigger_size;/* When exp_trigger_size entried are used, expand table */ unsigned int cmp_trigger_size;/* When cmp_trigger_size reached compact table */ sm_uc_ptr_t entry_passed_thru;/* Bit vector used to determine whether a particular */ /* ht_ent has been involved in a collision (meaning that */ /* this value can't be marked empty on delete */ } hash_table_objcode; #define HTENT_EMPTY_OBJCODE(tabent, type, htvalue) (!(htvalue = (type *)(tabent)->value) && !(tabent)->key.str.len) #define HTENT_MARK_EMPTY_OBJCODE(tabent) \ { \ (tabent)->value = NULL; \ (tabent)->key.str.len = 0; \ } #define HTENT_VALID_OBJCODE(tabent, type, htvalue) ((!HTENT_EMPTY_OBJCODE(tabent, type, htvalue)) && (HT_DELETED_ENTRY != htvalue)) #define COMPUTE_HASH_OBJCODE(hkey, hash) \ { \ char *sptr; \ sptr = (hkey)->str.addr; \ if ((hkey)->str.len < SIZEOF(mident_fixed)) \ { \ STR_HASH((sptr), (hkey)->str.len, hash, 0); \ } else \ { \ STR_HASH((sptr), (SIZEOF(mident_fixed) / 2), hash, 0); \ STR_HASH(((sptr) + (hkey)->str.len - (SIZEOF(mident_fixed) / 2)), \ (SIZEOF(mident_fixed) / 2), hash, hash); \ } \ } /* Prototypes for objcode hash routines. See hashtab_implementation.h for detail interface and implementation */ void init_hashtab_objcode(hash_table_objcode *table, int minsize, boolean_t dont_compact, boolean_t dont_keep_spare_table); void expand_hashtab_objcode(hash_table_objcode *table, int minsize); boolean_t add_hashtab_objcode(hash_table_objcode *table, icode_str *key, void *value, ht_ent_objcode **tabentptr); void *lookup_hashtab_objcode(hash_table_objcode *table, icode_str *key); void delete_hashtab_ent_objcode(hash_table_objcode *table, ht_ent_objcode *tabent); boolean_t delete_hashtab_objcode(hash_table_objcode *table, icode_str *key); void free_hashtab_objcode(hash_table_objcode *table); void reinitialize_hashtab_objcode(hash_table_objcode *table); void compact_hashtab_objcode(hash_table_objcode *table); #endif fis-gtm-V6.0-003/sr_port/hashtab_rehash_ch.c0000644000032200000250000000255712201176157017627 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "error.h" #include "util.h" CONDITION_HANDLER(hashtab_rehash_ch) { /* If we cannot alloc memory during rehashing, just continue in normal program flow */ error_def(ERR_MEMORY); error_def(ERR_MEMORYRECURSIVE); error_def(ERR_HTOFLOW); START_CH; /* If we cannot allocate memory or any error while doing rehash, just abort any more rehashing. * We will continue with old table. Note that we do not ignore VMSMEMORY errors because if a * VMS_MEMORY error occurred, gtm_malloc is going to have released the memory cache trying to get * through process exit cleanly. We have no option to ignore the memory error on VMS */ if (ERR_HTOFLOW == SIGNAL || ERR_MEMORY == SIGNAL || ERR_MEMORYRECURSIVE == SIGNAL) { UNIX_ONLY(util_out_print("", RESET)); /* Prevents error message from being flushed later by rts_error() */ UNWIND(NULL, NULL); } else { NEXTCH; /* non memory related error */ } } fis-gtm-V6.0-003/sr_port/hashtab_str.c0000644000032200000250000000134712201176157016507 0ustar librarygtc/**************************************************************** * * * Copyright 2009, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "min_max.h" #include "gtm_string.h" #include "error.h" #include "send_msg.h" #include "gtmmsg.h" #include "hashtab_str.h" #define STRING_HASH /* The below include generates the hash table routines for the literal hash type */ #include "hashtab_implementation.h" fis-gtm-V6.0-003/sr_port/hashtab_str.h0000644000032200000250000000644412201176157016517 0ustar librarygtc/**************************************************************** * * * Copyright 2009, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef HASHTAB_STR_H #define HASHTAB_STR_H #include "hashtab.h" /* needed for STR_HASH (in COMPUTE_HASH_MNAME) */ typedef struct { mstr str; uint4 hash_code; GTM64_ONLY(int4 filler;) } stringkey; typedef struct { stringkey key; void *value; } ht_ent_str; typedef struct hash_table_str_struct { ht_ent_str *base; /* base of array of hent_* entries */ ht_ent_str *top; /* top of array of hent_* entries */ unsigned int size; /* Hash table size */ unsigned int initial_size; /* Hash table initial size */ ht_ent_str *spare_base; /* spare array of hent_* entries */ unsigned int spare_base_size;/* size of spare array */ boolean_t dont_compact; /* if set, never perform compaction */ boolean_t dont_keep_spare_table; /* if set, don't keep a spare table */ boolean_t defer_base_release; /* if set don't release base, caller will free_base...() later */ unsigned int count; /* Number of valid entries */ unsigned int del_count; /* Number of entries marked deleted. */ unsigned int exp_trigger_size;/* When exp_trigger_size entried are used, expand table */ unsigned int cmp_trigger_size;/* When cmp_trigger_size reached compact table */ sm_uc_ptr_t entry_passed_thru;/* Bit vector used to determine whether a particular */ /* ht_ent has been involved in a collision (meaning that */ /* this value can't be marked empty on delete */ } hash_table_str; #define HTENT_EMPTY_STR(tabent, type, htvalue) (!(tabent)->key.hash_code && !(tabent)->key.str.len) #define HTENT_MARK_EMPTY_STR(tabent) \ { \ (tabent)->key.hash_code = 0; \ (tabent)->key.str.len = 0; \ } #define HTENT_VALID_STR(tabent, type, htvalue) ((!HTENT_EMPTY_STR(tabent, type, htvalue)) && \ (HT_DELETED_ENTRY != (htvalue = (type *)(tabent)->value))) #define COMPUTE_HASH_STR(hkey) \ { \ assert((0 <= (hkey)->str.len) && (MAX_STRLEN >= (hkey)->str.len)); \ if (0 == (hkey)->str.len) \ /* Likely null string -- need nonzero hash code */ \ (hkey)->hash_code = 1; \ else \ STR_HASH((hkey)->str.addr, (hkey)->str.len, ((hkey)->hash_code), 0); \ } /* Prototypes for addr hash routines. See hashtab_implementation.h for detail interface and implementation */ void init_hashtab_str(hash_table_str *table, int minsize, boolean_t dont_compact, boolean_t dont_keep_spare_table); void expand_hashtab_str(hash_table_str *table, int minsize); boolean_t add_hashtab_str(hash_table_str *table, stringkey *key, void *value, ht_ent_str **tabentptr); void *lookup_hashtab_str(hash_table_str *table, stringkey *key); void delete_hashtab_ent_str(hash_table_str *table, ht_ent_str *tabent); boolean_t delete_hashtab_str(hash_table_str *table, stringkey *key); void free_hashtab_str(hash_table_str *table); void reinitialize_hashtab_str(hash_table_str *table); void compact_hashtab_str(hash_table_str *table); #endif /* HASHTAB_STR_H */ fis-gtm-V6.0-003/sr_port/have_crit.c0000644000032200000250000001202212201176157016141 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_inet.h" #ifdef VMS #include /* Required for gtmsource.h */ #endif #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "repl_msg.h" #include "gtmsource.h" #include "filestruct.h" #include "jnl.h" #include "dpgbldir.h" #include "have_crit.h" #include "send_msg.h" GBLREF volatile int4 crit_count; GBLREF jnlpool_addrs jnlpool; GBLREF uint4 process_id; GBLREF uint4 crit_deadlock_check_cycle; GBLREF uint4 dollar_tlevel; GBLREF unsigned int t_tries; #if defined(UNIX) && defined(DEBUG) GBLREF jnl_gbls_t jgbl; #endif error_def(ERR_MUTEXRELEASED); /* Return number of regions (including jnlpool dummy region) if have or are aquiring crit or in_wtstart * ** NOTE ** This routine is called from signal handlers and is thus called asynchronously. * If CRIT_IN_COMMIT bit is set, we check if in middle of commit (PHASE1 inside crit or PHASE2 outside crit) on some region. * If CRIT_RELEASE bit is set, we release crit on region(s) that: * 1) we hold crit on (neither CRIT_IN_COMMIT NOR CRIT_TRANS_NO_REG is specified) * 2) are part of the current transactions except those regions that are marked as being valid * to have crit in by virtue of their crit_check_cycle value is the same as crit_deadlock_check_cycle. * Note: CRIT_RELEASE implies CRIT_ALL_REGIONS * If CRIT_ALL_REGIONS bit is set, go through the entire list of regions */ uint4 have_crit(uint4 crit_state) { gd_region *r_top, *r_local; gd_addr *addr_ptr; sgmnt_addrs *csa; uint4 crit_reg_cnt = 0; /* in order to proper release the necessary regions, CRIT_RELEASE implies going through all the regions */ if (crit_state & CRIT_RELEASE) { UNIX_ONLY(assert(!jgbl.onlnrlbk)); /* should not request crit to be released if online rollback */ crit_state |= CRIT_ALL_REGIONS; } if ((0 != crit_count) && (crit_state & CRIT_HAVE_ANY_REG)) { crit_reg_cnt++; if (0 == (crit_state & CRIT_ALL_REGIONS)) return crit_reg_cnt; } for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr)) { for (r_local = addr_ptr->regions, r_top = r_local + addr_ptr->n_regions; r_local < r_top; r_local++) { if (r_local->open && !r_local->was_open) { csa = &FILE_INFO(r_local)->s_addrs; if (NULL != csa) { if ((csa->now_crit) && (crit_state & CRIT_HAVE_ANY_REG)) { crit_reg_cnt++; /* It is possible that if DSE has done a CRIT REMOVE and stolen our crit, it * could be given to someone else which would cause this test to fail. The * current thinking is that the state DSE put this process is no longer viable * and it should die at the earliest opportunity, there being no way to know if * that is what happened anyway. */ if (csa->nl->in_crit != process_id) GTMASSERT; /* If we are releasing (all) regions with critical section or if special * TP case, release if the cycle number doesn't match meaning this is a * region we should not hold crit in (even if it is part of tp_reg_list). */ if ((0 != (crit_state & CRIT_RELEASE)) && (0 == (crit_state & CRIT_NOT_TRANS_REG) || crit_deadlock_check_cycle != csa->crit_check_cycle)) { assert(WBTEST_HOLD_CRIT_ENABLED); assert(!csa->hold_onto_crit); rel_crit(r_local); send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_MUTEXRELEASED, 6, process_id, process_id, DB_LEN_STR(r_local), dollar_tlevel, t_tries); } if (0 == (crit_state & CRIT_ALL_REGIONS)) return crit_reg_cnt; } /* In Commit-crit is defined as the time since when early_tn is 1 + curr_tn upto when * t_commit_crit is set to FALSE. Note that the first check should be done only if we * hold crit as otherwise we could see inconsistent values. */ if ((crit_state & CRIT_IN_COMMIT) && (csa->now_crit && (csa->ti->early_tn != csa->ti->curr_tn) || csa->t_commit_crit)) { crit_reg_cnt++; if (0 == (crit_state & CRIT_ALL_REGIONS)) return crit_reg_cnt; } if ((crit_state & CRIT_IN_WTSTART) && csa->in_wtstart) { crit_reg_cnt++; if (0 == (crit_state & CRIT_ALL_REGIONS)) return crit_reg_cnt; } } } } } if (NULL != jnlpool.jnlpool_ctl) { csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; if ((NULL != csa) && csa->now_crit && (crit_state & CRIT_HAVE_ANY_REG)) { crit_reg_cnt++; if (0 != (crit_state & CRIT_RELEASE)) { assert(!csa->hold_onto_crit); rel_lock(jnlpool.jnlpool_dummy_reg); } } } return crit_reg_cnt; } fis-gtm-V6.0-003/sr_port/have_crit.h0000644000032200000250000002147012201176157016155 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef HAVE_CRIT_H_INCLUDED #define HAVE_CRIT_H_INCLUDED #include /* needed for VSIG_ATOMIC_T */ #ifdef UNIX #include #endif /* states of CRIT passed as argument to have_crit() */ #define CRIT_HAVE_ANY_REG 0x00000001 #define CRIT_IN_COMMIT 0x00000002 #define CRIT_NOT_TRANS_REG 0x00000004 #define CRIT_RELEASE 0x00000008 #define CRIT_ALL_REGIONS 0x00000010 #define CRIT_IN_WTSTART 0x00000020 /* check if csa->in_wtstart is true */ #ifdef DEBUG #include "wbox_test_init.h" #endif #ifdef UNIX #include "gt_timer.h" #endif typedef enum { INTRPT_OK_TO_INTERRUPT = 0, INTRPT_IN_GTCMTR_TERMINATE, INTRPT_IN_TP_UNWIND, INTRPT_IN_TP_CLEAN_UP, INTRPT_IN_CRYPT_SECTION, INTRPT_IN_DB_CSH_GETN, INTRPT_IN_GVCST_INIT, INTRPT_IN_GDS_RUNDOWN, INTRPT_IN_SS_INITIATE, INTRPT_IN_ZLIB_CMP_UNCMP, INTRPT_IN_TRIGGER_NOMANS_LAND, /* State where have trigger base frame but no trigger (exec) frame */ INTRPT_IN_MUR_OPEN_FILES, INTRPT_IN_TRUNC, INTRPT_IN_SET_NUM_ADD_PROCS, INTRPT_IN_SYSCONF, INTRPT_NO_TIMER_EVENTS, /* State where primary reason for deferral is to avoid timer pops */ INTRPT_IN_FFLUSH, /* Deferring interrupts during fflush */ INTRPT_IN_SHMDT, /* Deferring interrupts during SHMDT */ INTRPT_IN_WAIT_FOR_DISK_SPACE, /* Deferring interrupts during wait_for_disk_space.c */ INTRPT_IN_WCS_WTSTART, /* Deferring interrupts until cnl->intent_wtstart is decremented and dbsync timer is * started */ INTRPT_IN_REFORMAT_BUFFER_USE, /* Deferring interrupts until buffer is reformatted */ INTRPT_IN_X_TIME_FUNCTION, /* Deferring interrupts in non-nesting functions, such as localtime, ctime, and mktime. */ INTRPT_IN_FUNC_WITH_MALLOC, /* Deferring interrupts while in libc- or system functions that do a malloc internally. */ INTRPT_IN_FDOPEN, /* Deferring interrupts in fdopen. */ INTRPT_IN_LOG_FUNCTION, /* Deferring interrupts in openlog, syslog, or closelog. */ INTRPT_IN_FORK_OR_SYSTEM, /* Deferring interrupts in fork or system. */ INTRPT_IN_FSTAT, /* Deferring interrupts in fstat. */ INTRPT_NUM_STATES /* Should be the *last* one in the enum */ } intrpt_state_t; GBLREF intrpt_state_t intrpt_ok_state; GBLREF boolean_t deferred_timers_check_needed; /* Macro to check if we are in a state that is ok to interrupt (or to do deferred signal handling). We do not want to interrupt if * the global variable intrpt_ok_state indicates it is not ok to interrupt, if we are in the midst of a malloc, if we are holding * crit, if we are in the midst of commit, or in wcs_wtstart. In the last case, we could be causing another process HOLDING CRIT on * the region to wait in bg_update_phase1 if we hold the write interlock. Hence it is important for us to finish that as soon as * possible and not interrupt it. */ #define OK_TO_INTERRUPT ((INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) && (0 == gtmMallocDepth) \ && (0 == have_crit(CRIT_HAVE_ANY_REG | CRIT_IN_COMMIT | CRIT_IN_WTSTART))) /* Set the value of forced_exit to 1. This should indicate that we want a deferred signal handler to be invoked first upon leaving * the current deferred window. Since we do not want forced_exit state to ever regress, and there might be several signals delivered * within the same deferred window, assert that forced_exit is either 0 or 1 before setting it to 1. */ #define SET_FORCED_EXIT_STATE \ { \ GBLREF VSIG_ATOMIC_T forced_exit; \ \ assert((0 == forced_exit) || (1 == forced_exit)); \ forced_exit = 1; \ } /* Set the value of forced_exit to 2. This should indicate that we are already in the exit processing, and do not want to handle any * deferred events, from timers or other interrupts, anymore. Ensure that forced_exit state does not regress by asserting that the * current value is 0 or 1 before setting it to 2. Note that on UNIX forced_exit can progress to 2 only from 1, while on VMS it is * possible to generic_exit_handler or dbcertify_exit_handler to change forced_exit from 0 to 2 directly. This design ensures that * on VMS we will not invoke sys$exit from DEFERRED_EXIT_HANDLING_CHECK after we started exit processing; on UNIX process_exiting * flag servs the same purpose (and is also checked by DEFERRED_EXIT_HANDLING_CHECK), so it is not necessary for either * generic_signal_handler or dbcertify_signal_handler to set forced_exit to 2. */ #define SET_FORCED_EXIT_STATE_ALREADY_EXITING \ { \ GBLREF VSIG_ATOMIC_T forced_exit; \ \ assert(VMS_ONLY((0 == forced_exit) || ) (1 == forced_exit)); \ forced_exit = 2; \ } /* Macro to be used whenever we want to handle any signals that we deferred handling and exit in the process. * In VMS, we dont do any signal handling, only exit handling. */ #define DEFERRED_EXIT_HANDLING_CHECK \ { \ VMS_ONLY(GBLREF int4 exi_condition;) \ GBLREF int process_exiting; \ GBLREF VSIG_ATOMIC_T forced_exit; \ GBLREF volatile int4 gtmMallocDepth; \ \ /* The forced_exit state of 2 indicates that the exit is already in progress, so we do not \ * need to process any deferred events. \ */ \ if (2 > forced_exit) \ { /* If forced_exit was set while in a deferred state, disregard any deferred timers and \ * invoke deferred_signal_handler directly. \ */ \ if (forced_exit) \ { \ if (!process_exiting && OK_TO_INTERRUPT) \ { \ UNIX_ONLY(deferred_signal_handler();) \ VMS_ONLY(sys$exit(exi_condition);) \ } \ } \ UNIX_ONLY( \ else if (deferred_timers_check_needed) \ { \ if (!process_exiting && OK_TO_INTERRUPT) \ check_for_deferred_timers(); \ } \ ) \ } \ } /* Macro to cause deferrable interrupts to be deferred recording the cause. * If interrupt is already deferred, state is not changed. * * The normal usage of the below macros is * DEFER_INTERRUPTS * non-interruptible code * ENABLE_INTERRUPTS * We want the non-interruptible code to be executed AFTER the SAVE_INTRPT_OK_STATE macro. * To enforce this ordering, one would think a read memory barrier is needed in between. * But it is not needed. This is because we expect the non-interruptible code to have * a) pointer dereferences OR * b) function calls * Either of these will prevent the compiler from reordering the non-interruptible code. * Any non-interruptible code that does not have either of the above usages (for e.g. uses C global * variables) might be affected by compiler reordering. As of now, there is no known case of such * usage and no such usage is anticipated in the future. * * We dont need to worry about machine reordering as well since there is no shared memory variable * involved here (intrpt_ok_state is a process private variable) and even if any reordering occurs * they will all be in-flight instructions when the interrupt occurs so the hardware will guarantee * all such instructions are completely done or completely discarded before servicing the interrupt * which means the interrupt service routine will never see a reordered state of the above code. */ #define DEFER_INTERRUPTS(NEWSTATE) \ { \ if (INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) \ /* Only reset state if we are in "OK" state */ \ intrpt_ok_state = NEWSTATE; \ else \ assert((NEWSTATE) != intrpt_ok_state); /* Make sure not nesting same code */ \ } /* Re-enable deferrable interrupts if the expected state is found. If expected state is not found, then * we must have nested interrupt types. Avoid state changes in that case. When the nested state pops, * interrupts will be restored. */ #define ENABLE_INTERRUPTS(OLDSTATE) \ { \ assert(((OLDSTATE) == intrpt_ok_state) || (INTRPT_OK_TO_INTERRUPT != intrpt_ok_state)); \ if ((OLDSTATE) == intrpt_ok_state) \ { /* Only reset state if in expected state - othwise state must be non-zero which is \ * asserted above. \ */ \ intrpt_ok_state = INTRPT_OK_TO_INTERRUPT; \ DEFERRED_EXIT_HANDLING_CHECK; /* check if signals were deferred while held lock */ \ } \ } #define OK_TO_SEND_MSG ((INTRPT_IN_X_TIME_FUNCTION != intrpt_ok_state) \ && (INTRPT_IN_LOG_FUNCTION != intrpt_ok_state) \ && (INTRPT_IN_FORK_OR_SYSTEM != intrpt_ok_state)) uint4 have_crit(uint4 crit_state); #endif /* HAVE_CRIT_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/hd.mpt0000644000032200000250000000160512201176157015153 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1987,2001 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %HD ;GT.M %HD utility - hexadecimal to decimal conversion program ;invoke at INT with %HD in hexadecimal to return %HD in decimal ;invoke at FUNC as an extrinsic function ;if you make heavy use of this routine, consider $ZCALL ; s %HD=$$FUNC(%HD) q INT r !,"Hexidecimal: ",%HD s %HD=$$FUNC(%HD) q FUNC(h) q:$tr(h,"E","e")<0 "" n c,d,dg s d=0,h=$tr(h,"abcdef","ABCDEF") f c=1:1:$l(h) s dg=$f("0123456789ABCDEF",$e(h,c)) q:'dg s d=(d*16)+(dg-2) q d fis-gtm-V6.0-003/sr_port/ho.mpt0000644000032200000250000000165712201176157015175 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1987, 2003 Sanchez Computer Associates, Inc. ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %HO ;GT.M %HO utility - hexadecimal to octal conversion program ;invoke at INT with %HO in hexadecimal to return %HO in octal ;invoke at FUNC as an extrinsic function ;if you make heavy use of this routine, consider $ZCALL ; s %HO=$$FUNC(%HO) q INT r !,"Hexadecimal: ",%HO s %HO=$$FUNC(%HO) q FUNC(h) q:$tr(h,"E","e")<0 "" n c,d,dg,o s d=0,h=$tr(h,"abcdef","ABCDEF"),o="" f c=1:1:$l(h) s dg=$f("0123456789ABCDEF",$e(h,c)) q:'dg s d=(d*16)+(dg-2) f q:'d s o=d#8_o,d=d\8 q:0= (uintszofptr_t)ar); len = (unsigned int)(ar + SIZEOF(ar) - q); memcpy(p, q, len); return p + len; } uchar_ptr_t i2ascl(uchar_ptr_t p, qw_num n) { unsigned char ar[MAX_DIGITS_IN_INT8], *q; uint4 len; long r; q = ar + SIZEOF(ar); if (QWEQ(n, seq_num_zero)) *--q = '0'; else { while (QWNE(n, seq_num_zero)) { QWDIVIDEBYDW(n, 10, n, r); *--q = r + '0'; } } assert((uintszofptr_t)q >= (uintszofptr_t)ar); len = (uint4)(ar + SIZEOF(ar) - q); memcpy(p, q, len); return (unsigned char *)(p + len) ; } #ifdef INT8_SUPPORTED uchar_ptr_t i2asclx(uchar_ptr_t p, qw_num n) { unsigned char ar[MAX_HEX_DIGITS_IN_INT8], *q; uint4 len; qw_num m; q = ar + SIZEOF(ar); if (!n) *--q = '0'; else { while (n) { m = n & 0xF; if (m <= 9) *--q = m + '0'; else *--q = m - 0xa + 'A'; n = n >> 4; } } assert((uintszofptr_t)q >= (uintszofptr_t)ar); len = (uint4)(ar + SIZEOF(ar) - q); memcpy(p, q, len); return p + len; } #else uchar_ptr_t i2asclx(uchar_ptr_t p, qw_num n) { unsigned char ar[24], *q; uint4 msb, lsb, len, nibble; int i; q = ar + SIZEOF(ar); lsb = n.value[lsb_index]; msb = n.value[msb_index]; if (msb) { for (i = 0; i < 8; i++) /* 8 to denote 8 nibbles per 4-byte value */ { nibble = lsb & 0xF; if (nibble <= 9) *--q = nibble + '0'; else *--q = nibble - 0xa + 'A'; lsb = lsb >> 4; } lsb = msb; } if (!lsb) *--q = '0'; else { while (lsb) { nibble = lsb & 0xF; if (nibble <= 9) *--q = nibble + '0'; else *--q = nibble - 0xa + 'A'; lsb = lsb >> 4; } } assert((uintszofptr_t)q >= (uintszofptr_t)ar); len = ar + SIZEOF(ar) - q; memcpy(p, q, len); return p + len; } #endif fis-gtm-V6.0-003/sr_port/i2hex.c0000644000032200000250000000241712201176157015223 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" void i2hex(UINTPTR_T val, uchar_ptr_t dest, int len) { register uchar_ptr_t cp; register UINTPTR_T n; char x; n = val; cp = &dest[len]; while (cp > dest) { x = n & 0xF; n >>= 4; *--cp = x + ((x > 9) ? 'A' - 10 : '0'); } return; } #ifdef INT8_SUPPORTED void i2hexl(qw_num val, uchar_ptr_t dest, int len) { uchar_ptr_t cp; qw_num n; char x; n = val; cp = &dest[len]; while (cp > dest) { x = n & 0xF; n >>= 4; *--cp = x + ((x > 9) ? 'A' - 10 : '0'); } } #else void i2hexl(qw_num val, uchar_ptr_t dest, int len) { if (4 > len) { /* We only process some bytes of the low order word */ i2hex(val.value[msb_index], dest, len); return; } i2hex(val.value[msb_index], dest, 8); /* Process low order word */ dest += 8; len -= 8; if (len) i2hex(val.value[lsb_index], dest, len); } #endif fis-gtm-V6.0-003/sr_port/i2hex_blkfill.c0000644000032200000250000000200212201176157016710 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" void i2hex_blkfill(int num, uchar_ptr_t addr, int len) { unsigned char buff[8]; int i; assert(SIZEOF(buff) >= len); i2hex(num, buff, len); for ( i = 0; i < len - 1 ; i++) { if (buff[i] != '0') break; buff[i] = ' '; } memcpy(addr, buff, len); } void i2hexl_blkfill(qw_num num, uchar_ptr_t addr, int len) { unsigned char buff[16]; int i; assert(SIZEOF(buff) >= len); i2hexl(num, buff, len); for ( i = 0; i < len - 1 ; i++) { if (buff[i] != '0') break; buff[i] = ' '; } memcpy(addr, buff, len); } fis-gtm-V6.0-003/sr_port/i2hex_nofill.c0000644000032200000250000000200712201176157016561 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" int i2hex_nofill(int num, uchar_ptr_t addr, int len) { unsigned char buff[8]; int i; assert(SIZEOF(buff) >= len); i2hex(num, buff, len); for (i = 0; i < len - 1 ; i++) { if (buff[i] != '0') break; } memcpy(addr, &buff[i], len - i); return len - i; } int i2hexl_nofill(qw_num num, uchar_ptr_t addr, int len) { unsigned char buff[16]; int i; assert(SIZEOF(buff) >= len); i2hexl(num, buff, len); for (i = 0; i < len - 1 ; i++) { if (buff[i] != '0') break; } memcpy(addr, &buff[i], len - i); return len - i; } fis-gtm-V6.0-003/sr_port/ind_cg_var.c0000644000032200000250000000213612201176177016277 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include #include "cache.h" #include "obj_file.h" #include "cg_var.h" #include "stringpool.h" #include "hashtab_mname.h" GBLREF spdesc indr_stringpool; void ind_cg_var(mvar *v, var_tabent **p) { /* Copy mident with variable name to variable table entry */ assert((char *)indr_stringpool.base <= v->mvname.addr && v->mvname.addr < (char *)indr_stringpool.top); (*p)[v->mvidx].var_name = v->mvname; COMPUTE_HASH_MNAME(&((*p)[v->mvidx])); (*p)[v->mvidx].var_name.addr = (char *)((v->mvname.addr - (char *)indr_stringpool.base) + ROUND_UP2(SIZEOF(ihdtyp), NATIVE_WSIZE)); (*p)[v->mvidx].marked = FALSE; } fis-gtm-V6.0-003/sr_port/ind_code.c0000644000032200000250000001435412201176177015755 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "objlabel.h" #include #include "cache.h" #include "cgp.h" #include "stringpool.h" #include "copy.h" #include "mmemory.h" #include "obj_file.h" #include "cg_var.h" GBLREF boolean_t run_time; GBLREF int4 mvmax, mlitmax; GBLREF mvar *mvartab; GBLREF int4 curr_addr, code_size; GBLREF int4 sa_temps[]; GBLREF int4 sa_temps_offset[]; GBLREF char cg_phase; /* code generation phase */ GBLREF char cg_phase_last; /* previous code generation phase */ GBLREF spdesc stringpool, indr_stringpool; #ifdef __ia64 GBLREF int4 generated_code_size, calculated_code_size; #endif GBLDEF unsigned char *runtime_base; /************** Indirect Object Code Format ************* * * +-------------------------+> aligned section boundary * | ihdtyp | * +-------------------------> aligned section boundary * | lit text pool | * +-------------------------- * | lit mval table | * +-------------------------- * | hdr_offset (4-byte) | (8-byte on GTM64) * +-------------------------- * | validation (4-byte) | (8-byte on GTM64) * +-------------------------- * | Executable Code | * +-------------------------- * | variable Table | * +-------------------------+ * ***************************************************/ void ind_code(mstr *obj) { var_tabent *vptr; ihdtyp *itext; uint4 indir_code_size; IA64_ONLY(int old_code_size;) INTPTR_T validation, hdr_offset, long_temp; unsigned char *indr_base_addr; assert(run_time); curr_addr = SIZEOF(ihdtyp); cg_phase = CGP_APPROX_ADDR; cg_phase_last = CGP_NOSTATE; IA64_ONLY(calculated_code_size = 0); code_gen(); code_size = curr_addr; cg_phase = CGP_ADDR_OPT; # if (!defined(USHBIN_SUPPORTED) && !defined(VMS)) /* non-shared binary UNIX platforms */ shrink_jmps(); # endif /* GTM64: assuming indir_code_size wont exceed MAX_INT */ indir_code_size = (uint4)((SECTION_ALIGN_BOUNDARY - 1) /* extra padding to align the beginning of the entire indirect object */ + SIZEOF(ihdtyp) + PADLEN(SIZEOF(ihdtyp), NATIVE_WSIZE) /* extra padding to align the beginning of lit text pool */ + ROUND_UP2(indr_stringpool.free - indr_stringpool.base, NATIVE_WSIZE) /* base literal strings */ + mlitmax * SIZEOF(mval) /* literal mval table aligned at NATIVE_WSIZE boundary */ + (SIZEOF(INTPTR_T) * 2) /* validation word and (neg) offset to ihdtyp */ /* SIZEOF(INTPTR_T) is used for alignment reasons */ + GTM64_ONLY((SECTION_ALIGN_BOUNDARY - 1)) /* extra padding to align the beginning of the code address */ + code_size /* code already aligned at SECTION_ALIGN_BOUNDARY boundary */ + mvmax * SIZEOF(var_tabent)); /* variable table ents */ ENSURE_STP_FREE_SPACE(indir_code_size); /* Align the beginning of the indirect object so that ihdtyp fields can be accessed normally */ stringpool.free = (unsigned char *)ROUND_UP2((UINTPTR_T)stringpool.free, SECTION_ALIGN_BOUNDARY); itext = (ihdtyp *)stringpool.free; indr_base_addr = stringpool.free; stringpool.free += SIZEOF(ihdtyp); indir_lits(itext); /* Runtime base (fp->ctxt) needs to be set to the beginning of the Executable code so that * the literal references are generated with appropriate (-ve) offsets from the base * register (fp->ctxt). On USHBIN_SUPPORTED platforms, runtime_base should be computed * before shrink_trips since it could be used in codegen of literals */ runtime_base = stringpool.free + SIZEOF(hdr_offset) + SIZEOF(validation); /* Align the begining of the code so that it can be access properly. */ GTM64_ONLY(runtime_base = (unsigned char *)ROUND_UP2((UINTPTR_T)runtime_base, SECTION_ALIGN_BOUNDARY);) IA64_ONLY(old_code_size = code_size;) # if defined(USHBIN_SUPPORTED) || defined(VMS) shrink_trips(); # endif IA64_ONLY( if (old_code_size != code_size) calculated_code_size -= ((old_code_size - code_size)/16); ) /* Alignment for the starting of code address before code_gen.*/ GTM64_ONLY(stringpool.free = (unsigned char *)ROUND_UP2((UINTPTR_T)stringpool.free, SECTION_ALIGN_BOUNDARY);) assert(0 == GTM64_ONLY(PADLEN((UINTPTR_T)stringpool.free, SECTION_ALIGN_BOUNDARY)) NON_GTM64_ONLY(PADLEN((UINTPTR_T)stringpool.free, SIZEOF(int4)))); /* Since we know stringpool is aligned atleast at 4-byte boundary, copy both offset and validation * words with integer assignments instead of copying them by emit_immed(). */ hdr_offset = indr_base_addr - stringpool.free; /* -ve offset to ihdtyp */ *(INTPTR_T *)stringpool.free = hdr_offset; stringpool.free += SIZEOF(hdr_offset); validation = MAGIC_COOKIE; /* Word to validate we are in right place */ *(UINTPTR_T *)stringpool.free = validation; stringpool.free += SIZEOF(validation); cg_phase = CGP_MACHINE; IA64_ONLY(generated_code_size = 0); code_gen(); IA64_ONLY(assert(calculated_code_size == generated_code_size)); long_temp = stringpool.free - indr_base_addr; assert(0 == PADLEN(long_temp, SIZEOF(INTPTR_T))); /* Just to make sure things are aligned for the vartab that follows */ /* variable table */ itext->vartab_off = (int4)long_temp; itext->vartab_len = mvmax; vptr = (var_tabent*)mcalloc(mvmax * SIZEOF(var_tabent)); if (mvartab) walktree(mvartab, ind_cg_var, (char *)&vptr); else assert(0 == mvmax); emit_immed((char *) vptr, mvmax * SIZEOF(var_tabent)); itext->temp_mvals = sa_temps[TVAL_REF]; itext->temp_size = sa_temps_offset[TCAD_REF]; /* indir_code_size may be greater than the actual resultant code size because expression coersion may cause some literals * to be optimized away, leaving mlitmax greater than actual. */ assert(indir_code_size >= stringpool.free - indr_base_addr); /* Return object code pointers on stack. A later cache_put will move * the code to its new home and do the necessary cleanup on it. */ obj->addr = (char *)indr_base_addr; obj->len = INTCAST(stringpool.free - indr_base_addr); } fis-gtm-V6.0-003/sr_port/indir.h0000644000032200000250000000717112201176157015320 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* The third column represents the opcodes for functions to be used by op_indfun(). * The one parameter version of $name can probably be folded into op_indfun, but at a later time. * Note: *** Please add new entries to end of list so as not to cause execution problems for * compilations from previous versions. Yes, they should have recompiled but we can * avoid exploding by simply adding entries to end of list. *** * This comment and the preceeding empty lines put the first item at line 20, so adding 20 to an argcode * places you on the line with its information or subtracting 20 from a line gives the corresponding argcode */ INDIR(indir_fndata, f_data, OC_FNDATA) ,INDIR(indir_fnnext, f_next, OC_FNNEXT) ,INDIR(indir_fnorder1, f_order1, OC_FNORDER) ,INDIR(indir_get, f_get1, OC_FNGET) ,INDIR(indir_close, m_close, 0) ,INDIR(indir_hang, m_hang, 0) ,INDIR(indir_if, m_if, 0) ,INDIR(indir_kill, m_kill, 0) ,INDIR(indir_open, m_open, 0) ,INDIR(indir_read, m_read, 0) ,INDIR(indir_set, m_set, 0) ,INDIR(indir_use, m_use, 0) ,INDIR(indir_write, m_write, 0) ,INDIR(indir_xecute, m_xecute, 0) ,INDIR(indir_nref, nref, 0) ,INDIR(indir_lock, m_lock, 0) ,INDIR(indir_do, m_do, 0) ,INDIR(indir_goto, m_goto, 0) ,INDIR(indir_job, m_job, 0) ,INDIR(indir_linetail, linetail, 0) ,INDIR(indir_new, m_new, 0) ,INDIR(indir_zlink, m_zlink, 0) ,INDIR(indir_zbreak, m_zbreak, 0) ,INDIR(indir_zsystem, m_zsystem, 0) ,INDIR(indir_zedit, m_zedit, 0) ,INDIR(indir_zmess, m_zmessage, 0) ,INDIR(indir_zwatch, m_zwatch, 0) ,INDIR(indir_zgoto, m_zgoto, 0) ,INDIR(indir_zprint, m_zprint, 0) ,INDIR(indir_zwrite, m_zwrite, 0) ,INDIR(indir_glvn, indirection, 0) ,INDIR(indir_lvadr, indirection, 0) ,INDIR(indir_pattern, indirection, 0) ,INDIR(indir_iset, indirection, 0) ,INDIR(indir_text, indirection, 0) ,INDIR(indir_view, m_view, 0) ,INDIR(indir_zattach, m_zattach, 0) ,INDIR(indir_zallocate, m_zallocate, 0) ,INDIR(indir_zdeallocate, m_zdeallocate, 0) ,INDIR(indir_lvarg, indirection, 0) ,INDIR(indir_fnzprevious, f_zprevious, OC_FNZPREVIOUS) ,INDIR(indir_fnquery, f_query, OC_FNQUERY) ,INDIR(indir_zhelp, m_zhelp, 0) ,INDIR(indir_zshow, m_zshow, 0) ,INDIR(indir_lvnamadr, indirection, 0) ,INDIR(indir_zwithdraw, m_zwithdraw, 0) ,INDIR(indir_tstart, m_tstart, 0) ,INDIR(indir_fnname, f_name, 0) /* f_name is really a dummy */ ,INDIR(indir_fnorder2, f_order, 0) ,INDIR(indir_fnzqgblmod, f_zqgblmod, OC_FNZQGBLMOD) ,INDIR(indir_trollback, m_trollback, 0) ,INDIR(indir_devparms, indirection, 0) ,INDIR(indir_merge, m_merge, 0) ,INDIR(indir_merge1, m_merge, 0) ,INDIR(indir_merge2, m_merge, 0) ,INDIR(indir_fntext, f_text, OC_FNTEXT) ,INDIR(indir_quit, m_quit, 0) ,INDIR(indir_increment, f_incr, 0) ,INDIR(indir_fnzahandle, f_zahandle, OC_FNZAHANDLE) ,INDIR(indir_fnzdata, f_data, OC_FNZDATA) #ifdef GTM_TRIGGER ,INDIR(indir_ztrigger, m_ztrigger, 0) #endif ,INDIR(indir_zhalt, m_zhalt, 0) ,INDIR(indir_fnzwrite, f_zwrite, OC_FNZWRITE) ,INDIR(indir_savglvn0, indirection, 0) /* this entry and the following use indirection as a dummy value */ ,INDIR(indir_savlvn, indirection, 0) ,INDIR(indir_savglvn1, indirection, 0) /* 0 and 1 (above) separate 2 variants of generated code */ fis-gtm-V6.0-003/sr_port/indir_enum.h0000644000032200000250000000101212201176157016330 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #define INDIR(a,b,c) a enum indir_enum { #include "indir.h" }; #undef INDIR fis-gtm-V6.0-003/sr_port/indir_lits.c0000644000032200000250000000340712201176177016346 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "compiler.h" #include "mdq.h" #include "stringpool.h" #include #include "copy.h" #include "obj_file.h" #include "cache.h" GBLREF mliteral literal_chain; GBLREF spdesc stringpool, indr_stringpool; void indir_lits(ihdtyp *ihead) { ssize_t size, lits_pad_len, hdr_pad_len; int4 long_temp; mliteral *lit; hdr_pad_len = PADLEN(SIZEOF(ihdtyp), NATIVE_WSIZE); if (hdr_pad_len) /* additional padding to ihdtyp so that the literal text pool begins at the aligned boundary */ emit_immed(PADCHARS, (uint4)hdr_pad_len); size = indr_stringpool.free - indr_stringpool.base; emit_immed((char *)indr_stringpool.base, (uint4)size); lits_pad_len = PADLEN(size, NATIVE_WSIZE); /* Length to pad to put instructions on even bdy */ if (lits_pad_len) emit_immed(PADCHARS, (uint4)lits_pad_len); /* Pad out with extraneous info */ size += (SIZEOF(ihdtyp) + hdr_pad_len + lits_pad_len); ihead->fixup_vals_off = (int4)(ROUND_UP2(size, NATIVE_WSIZE)); ihead->fixup_vals_num = 0; dqloop(&literal_chain, que, lit) { if (lit->rt_addr < 0) { ihead->fixup_vals_num++; lit->rt_addr = (INTPTR_T)stringpool.free; lit->v.str.addr = (char *)((lit->v.str.addr - (char *)indr_stringpool.base) + SIZEOF(ihdtyp) + hdr_pad_len); emit_immed((char *)&lit->v, SIZEOF(mval)); } } } fis-gtm-V6.0-003/sr_port/indirection.c0000644000032200000250000000626012201176157016513 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" /* needed by INCREMENT_EXPR_DEPTH */ #include "compiler.h" #include "opcode.h" #include "mdq.h" #include "toktyp.h" #include "advancewindow.h" #include "fullbool.h" #include "show_source_line.h" #include "stringpool.h" GBLREF boolean_t run_time; GBLREF char *lexical_ptr; GBLREF spdesc stringpool; GBLREF unsigned char *source_buffer; GBLREF short int source_column; error_def(ERR_BOOLSIDEFFECT); error_def(ERR_EXPR); error_def(ERR_LPARENMISSING); error_def(ERR_MAXNRSUBSCRIPTS); error_def(ERR_RPARENMISSING); error_def(ERR_SIDEEFFECTEVAL); int indirection(oprtype *a) { char c; oprtype *sb1, *sb2, subs[MAX_INDSUBSCRIPTS], x; triple *next, *ref; int parens, oldlen, len; char *start, *end, *oldend; boolean_t concat_athashes; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(TK_ATSIGN == TREF(window_token)); concat_athashes = (2 == source_column); INCREMENT_EXPR_DEPTH; advancewindow(); if (!expratom(a)) { DECREMENT_EXPR_DEPTH; stx_error(ERR_EXPR); return FALSE; } coerce(a, OCT_MVAL); ex_tail(a); ENCOUNTERED_SIDE_EFFECT; DECREMENT_EXPR_DEPTH; if ((TK_ATSIGN == TREF(window_token)) || ((TK_ATHASH == TREF(window_token)) && concat_athashes)) { (TREF(indirection_mval)).mvtype = 0; (TREF(indirection_mval)).str.len = 0; do { start = lexical_ptr; advancewindow(); if (TK_LPAREN != TREF(window_token)) { stx_error(ERR_LPARENMISSING); return FALSE; } advancewindow(); if (!parse_until_rparen_or_space() || (TK_RPAREN != TREF(window_token))) { stx_error(ERR_RPARENMISSING); return FALSE; } end = (char *)source_buffer + (INTPTR_T)source_column - 1; /* lexical_ptr before last advancewindow */ len = INTCAST(end - start); oldlen = (TREF(indirection_mval)).str.len; ENSURE_STP_FREE_SPACE(oldlen + len); /* Ok to copy from beginning each iteration because we generally expect no more than two iterations, * and that's with nested indirection. */ memcpy(stringpool.free, (TREF(indirection_mval)).str.addr, oldlen); if (oldlen) { oldend = (char *)stringpool.free + oldlen - 1; assert(*oldend == ')'); *oldend = ','; } (TREF(indirection_mval)).mvtype = MV_STR; (TREF(indirection_mval)).str.addr = (char *)stringpool.free; (TREF(indirection_mval)).str.len = oldlen + len; stringpool.free += oldlen; memcpy(stringpool.free, start, len); stringpool.free += len; advancewindow(); } while ((TK_ATHASH == TREF(window_token)) && concat_athashes); ref = newtriple(OC_INDNAME); ref->operand[0] = *a; ref->operand[1] = put_lit(&(TREF(indirection_mval))); (TREF(indirection_mval)).mvtype = 0; /* so stp_gcol (BYPASSOK) - if invoked later - can free up space */ *a = put_tref(ref); } return TRUE; } fis-gtm-V6.0-003/sr_port/init_root_gv.h0000644000032200000250000000462712201176157016720 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #define INIT_GBL_ROOT() { curr_gbl_root.str.addr = (char *)malloc(SIZEOF(mident_fixed)); } #define CREATE_DUMMY_GBLDIR(header, saved, region, map, map_top) { \ mval v; \ gd_binding *map_temp; \ \ saved = header; \ header = 0; \ v.mvtype = MV_STR; \ header = (gd_addr *)create_dummy_gbldir(); \ map = header->maps; \ map_top = map + header->n_maps; \ map_temp = map + 1; \ map_temp->reg.addr = region; \ map_temp = map_temp + 1;\ map_temp->reg.addr = region; \ } #define GET_SAVED_GDADDR(header, saved, map, region) {\ header = saved; \ map = header->maps; \ map = map + 1; /* get past local locks */ \ map->reg.addr = region; \ map = map + 1; \ map->reg.addr = region; \ } #define RESTORE_ORIGINAL_GDADDR (header, saved) { header = saved; } #define RETRIEVE_ROOT_VAL(gbl_name, root_val, temp_gbl_name, temp_root_val, root_val_len) \ { \ temp_gbl_name = gbl_name; temp_root_val = root_val; \ for (root_val_len = 0; (*temp_root_val++ = *temp_gbl_name++); root_val_len++); \ *temp_root_val = '\0'; \ } #define INIT_ROOT_GVT(curr_gbl_root, root_val_len, curr_gbl_root_mval) \ { \ unsigned char *key; \ gv_namehead *hasht_tree; \ mname_entry gvent; \ \ GTMTRIG_ONLY(if ((HASHT_GBLNAME_LEN != root_val_len) || (0 != memcmp(HASHT_GBLNAME, curr_gbl_root, root_val_len))))\ { \ curr_gbl_root_mval.str.len = MIN(root_val_len, MAX_MIDENT_LEN); \ memcpy(curr_gbl_root_mval.str.addr, curr_gbl_root, curr_gbl_root_mval.str.len); \ op_gvname(VARLSTCNT(1) &curr_gbl_root_mval); \ } GTMTRIG_ONLY(else \ { \ SETUP_TRIGGER_GLOBAL; \ key = &gv_currkey->base[0]; \ memcpy(key, HASHT_GBLNAME, HASHT_GBLNAME_FULL_LEN); \ key += HASHT_GBLNAME_FULL_LEN; \ *key++ = '\0'; \ gv_currkey->end = HASHT_GBLNAME_FULL_LEN; \ } \ ) \ } fis-gtm-V6.0-003/sr_port/init_secshr_addrs.c0000644000032200000250000000552212201176157017673 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #ifdef VMS #include /* Required for gtmsource.h */ #endif #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdscc.h" #include "gdskill.h" #include "filestruct.h" #include "repl_msg.h" #include "gtmsource.h" #include "jnl.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "init_secshr_addrs.h" GBLREF gd_addr_fn_ptr get_next_gdr_addrs; GBLREF cw_set_element *cw_set_addrs; GBLREF sgm_info **first_sgm_info_addrs; GBLREF sgm_info **first_tp_si_by_ftok_addrs; GBLREF unsigned char *cw_depth_addrs; GBLREF uint4 rundown_process_id; GBLREF uint4 rundown_image_count; GBLREF int4 rundown_os_page_size; GBLREF gd_region **jnlpool_reg_addrs; GBLREF inctn_opcode_t *inctn_opcode_addrs; GBLREF inctn_detail_t *inctn_detail_addrs; GBLREF uint4 *dollar_tlevel_addrs; GBLREF uint4 *update_trans_addrs; GBLREF sgmnt_addrs **cs_addrs_addrs; GBLREF sgmnt_addrs **kip_csa_addrs; GBLREF boolean_t *need_kip_incr_addrs; GBLREF trans_num *start_tn_addrs; #define DEF_PGSZ 512 void init_secshr_addrs(gd_addr_fn_ptr getnxtgdr, cw_set_element *cwsetaddrs, sgm_info **firstsiaddrs, sgm_info **firstsibyftokaddrs, unsigned char *cwsetdepthaddrs, uint4 epid, uint4 icnt, int4 gtmospagesize, gd_region **jpool_reg_address, inctn_opcode_t *inctn_opcode_address, inctn_detail_t *inctn_detail_address, uint4 *dollar_tlevel_address, uint4 *update_trans_address, sgmnt_addrs **cs_addrs_address, sgmnt_addrs **kip_csa_address, boolean_t *need_kip_incr_address, trans_num *start_tn_address) { get_next_gdr_addrs = getnxtgdr; cw_set_addrs = cwsetaddrs; first_sgm_info_addrs = firstsiaddrs; first_tp_si_by_ftok_addrs = firstsibyftokaddrs; cw_depth_addrs = cwsetdepthaddrs; rundown_process_id = epid; assert(rundown_process_id); rundown_image_count = icnt; rundown_os_page_size = ((0 != gtmospagesize) && ((gtmospagesize / DEF_PGSZ) * DEF_PGSZ) == gtmospagesize) ? gtmospagesize : DEF_PGSZ; jnlpool_reg_addrs = jpool_reg_address; inctn_opcode_addrs = inctn_opcode_address; inctn_detail_addrs = inctn_detail_address; dollar_tlevel_addrs = dollar_tlevel_address; update_trans_addrs = update_trans_address; cs_addrs_addrs = cs_addrs_address; kip_csa_addrs = kip_csa_address; need_kip_incr_addrs = need_kip_incr_address; start_tn_addrs = start_tn_address; } fis-gtm-V6.0-003/sr_port/init_secshr_addrs.h0000644000032200000250000000425312201176157017700 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef INIT_SECSHR_ADDRS_INCLUDED #define INIT_SECSHR_ADDRS_INCLUDED void init_secshr_addrs(gd_addr_fn_ptr getnxtgdr, cw_set_element *cwsetaddrs, sgm_info **firstsiaddrs, sgm_info **firstsibyftokaddrs, unsigned char *cwsetdepthaddrs, uint4 epid, uint4 icnt, int4 gtmospagesize, gd_region **jpool_reg_address, inctn_opcode_t *inctn_opcode_address, inctn_detail_t *inctn_detail_address, uint4 *dollar_tlevel_address, uint4 *update_trans_address, sgmnt_addrs **cs_addrs_address, sgmnt_addrs **kip_csa_addrs, boolean_t *need_kip_incr_address, trans_num *start_tn_address); #include "dpgbldir.h" /* for "get_next_gdr" used by INVOKE_INIT_SECSHR_ADDRS macro */ GBLREF sgm_info *first_sgm_info; /* List of all regions (unsorted) in TP transaction */ GBLREF sgm_info *first_tp_si_by_ftok; /* List of READ or UPDATED regions sorted on ftok order */ GBLREF cw_set_element cw_set[]; GBLREF unsigned char cw_set_depth; GBLREF uint4 process_id; GBLREF uint4 image_count; GBLREF jnlpool_addrs jnlpool; GBLREF inctn_opcode_t inctn_opcode; GBLREF inctn_detail_t inctn_detail; /* holds detail to fill in to inctn jnl record */ GBLREF uint4 dollar_tlevel; GBLREF uint4 update_trans; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_addrs *kip_csa; GBLREF boolean_t need_kip_incr; GBLREF trans_num start_tn; #define INVOKE_INIT_SECSHR_ADDRS \ init_secshr_addrs(get_next_gdr, cw_set, &first_sgm_info, &first_tp_si_by_ftok, \ &cw_set_depth, process_id, image_count, OS_PAGE_SIZE, \ &jnlpool.jnlpool_dummy_reg, &inctn_opcode, &inctn_detail, \ &dollar_tlevel, &update_trans, &cs_addrs, \ &kip_csa, &need_kip_incr, &start_tn); #endif /* INIT_SECSHR_ADDRS_INCLUDED */ fis-gtm-V6.0-003/sr_port/ins_errtriple.c0000644000032200000250000000534112201176157017064 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "mdq.h" GBLREF int4 pending_errtriplecode; /* if non-zero contains the error code to invoke ins_errtriple with */ GBLREF triple t_orig; void ins_errtriple(int4 in_error) { boolean_t add_rterror_triple; triple *triptr, *x; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (!IS_STX_WARN(in_error) GTMTRIG_ONLY( || TREF(trigger_compile))) { /* Not a warning and not a trigger, we have a real error (warnings become errors in triggers) */ if (TREF(curtchain) != &t_orig) { /* If working with more than 1 chain defer until back to 1 because dqdelchain cannot delete across * multiple chains. Set global variable "pending_errtriplecode" and let "setcurtchain" call here again. */ if (!pending_errtriplecode) /* Give user only the first error on the line */ pending_errtriplecode = in_error; /* Save error for later insert */ return; } x = (TREF(pos_in_chain)).exorder.bl; /* If first error in the current line/cmd, delete all triples and replace them with an OC_RTERROR triple. */ add_rterror_triple = (OC_RTERROR != x->exorder.fl->opcode); if (!add_rterror_triple) { /* This is the second error in this line/cmd. Check for triples added after OC_RTERROR and remove them * as there could be dangling references amongst them which could later cause GTMASSERT in emit_code. */ x = x->exorder.fl; assert(OC_RTERROR == x->opcode);/* corresponds to newtriple(OC_RTERROR) in previous ins_errtriple */ x = x->exorder.fl; assert(OC_ILIT == x->opcode); /* corresponds to put_ilit(in_error) in previous ins_errtriple */ x = x->exorder.fl; assert(OC_ILIT == x->opcode); /* corresponds to put_ilit(FALSE) in previous ins_errtriple */ } dqdelchain(x, TREF(curtchain), exorder); assert(!add_rterror_triple || ((TREF(pos_in_chain)).exorder.bl->exorder.fl == TREF(curtchain))); assert(!add_rterror_triple || ((TREF(curtchain))->exorder.bl == (TREF(pos_in_chain)).exorder.bl)); } else /* For IS_STX_WARN errors (if not compiling a trigger), parsing continues, so dont strip the chain */ add_rterror_triple = TRUE; if (add_rterror_triple) { triptr = newtriple(OC_RTERROR); triptr->operand[0] = put_ilit(in_error); triptr->operand[1] = put_ilit(FALSE); /* not a subroutine reference */ } } fis-gtm-V6.0-003/sr_port/ins_triple.c0000644000032200000250000000152712201176157016355 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "mdq.h" void ins_triple(triple *x) { triple *y; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; /* Need to pass a temporary variable "y" (instead of "curtchain->exorder.bl") to the dqins macro as it will * otherwise result in incorrect queue insertion. */ y = (TREF(curtchain))->exorder.bl; dqins(y,exorder,x); CHKTCHAIN(TREF(curtchain)); } fis-gtm-V6.0-003/sr_port/insert_region.c0000644000032200000250000001716212201176157017056 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* insert_region.c * requirement * reg initialized (gvcst_init) * parameters * reg the region to be inserted * reg_list pointer to the pointer to the list head * reg_free_list pointer to the pointer to the free list * size size of the structure of each item in the list * return * pointer to the item in the list that is corresponding to the region. * *reg_list and *reg_free_list are also updated if needed. * fid_index field in csa and tp_reg_list is maintained by gvcst_init. Maintaining tp_reg_list is * important, since the regions might be re-sorted in between insert_region() calls (i.e. new * regions opening). All callers of insert_region except for dse_all() either use tp_reg_list or do not * have the regions open. dse_all() opens the regions before it calls insert_region(), so maintaining * fid_index in tp_reg_list is sufficient. */ #include "mdef.h" #ifdef VMS #include #endif #ifdef UNIX #include "gtm_ipc.h" /* needed for FTOK */ #endif #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "gdscc.h" #include "gdskill.h" #include "filestruct.h" #include "jnl.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "iosp.h" #include "dbfilop.h" #include "gtmmsg.h" #include "is_file_identical.h" #include "t_retry.h" #include "wcs_mm_recover.h" #include "gtmimagename.h" GBLREF gd_region *gv_cur_region; GBLREF uint4 dollar_tlevel; GBLREF unsigned int t_tries; tp_region *insert_region( gd_region *reg, tp_region **reg_list, tp_region **reg_free_list, int4 size) { tp_region *tr, *tr_last, *tr_new; unique_file_id local_id; # ifdef VMS char *local_id_fiptr; file_control *fc; uint4 status; gd_region *temp_reg; # endif int4 local_fid_index; sgmnt_addrs *csa; int4 match; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(SIZEOF(tp_region) <= size); assert(!IS_GTM_IMAGE || dollar_tlevel); if (reg->open) csa = (sgmnt_addrs *)&FILE_INFO(reg)->s_addrs; # if defined(VMS) if (!reg->open) { temp_reg = gv_cur_region; gv_cur_region = reg; local_id_fiptr = local_id.file_id; if (!mupfndfil(reg, NULL)) { gv_cur_region = temp_reg; return NULL; } FILE_CNTL_INIT_IF_NULL(reg->dyn.addr); fc = reg->dyn.addr->file_cntl; fc->file_type = reg->dyn.addr->acc_meth; fc->op = FC_OPEN; status = dbfilop(fc); if (status & 1) { local_id_fiptr = &(FILE_INFO(reg)->file_id); sys$dassgn(FILE_INFO(reg)->fab->fab$l_stv); } else { gtm_putmsg(VARLSTCNT(1) status); gv_cur_region = temp_reg; return NULL; } gv_cur_region = temp_reg; } else local_fid_index = csa->fid_index; # elif defined(UNIX) if (!reg->open) { if (!mupfndfil(reg, NULL)) return NULL; if (!filename_to_id(&local_id.uid, (char *)reg->dyn.addr->fname)) return NULL; } else local_fid_index = csa->fid_index; # endif /* See if the region is already on the list or if we have to add it */ for (tr = *reg_list, tr_last = NULL; NULL != tr; tr = tr->fPtr) { if (reg->open) { /* gvcst_init must have sorted them and filled in the fid_index field of node_local */ assert(tr->reg->open); /* note that it is possible that "reg" and "tr->reg" are different although their "fid_index" is the same. * this is possible if both regions point to the same physical file. * in this case we return the existing "tr" instead of creating a new one. */ if (local_fid_index == tr->file.fid_index) /* Region is found */ { /* assert we are not in final retry or we are in TP and have crit on the region already */ assert((CDB_STAGNATE > t_tries) || (dollar_tlevel && reg->open && csa->now_crit)); return tr; } if ((tr->file.fid_index > local_fid_index)) break; /* .. we have found our insertion point */ } else { if (reg == tr->reg) /* Region is found */ { /* assert we are not in final retry or we are in TP and have crit on the region already */ assert((CDB_STAGNATE > t_tries) || (dollar_tlevel && reg->open && csa->now_crit)); return tr; } /* let's sort here */ if (!tr->reg->open) { /* all regions closed */ VMS_ONLY(match = memcmp(&(tr->file.file_id), local_id_fiptr, SIZEOF(gd_id))); UNIX_ONLY(match = gdid_cmp(&(tr->file.file_id), &(local_id.uid))); } else { /* the other regions are open, i.e. file is pointing to fid_index, use file_id * from node_local */ VMS_ONLY(match = memcmp( &(((sgmnt_addrs *)&FILE_INFO(tr->reg)->s_addrs)->nl->unique_id.file_id), local_id_fiptr, SIZEOF(gd_id))); UNIX_ONLY(match = gdid_cmp( &(((sgmnt_addrs *)&FILE_INFO(tr->reg)->s_addrs)->nl->unique_id.uid), &(local_id.uid))); } if (0 == match) return tr; if (0 < match) break; /* .. we have found our insertion point */ } tr_last = tr; } if ((NULL != reg_free_list) && (NULL != *reg_free_list)) /* Get a used block off our unused queue */ { tr_new = *reg_free_list; /* Get element */ *reg_free_list = tr_new->fPtr; /* Remove from queue */ } else /* get a new one */ { tr_new = (tp_region *)malloc(size); if (size > SIZEOF(tp_region)) memset(tr_new, 0, size); } tr_new->reg = reg; /* Add this region to end of list */ if (!reg->open) { VMS_ONLY(memcpy(&(tr_new->file.file_id), local_id_fiptr, SIZEOF(gd_id))); UNIX_ONLY(tr_new->file.file_id = local_id.uid;) } else tr_new->file.fid_index = local_fid_index; if (NULL == tr_last) { /* First element on the list */ tr_new->fPtr = *reg_list; *reg_list = tr_new; } else { /* Insert into list */ tr_new->fPtr = tr_last->fPtr; tr_last->fPtr = tr_new; } if ((CDB_STAGNATE <= t_tries) && dollar_tlevel && reg->open && !csa->now_crit) { /* Final retry in TP and this region not locked down. Get crit on it if it is open. * reg->open needs to be checked above to take care of the case where we do an insert_region() from gvcst_init() * in the 3rd retry in TP when we have not yet opened the region. In case region is not open, * tp_restart() (invoked through t_retry from gvcst_init) will open "reg" as well as get crit on it for us. */ DEBUG_ONLY(TREF(ok_to_call_wcs_recover) = TRUE;) if (FALSE == grab_crit_immediate(reg)) /* Attempt lockdown now */ { DEBUG_ONLY(TREF(ok_to_call_wcs_recover) = FALSE;) t_retry(cdb_sc_needcrit); /* avoid deadlock -- restart transaction */ assert(FALSE); /* should not come here as t_retry() does not return */ } DEBUG_ONLY(TREF(ok_to_call_wcs_recover) = FALSE;) assert(csa->now_crit); /* ensure we have crit now */ CHECK_MM_DBFILEXT_REMAP_IF_NEEDED(csa, reg); # ifdef UNIX if (MISMATCH_ROOT_CYCLES(csa, csa->nl)) { /* Going into this retry, we have already checked in tp_restart for moved root blocks in tp_reg_list. * Since we haven't yet checked this region, we check it here and reset clues for an globals in the * newly inserted region. We don't want to reset ALL gvt clues because the current retry may have made * use (and valid use at that) of clues for globals in other regions. */ RESET_ALL_GVT_CLUES_REG(csa); csa->root_search_cycle = csa->nl->root_search_cycle; } # endif } DBG_CHECK_TP_REG_LIST_SORTING(*reg_list); return tr_new; } fis-gtm-V6.0-003/sr_port/inst_flush.h0000644000032200000250000000110112201176157016354 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef INST_FLUSH_INCLUDED #define INST_FLUSH_INCLUDED void inst_flush(void *start, int4 len); #endif /* INST_FLUSH_INCLUDED */ fis-gtm-V6.0-003/sr_port/int_label.c0000644000032200000250000000152112201176157016130 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "compiler.h" #include "toktyp.h" void int_label(void) { int len; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; TREF(window_token) = TK_IDENT; len = (TREF(window_mval)).str.len; len = (len < MAX_MIDENT_LEN) ? len: MAX_MIDENT_LEN; memcpy((TREF(window_ident)).addr, (TREF(window_mval)).str.addr, len); (TREF(window_ident)).len = len; } fis-gtm-V6.0-003/sr_port/io.h0000644000032200000250000002565612201176177014634 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef IO_H #define IO_H #ifdef USING_ICONV #define _OSF_SOURCE #include #undef _OSF_SOURCE #else /* no iconv.h - must define size_t on VMS platform */ #ifdef VMS #include #endif #endif #include "gt_timer.h" #include #include "stack_frame.h" #include "mv_stent.h" #ifdef __MVS__ #include "gtm_zos_io.h" #endif error_def(ERR_BADCHSET); #define INSERT TRUE #define NO_INSERT FALSE #define IO_SEQ_WRT 1 #define IO_RD_ONLY 2 #define ESC_LEN 16 #define MAX_DEVCTL_LENGTH 256 #define IO_ESC 0x1b #define MAX_DEV_TYPE_LEN 7 #define DD_BUFLEN 80 #define CHAR_FILTER 128 #define ESC1 1 #define ESC2 2 #define ESC_MASK (ESC1+ESC2) #define START 0 #define AFTESC 1 #define SEQ1 2 #define SEQ2 3 #define SEQ3 4 #define SEQ4 5 #define FINI 6 #define BADESC 7 #define DEFAULT_IOD_LENGTH 55 #define DEFAULT_IOD_WIDTH 80 #define DEFAULT_IOD_WRAP TRUE #define BADCHAR_DEVICE_MSG "BADCHAR error raised on input" #define UNAVAILABLE_DEVICE_MSG "Resource temporarily unavailable" typedef unsigned char params; /* * The enum nl below conflicts with curses.h on AIX. At some point * These names should be expanded to less generic identifiers * to avoid conflicts with prototype header files. */ enum io_dev_type { tt, /* terminal */ mt, /* mag tape */ rm, /* rms */ us, /* user device driver */ mb, /* mail box */ nl, /* null device */ ff, /* fifo device */ tcp, /* TCP socket */ gtmsocket, /* socket device, socket is already used by sys/socket.h */ #ifdef UNIX pi, /* pipe */ #endif n_io_dev_types /* terminator */ }; enum io_dev_state { dev_never_opened, dev_closed, dev_open, n_io_dev_states }; #ifdef VMS enum code_set_type { ascii, ebcdic }; #endif typedef struct { struct io_desc_struct *in; struct io_desc_struct *out; }io_pair; typedef struct io_desc_struct { io_pair pair; struct io_log_name_struct *trans_name; struct io_log_name_struct *name; mstr error_handler; unsigned int length; unsigned int width; bool perm; /* permanent */ bool wrap; /* if FALSE trunc */ enum io_dev_type type; enum io_dev_state state; struct { unsigned int x; unsigned int y; unsigned short zeof; unsigned short za; unsigned char zb[ESC_LEN]; char key[DD_BUFLEN]; char device[DD_BUFLEN]; }dollar; unsigned char esc_state; void *dev_sp; struct dev_dispatch_struct *disp_ptr; #if defined(KEEP_zOS_EBCDIC) || defined(VMS) iconv_t input_conv_cd; iconv_t output_conv_cd; enum code_set_type in_code_set; enum code_set_type out_code_set; #endif boolean_t newly_created; #ifdef __MVS__ gtm_chset_t file_chset; /* from file tag */ gtm_chset_t process_chset; /* how to do conversion */ unsigned int file_tag; boolean_t text_flag; boolean_t is_ichset_default; boolean_t is_ochset_default; #endif gtm_chset_t ichset; gtm_chset_t ochset; int4 write_filter; } io_desc; /* * ICHSET: UTF-16 * First READ: BOM * Transition to UTF-16BE or UTF-16LE based on BOM * * ICHSET: UTF-16 * First READ: Not BOM * Transition to UTF-16BE per Unicode standard * * ICHSET: UTF-16LE (or UTF-16BE) * First READ: BOM or not BOM * Do nothing, assume input is in specified endian format. Pass input to application (if BOM present, it is treated as ZWNBS) * * OCHSET: UTF-16 * First WRITE: Transition to UTF-16BE, write BOM * * OCHSET: UTF-16LE (or UTF-16BE) * First WRITE: Do not WRITE BOM. All output in specified endian format */ typedef struct io_log_name_struct { io_desc *iod; /* io descriptor */ struct io_log_name_struct *next; /* linked list */ unsigned char len; /* name length */ char dollar_io[1]; /* _$IO hidden variable */ }io_log_name; io_log_name *get_log_name(mstr *v, bool insert); /* wttab is not used in the IO dispatch, but used in the user defined dispatch for ious*. Even though all the entries are NULL in * the IO dispatch table are NULL in the IO dispatch tables, they have to remain. */ typedef struct dev_dispatch_struct { short (*open)(io_log_name *, mval *, int, mval *, int4); void (*close)(io_desc *, mval *); void (*use)(io_desc *, mval *); int (*read)(mval *, int4); int (*rdone)(mint *, int4); void (*write)(mstr *); void (*wtone)(int); void (*wteol)(int4, io_desc *); void (*wtff)(void); void (*wttab)(int4); void (*flush)(io_desc *); int (*readfl)(mval *, int4, int4); void (*iocontrol)(mstr *); void (*dlr_device)(mstr *); void (*dlr_key)(mstr *); } dev_dispatch_struct; /* io_ prototypes */ void io_rundown(int rundown_type); void io_init(bool term_ctrl); bool io_is_rm(mstr *name); bool io_is_sn(mstr *tn); struct mv_stent_struct *io_find_mvstent(io_desc *io_ptr, boolean_t clear_mvstent); #ifdef UNIX bool io_is_tt(char *name); #endif bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mval *mspace); enum io_dev_type io_type(mstr *tn); void io_init_name(void); #define ioxx_open(X) short io##X##_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout) #define ioxx_dummy(X) short io##X##_dummy(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout) #define ioxx_close(X) void io##X##_close(io_desc *iod, mval *pp) #define ioxx_use(X) void io##X##_use(io_desc *iod, mval *pp) #define ioxx_read(X) int io##X##_read(mval *v, int4 t) #define ioxx_rdone(X) int io##X##_rdone (mint *v, int4 timeout) #define ioxx_write(X) void io##X##_write(mstr *v) #define ioxx_wtone(X) void io##X##_wtone(int c) #define ioxx_wteol(X) void io##X##_wteol(int4 cnt, io_desc *iod) #define ioxx_wtff(X) void io##X##_wtff(void) #define ioxx_wttab(X) void io##X##_wttab(int4 x) #define ioxx_flush(X) void io##X##_flush(io_desc *iod) #define ioxx_readfl(X) int io##X##_readfl(mval *v, int4 width, int4 timeout) #define xx_iocontrol(X) void X##_iocontrol(mstr *d) #define xx_dlr_device(X) void X##_dlr_device(mstr *d) #define xx_dlr_key(X) void X##_dlr_key(mstr *d) /* Following definitions have a pattern that most of the routines follow. Only exceptions are: * 1. ioff_open() is an extra routine * 2. iopi_open() is an extra routine on unix * 3. iopi_iocontrol() is an extra routine on unix to handle write /writeof */ #define ioxx(X) ioxx_##X(tt); ioxx_##X(mt); ioxx_##X(rm); VMS_ONLY(ioxx_##X(mb);) ioxx_##X(nl); \ ioxx_##X(us); ioxx_##X(tcp); ioxx_##X(socket) #define xxdlr(X) xx_iocontrol(X); xx_dlr_device(X); xx_dlr_key(X) /* prototypes for dispatch functions */ ioxx(open); ioxx(close); ioxx(rdone); ioxx(use); ioxx(read); ioxx(readfl); ioxx(write); ioxx(wtone); ioxx(wteol); ioxx(wtff); ioxx(dummy); ioxx(flush); xxdlr(nil); xxdlr(ious); xxdlr(iotcp); xxdlr(iosocket); ioxx_open(ff); #ifdef UNIX ioxx_open(pi); xxdlr(iopi); /* we need iopi_iocontrol(), iopi_dlr_device() and iopi_dlr_key() */ xxdlr(iott); /* we need iott_iocontrol(), iott_dlr_device() and iott_dlr_key() */ #endif ioxx_wttab(us); /* iott_ prototypes */ uchar_ptr_t iott_escape(uchar_ptr_t strin, uchar_ptr_t strtop, io_desc *io_ptr); /* iomt_ prototypes */ void iomt_getrec(io_desc *dv); void iomt_rdstream(uint4 len, void *str, io_desc *dv); int iomt_readblk(io_desc *dv); void iomt_vlflush(io_desc *dv); void iomt_wrtblk(io_desc *dv); int iomt_wrtinit(io_desc *dv); void iomt_wtansilab(io_desc *dv, uint4 labs); uint4 iomt_reopen(io_desc *dv, unsigned short mode, int rewind); void iomt_closesp(int4 channel); void iomt_eof(io_desc *dev); void iomt_erase(io_desc *dev); void iomt_qio(io_desc *iod, uint4 mask, uint4 parm); void iomt_rddoslab(io_desc *dv); void iomt_rdansiend(io_desc *dv); void iomt_rdansistart(io_desc *dv); void iomt_rewind(io_desc *dev); void iomt_skipfile(io_desc *dev, int count); void iomt_skiprecord(io_desc *dev, int count); void iomt_tm(io_desc *dev); void iomt_wtdoslab(io_desc *dv); /* iosocket_ prototypes */ boolean_t iosocket_listen(io_desc *iod, unsigned short len); boolean_t iosocket_wait(io_desc *iod, int4 timepar); void iosocket_poolinit(void); /* iotcp_ prototypes */ int iotcp_fillroutine(void); int iotcp_getlsock(io_log_name *dev); void iotcp_rmlsock(io_desc *iod); /* tcp_ prototypes */ int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive); /* iomb_ prototypes */ #ifdef VMS int iomb_dataread (int timeout); #endif bool same_device_check(mstr tname, char *buf); #define iotype(O,X,Y) \ { \ O##_open, X##_close, X##_use, X##_read, X##_rdone, X##_write, \ X##_wtone, X##_wteol, X##_wtff, NULL, X##_flush, X##_readfl, \ Y##_iocontrol, Y##_dlr_device, Y##_dlr_key \ } #define ionil_dev \ { \ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL \ } #ifdef __sparc int outc(char ch); #else int outc(int ch); #endif void get_dlr_device(mval *v); void get_dlr_key(mval *v); void flush_pio(void); void remove_rms(io_desc *ciod); void iosocket_destroy(io_desc *ciod); dev_dispatch_struct *io_get_fgn_driver(mstr *s); #define MAX_CHSET_NAME 64 #define TAB_BUF_SZ 128 LITREF unsigned char spaces_block[]; #if defined(KEEP_zOS_EBCDIC) || defined(VMS) LITREF unsigned char ebcdic_spaces_block[]; #define SPACES_BLOCK ((ascii != io_curr_device.out->out_code_set) ? \ ebcdic_spaces_block : spaces_block) #define RM_SPACES_BLOCK ((ascii != iod->out_code_set) ? \ ebcdic_spaces_block : spaces_block) #ifdef __MVS__ #define SET_CODE_SET(CODE_SET, CODE_SET_STR) \ { \ if (!strcmp(CODE_SET_STR, OUTSIDE_CH_SET)) \ CODE_SET = ebcdic; \ else \ CODE_SET = ascii; \ } #else #define SET_CODE_SET(CODE_SET, CODE_SET_STR) #endif /* __MVS__ */ #else /* !KEEP_zOS_EBCDIC && !VMS*/ #define SPACES_BLOCK spaces_block #define RM_SPACES_BLOCK spaces_block #endif /* KEEP_zOS_EBCDIC || VMS */ #define ICONV_OPEN_CD(DESC_CD, CODE_SRC, CODE_TARGET) \ { \ if (!strcmp(CODE_TARGET, CODE_SRC)) \ DESC_CD = NO_XLAT; \ else if (!strcmp(CODE_TARGET, "ISO8859-1")) \ DESC_CD = EBCDIC_TO_ASCII; \ else \ DESC_CD = ASCII_TO_EBCDIC; \ } #define ICONV_CLOSE_CD(DESC_CD) (DESC_CD = NO_XLAT) #define ICONVERT(CD, SRC, IN_LEN_PTR, DEST, OUT_LEN_PTR) \ { \ if (EBCDIC_TO_ASCII == CD) \ ebc_to_asc(*(DEST), *(SRC), *(IN_LEN_PTR)); \ else if (ASCII_TO_EBCDIC == CD) \ asc_to_ebc(*(DEST), *(SRC), *(IN_LEN_PTR)); \ } #define SET_ENCODING(CHSET, CHSET_MSTR) \ { \ int chset_idx; \ \ chset_idx = verify_chset(CHSET_MSTR); \ ; \ if (0 <= chset_idx) \ (CHSET) = (gtm_chset_t)chset_idx; \ else \ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADCHSET, 2, (CHSET_MSTR)->len, (CHSET_MSTR)->addr); \ } #endif /* IO_H */ fis-gtm-V6.0-003/sr_port/io_dev_dispatch.h0000644000032200000250000000242012201176157017327 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* mupip_io_dev_dispatch.h is a subset of this file which includes those needed only by MUPIP * so, if you need to make a change here, please keep the other one in sync. * * VMS can have addresses in literal constants while most Unix platforms cannot */ UNIX_ONLY(GBLDEF) VMS_ONLY(LITDEF) dev_dispatch_struct io_dev_dispatch[] = { # ifdef UNIX iotype(iott, iott, iott), # else iotype(iott, iott, nil), # endif iotype(iomt, iomt, nil), # ifdef UNIX iotype(iorm, iorm, iopi), # else iotype(iorm, iorm, nil), # endif iotype(ious, ious, ious), # ifdef UNIX ionil_dev, # else iotype(iomb, iomb, nil), # endif iotype(ionl, ionl, nil), # ifdef UNIX iotype(ioff, iorm, iopi), # else iotype(ioff, iorm, nil), # endif iotype(iotcp, iotcp, iotcp), iotype(iosocket, iosocket, iosocket) # ifdef UNIX ,iotype(iopi, iorm, iopi) # endif }; fis-gtm-V6.0-003/sr_port/io_init.c0000644000032200000250000001337712201176157015645 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "io.h" #include "iosp.h" #include "io_params.h" #include "error.h" #include "op.h" #include "term_setup.h" #include "trans_log_name.h" /***************** GLOBAL DATA FOR THE MUMPS IO SYSTEM *******************/ GBLREF io_pair io_curr_device; /* current device */ GBLREF io_pair io_std_device; /* standard device */ GBLREF io_log_name *dollar_principal; /* pointer to log name GTM$PRINCIPAL if defined */ GBLREF bool prin_in_dev_failure; GBLREF bool prin_out_dev_failure; GBLREF int (*op_open_ptr)(mval *v, mval *p, int t, mval *mspace); GBLREF io_log_name *io_root_log_name; /* root of linked list */ GBLREF mstr sys_input; GBLREF mstr sys_output; GBLREF mstr gtm_principal; /***************** END OF GLOBAL DATA ***************************************/ void io_init(bool term_ctrl) { static readonly unsigned char open_params_list[2] = { (unsigned char)iop_newversion, (unsigned char)iop_eol }; static readonly unsigned char null_params_list[2] = { (unsigned char)iop_nl, (unsigned char)iop_eol }; static readonly unsigned char no_params = (unsigned char)iop_eol; static readonly unsigned char shr_params[3] = { (unsigned char)iop_shared, (unsigned char)iop_readonly, (unsigned char)iop_eol }; int4 status; mval val; mstr tn; MSTR_CONST (gtm_netout, "GTM_NETOUT"); MSTR_CONST (sys_net, "SYS$NET"); char buf1[MAX_TRANS_NAME_LEN]; /* buffer to hold translated name */ mval pars; io_log_name *inp, *outp; io_log_name *ln; error_def(ERR_LOGTOOLONG); io_init_name(); /* default logical names */ io_root_log_name = (io_log_name *)malloc(SIZEOF(*io_root_log_name)); memset(io_root_log_name, 0, SIZEOF(*io_root_log_name)); val.mvtype = MV_STR; val.str.addr = "0"; val.str.len = 1; ln = get_log_name(&val.str, INSERT); assert(ln != 0); val.str = gtm_principal; status = TRANS_LOG_NAME(&val.str, &tn, buf1, SIZEOF(buf1), dont_sendmsg_on_log2long); if (SS_NOLOGNAM == status) dollar_principal = 0; else if (SS_NORMAL == status) dollar_principal = get_log_name(&tn, INSERT); # ifdef UNIX else if (SS_LOG2LONG == status) rts_error(VARLSTCNT(5) ERR_LOGTOOLONG, 3, val.str.len, val.str.addr, SIZEOF(buf1) - 1); # endif else rts_error(VARLSTCNT(1) status); /* open devices */ val.str = sys_input; inp = get_log_name(&val.str, INSERT); pars.mvtype = MV_STR; status = TRANS_LOG_NAME(&val.str, &tn, buf1, SIZEOF(buf1), dont_sendmsg_on_log2long); if (SS_NOLOGNAM == status) { pars.str.len = SIZEOF(null_params_list); pars.str.addr = (char *)null_params_list; } else if (SS_NORMAL == status) { if (!io_is_rm(&val.str)) { pars.str.len = SIZEOF(no_params); pars.str.addr = (char *)&no_params; } else if (io_is_sn(&val.str)) { pars.str.len = SIZEOF(open_params_list); pars.str.addr = (char *)open_params_list; } else { pars.str.len = SIZEOF(shr_params); pars.str.addr = (char *)shr_params; } } # ifdef UNIX else if (SS_LOG2LONG == status) rts_error(VARLSTCNT(5) ERR_LOGTOOLONG, 3, val.str.len, val.str.addr, SIZEOF(buf1) - 1); # endif else rts_error(VARLSTCNT(1) status); ESTABLISH(io_init_ch); (*op_open_ptr)(&val, &pars, 0, 0); io_curr_device.in = io_std_device.in = inp->iod; val.str = sys_output; if ((SS_NORMAL == TRANS_LOG_NAME(>m_netout, &tn, buf1, SIZEOF(buf1), do_sendmsg_on_log2long)) && (SS_NORMAL == TRANS_LOG_NAME(&sys_net, &tn, buf1, SIZEOF(buf1), do_sendmsg_on_log2long)) && io_is_sn(&sys_net)) val.str = sys_net; outp = get_log_name(&val.str, INSERT); status = TRANS_LOG_NAME(&val.str, &tn, buf1, SIZEOF(buf1), dont_sendmsg_on_log2long); if ((SS_NORMAL != status) && (SS_NOLOGNAM != status)) { # ifdef UNIX if (SS_LOG2LONG == status) rts_error(VARLSTCNT(5) ERR_LOGTOOLONG, 3, val.str.len, val.str.addr, SIZEOF(buf1) - 1); else # endif rts_error(VARLSTCNT(1) status); } if ((val.str.addr == sys_net.addr) && (pars.str.addr == (char *)open_params_list)) /* sys$net is the only input thing that uses open_params_list */ outp->iod = io_curr_device.in; /* For terminals and mailboxes and sockets, SYS$INPUT and SYS$OUTPUT may point to the same device. If input is one of those, then check translated name for output against translated name for input; in that case they should be joined by their logical names */ if (((tt == io_curr_device.in->type) || (mb == io_curr_device.in->type) || (gtmsocket == io_curr_device.in->type)) && same_device_check(tn, buf1)) outp->iod = io_curr_device.in; if (!outp->iod) { if (status == SS_NOLOGNAM) { pars.str.len = SIZEOF(null_params_list); pars.str.addr = (char *)null_params_list; } else if (status == SS_NORMAL) { pars.str.len = SIZEOF(open_params_list); pars.str.addr = (char *)open_params_list; } (*op_open_ptr)(&val, &pars, 0, 0); } io_curr_device.out = io_std_device.out = outp->iod; term_setup(term_ctrl); io_std_device.out->pair = io_std_device; io_std_device.in->pair = io_std_device; io_std_device.out->perm = io_std_device.in->perm = TRUE; for (ln = io_root_log_name; ln; ln = ln->next) ln->iod = io_std_device.in; if (dollar_principal) dollar_principal->iod = io_std_device.in; pars.str.len = SIZEOF(no_params); pars.str.addr = (char *)&no_params; val.str.len = io_curr_device.in->trans_name->len; val.str.addr = io_std_device.in->trans_name->dollar_io; op_use(&val, &pars); REVERT; return; } fis-gtm-V6.0-003/sr_port/io_init_ch.c0000644000032200000250000000161012201176157016302 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "io.h" #include "iottdef.h" #include "error.h" #include "setterm.h" #include "util.h" GBLREF io_log_name *io_root_log_name; CONDITION_HANDLER(io_init_ch) { io_log_name *iol; START_CH; if (INFO == SEVERITY) { PRN_ERROR; CONTINUE; } for (iol = io_root_log_name; 0 != iol; iol = iol->next) { if (iol->iod && (iol->iod->type == tt) && iol->iod->dev_sp) resetterm(iol->iod); } NEXTCH; } fis-gtm-V6.0-003/sr_port/io_params.h0000644000032200000250000000204512201176157016160 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #define MAXDEVPARLEN 1024 #define IOP_VAR_SIZE 255 #define IOP_OPEN_OK 1 #define IOP_USE_OK 2 #define IOP_CLOSE_OK 4 #define IOP_SRC_INT 1 /* source is integer */ #define IOP_SRC_STR 2 /* source is string */ #define IOP_SRC_MSK 3 /* source is character mask */ #define IOP_SRC_PRO 4 /* source is protection mask */ #define IOP_SRC_LNGMSK 5 /* source is int4 character mask */ #define IOP_SRC_TIME 6 /* source is the date-time string */ typedef struct { unsigned char valid_with; unsigned char source_type; } dev_ctl_struct; #define IOP_DESC(a,b,c,d,e) b enum io_params { #include "iop.h" }; #undef IOP_DESC fis-gtm-V6.0-003/sr_port/io_rundown.c0000644000032200000250000000340012201176157016360 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "iosp.h" #include "io_params.h" #include "error.h" GBLREF io_log_name *io_root_log_name; GBLREF io_pair io_std_device; GBLREF bool prin_in_dev_failure; GBLREF bool prin_out_dev_failure; void io_dev_close (io_log_name *d); void io_rundown (int rundown_type) { io_log_name *l; /* logical name pointer */ if (io_root_log_name == 0) return; for (l = io_root_log_name; l != 0; l = io_root_log_name) { io_root_log_name = l->next; if (l->iod != 0) { if ((NORMAL_RUNDOWN == rundown_type) || ((RUNDOWN_EXCEPT_STD == rundown_type) && ((l->iod->pair.in != io_std_device.in) && (l->iod->pair.out != io_std_device.out)))) io_dev_close(l); } } } void io_dev_close (io_log_name *d) { static readonly unsigned char p[] = {iop_rundown, iop_eol}; mval pp; if (d->iod->pair.in == io_std_device.in && d->iod->pair.out == io_std_device.out) { if (prin_in_dev_failure || prin_out_dev_failure) return; } ESTABLISH(lastchance3); pp.mvtype = MV_STR; pp.str.addr = (char *) p; pp.str.len = SIZEOF(p); if (d->iod->pair.in && d->iod->pair.in->state == dev_open) (d->iod->pair.in->disp_ptr->close)(d->iod->pair.in, &pp); if (d->iod->pair.out && d->iod->pair.out->state == dev_open) (d->iod->pair.out->disp_ptr->close)(d->iod->pair.out, &pp); REVERT; } fis-gtm-V6.0-003/sr_port/iomt_ansilab_manager.c0000644000032200000250000002217612201176157020343 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "io.h" #include "iosp.h" #include "iottdef.h" #include "iomtdef.h" #include "movtc.h" static readonly char vol1_lab[] = "VOL1MUMPS1 3"; static readonly char hdr1_lab[] = "HDR1MUMPS.SRC MUMPS100010001000100 00000 00000 000000GTCMUMPS "; static readonly char hdr2_lab[] = " 00 "; static readonly char eof1_lab[] = "EOF1MUMPS.SRC MUMPS100010001000100 00000 00000 000000GTCMUMPS "; LITREF unsigned char LIB_AB_ASC_EBC[]; LITREF unsigned char LIB_AB_EBC_ASC[]; void iomt_wtansilab(io_desc *dv, uint4 labs) { iosb io_status_blk; uint4 status, status1, mask; unsigned char *outcp, buff[ANSI_LAB_LENGTH], *ptr, asc_buf[12]; d_mt_struct *mt_ptr; error_def(ERR_MTIS); mt_ptr = (d_mt_struct *) dv->dev_sp; mask = 0; #ifdef UNIX if (mt_ptr->mode != MT_M_WRITE) { uint4 status; status = iomt_reopen (dv, MT_M_WRITE, FALSE); } #endif if (labs & MTL_VOL1) { outcp = (unsigned char*) vol1_lab; if (mt_ptr->ebcdic) { movtc(ANSI_LAB_LENGTH, outcp, LIB_AB_ASC_EBC, buff); status = iomt_wtlblk(mt_ptr->access_id, mask, &io_status_blk, buff, ANSI_LAB_LENGTH); } else { status = iomt_wtlblk(mt_ptr->access_id, mask, &io_status_blk, outcp, ANSI_LAB_LENGTH); } if (status != SS_NORMAL || (status1 = io_status_blk.status) != SS_NORMAL) { if ( status1 == SS_ENDOFTAPE) { dv->dollar.za = 1; } else { dv->dollar.za = 9; } rts_error(VARLSTCNT(4) ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); } else dv->dollar.za = 0; } if (labs & MTL_HDR1) { outcp = (unsigned char *) hdr1_lab; mask = 0; if (mt_ptr->ebcdic) { movtc(ANSI_LAB_LENGTH, outcp, LIB_AB_ASC_EBC, buff); status = iomt_wtlblk(mt_ptr->access_id, mask, &io_status_blk, buff, ANSI_LAB_LENGTH); } else { status = iomt_wtlblk(mt_ptr->access_id, mask, &io_status_blk, outcp, ANSI_LAB_LENGTH); } if (status != SS_NORMAL || (status1 = io_status_blk.status) != SS_NORMAL) { if ( status1 == SS_ENDOFTAPE) { dv->dollar.za = 1; } else { dv->dollar.za = 9; } rts_error(VARLSTCNT(4) ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); } else dv->dollar.za = 0; } if (labs & MTL_HDR2) { outcp = buff; memcpy(outcp, mt_ptr->fixed ? "HDR2F" : "HDR2D" , 5); *(outcp+5) = '0'; i2asc(asc_buf,mt_ptr->block_sz); *(outcp+6) = asc_buf[0]; *(outcp+7) = asc_buf[1]; *(outcp+8) = asc_buf[2]; *(outcp+9) = asc_buf[3]; *(outcp+10) = '0'; i2asc(asc_buf,mt_ptr->record_sz); *(outcp+11) = asc_buf[0]; *(outcp+12) = asc_buf[1]; *(outcp+13) = asc_buf[2]; *(outcp+14) = asc_buf[3]; memcpy(outcp+15, hdr2_lab, SIZEOF(hdr2_lab) - 1); mask = 0; if (mt_ptr->ebcdic) { movtc(ANSI_LAB_LENGTH, outcp, LIB_AB_ASC_EBC, buff); status = iomt_wtlblk(mt_ptr->access_id, mask, &io_status_blk, buff, ANSI_LAB_LENGTH); } else { status = iomt_wtlblk(mt_ptr->access_id, mask, &io_status_blk, outcp, ANSI_LAB_LENGTH); } if (status != SS_NORMAL || (status1 = io_status_blk.status) != SS_NORMAL) { if ( status1 == SS_ENDOFTAPE) { dv->dollar.za = 1; } else { dv->dollar.za = 9; } rts_error(VARLSTCNT(4) ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); } else dv->dollar.za = 0; } if (labs & MTL_EOF1) { outcp = (unsigned char *) eof1_lab; mask = 0; if (mt_ptr->ebcdic) { movtc(ANSI_LAB_LENGTH, outcp, LIB_AB_ASC_EBC, buff); status = iomt_wtlblk(mt_ptr->access_id, mask, &io_status_blk, buff, ANSI_LAB_LENGTH); } else { status = iomt_wtlblk(mt_ptr->access_id, mask, &io_status_blk, outcp, ANSI_LAB_LENGTH); } if (status != SS_NORMAL || (status1 = io_status_blk.status) != SS_NORMAL) { if (status1 == SS_ENDOFTAPE) { dv->dollar.za = 1; } else { dv->dollar.za = 9; } rts_error(VARLSTCNT(4) ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); } else dv->dollar.za = 0; } if (labs & MTL_EOF2) { outcp = buff; memcpy(outcp, mt_ptr->fixed ? "EOF2F" : "EOF2D" , 5); *(outcp+5) = '0'; i2asc(asc_buf,mt_ptr->block_sz); *(outcp+6) = asc_buf[0]; *(outcp+7) = asc_buf[1]; *(outcp+8) = asc_buf[2]; *(outcp+9) = asc_buf[3]; *(outcp+10) = '0'; i2asc(asc_buf,mt_ptr->record_sz); *(outcp+11) = asc_buf[0]; *(outcp+12) = asc_buf[1]; *(outcp+13) = asc_buf[2]; *(outcp+14) = asc_buf[3]; memcpy(outcp+15, hdr2_lab, SIZEOF(hdr2_lab) - 1); if (mt_ptr->ebcdic) { movtc(ANSI_LAB_LENGTH, outcp, LIB_AB_ASC_EBC, buff); status = iomt_wtlblk(mt_ptr->access_id, mask, &io_status_blk, buff, ANSI_LAB_LENGTH); } else { status = iomt_wtlblk(mt_ptr->access_id, mask, &io_status_blk, outcp, ANSI_LAB_LENGTH); } if (status != SS_NORMAL || (status1 = io_status_blk.status) != SS_NORMAL) { if (status1 == SS_ENDOFTAPE) { dv->dollar.za = 1; } else { dv->dollar.za = 9; } rts_error(VARLSTCNT(4) ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); } else dv->dollar.za = 0; } return; } void iomt_rdansistart(io_desc *dv) { uint4 status, status1, mask; iosb io_status_blk; d_mt_struct *mt_ptr; int inlen, i; unsigned char *incp, *ptr; error_def (ERR_MTIS); error_def(ERR_MTANSILAB); mt_ptr = (d_mt_struct *) dv->dev_sp; inlen = ANSI_LAB_LENGTH; incp = (unsigned char*) malloc(mt_ptr->block_sz); for (i = 0; i < 4; i++) { io_status_blk.status = 0; mask = 0; status = iomt_rdlblk(mt_ptr, mask, &io_status_blk, incp, mt_ptr->block_sz); if (status != SS_NORMAL || (status1 = io_status_blk.status) != SS_NORMAL) { if ( status1 == SS_ENDOFTAPE) { dv->dollar.za = 1; } else { dv->dollar.za = 9; } free(incp); if (status == SS_NORMAL && status1 == SS_ENDOFFILE) return; rts_error(VARLSTCNT(4) ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); } else dv->dollar.za = 0; if (mt_ptr->ebcdic) movtc(ANSI_LAB_LENGTH, incp, LIB_AB_EBC_ASC, incp); switch(i) { case 0: if (io_status_blk.char_ct != ANSI_LAB_LENGTH || memcmp(incp, vol1_lab, 4)) { dv->dollar.za = 9; free (incp); rts_error(VARLSTCNT(6) ERR_MTANSILAB, 0, ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); } break; case 1: if (io_status_blk.char_ct != ANSI_LAB_LENGTH || memcmp(incp, hdr1_lab, 4)) { dv->dollar.za = 9; free (incp); rts_error(VARLSTCNT(6) ERR_MTANSILAB, 0, ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); } break; case 2: if (!(io_status_blk.char_ct != ANSI_LAB_LENGTH || memcmp(incp, "HDR2", 4))) { ptr = incp + 4; if (*ptr == 'D' || *ptr == 'F') { break; } } dv->dollar.za = 9; free (incp); rts_error(VARLSTCNT(6) ERR_MTANSILAB, 0, ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); default: dv->dollar.za = 9; free (incp); rts_error(VARLSTCNT(6) ERR_MTANSILAB, 0, ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); } } } void iomt_rdansiend(io_desc *dv) { uint4 status, status1, mask; iosb io_status_blk; int inlen, i; d_mt_struct *mt_ptr; unsigned char *incp, *ptr; error_def (ERR_MTIS); error_def(ERR_MTANSILAB); mt_ptr = (d_mt_struct *) dv->dev_sp; inlen = ANSI_LAB_LENGTH; incp = (unsigned char *) malloc(mt_ptr->block_sz); for (i = 0; i < 3; i++) { io_status_blk.status = 0; mask = 0; status = iomt_rdlblk(mt_ptr, mask, &io_status_blk, incp, mt_ptr->block_sz); if (status != SS_NORMAL || (status1 = io_status_blk.status) != SS_NORMAL) { if (status1 == SS_ENDOFTAPE) { dv->dollar.za = 1; } else { dv->dollar.za = 9; } free (incp); if (status == SS_NORMAL && (status1 == SS_ENDOFFILE)) return; rts_error(VARLSTCNT(4) ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); } else dv->dollar.za = 0; if (mt_ptr->ebcdic) movtc(ANSI_LAB_LENGTH, incp, LIB_AB_EBC_ASC, incp); switch(i) { case 0: if (io_status_blk.char_ct != ANSI_LAB_LENGTH || memcmp(incp, eof1_lab, 4)) { dv->dollar.za = 9; free (incp); rts_error(VARLSTCNT(6) ERR_MTANSILAB, 0, ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); } break; case 1: if (!(io_status_blk.char_ct != ANSI_LAB_LENGTH || memcmp(incp, "EOF2", 4))) { ptr = incp + 4; if (*ptr == 'D' || *ptr == 'F') { break; } } dv->dollar.za = 9; free (incp); rts_error(VARLSTCNT(6) ERR_MTANSILAB, 0, ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); default: dv->dollar.za = 9; free (incp); rts_error(VARLSTCNT(6) ERR_MTANSILAB, 0, ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); } } free (incp); return; } fis-gtm-V6.0-003/sr_port/iomt_close.c0000644000032200000250000000564412201176157016346 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" #include "io_params.h" #include "stringpool.h" #include "copy.h" LITREF unsigned char io_params_size[]; void iomt_close(io_desc *dv, mval *pp) { unsigned char ch; d_mt_struct *mt_ptr; int p_offset; int4 skips; error_def(ERR_UNIMPLOP); p_offset = 0; mt_ptr = (d_mt_struct *)dv->dev_sp; #ifdef DP FPRINTF(stderr, ">> iomt_close\n"); #endif if (dv->state == dev_open) { iomt_flush(dv); while (*(pp->str.addr + p_offset) != iop_eol) { switch (ch = *(pp->str.addr + p_offset++)) { case iop_exception: dv->error_handler.len = *(pp->str.addr + p_offset); dv->error_handler.addr = (char *)(pp->str.addr + p_offset + 1); s2pool(&dv->error_handler); break; case iop_skipfile: GET_LONG(skips, (pp->str.addr + p_offset)); iomt_skipfile(dv, skips); break; case iop_unload: #ifdef UNIX rts_error(VARLSTCNT(1) ERR_UNIMPLOP); #else assert(FALSE); #endif break; case iop_rewind: iomt_rewind(dv); break; case iop_erasetape: iomt_erase(dv); break; case iop_space: GET_LONG(skips, (pp->str.addr + p_offset)); iomt_skiprecord(dv, skips); break; case iop_writeof: iomt_eof(dv); break; default: break; } p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ? (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]); } if (mt_ptr->labeled == MTLAB_ANSI) { if (mt_ptr->last_op == mt_write) { iomt_tm(dv); iomt_wtansilab(dv, MTL_EOF1 | MTL_EOF2); iomt_tm(dv); iomt_tm(dv); } } else { if (mt_ptr->last_op == mt_write) iomt_eof(dv); #ifdef UNIX if (mt_ptr->cap.req_extra_filemark && mt_ptr->last_op == mt_eof) #else if (mt_ptr->last_op == mt_eof) #endif { iomt_eof(dv); iomt_skipfile(dv, -1); } } if (mt_ptr->buffer) { /* * If bufftoggle is zero, then there is one buffer. * Otherwise, there are two buffers. If bufftoggle is * less than zero, then the buffer pointer points at * the second buffer, and we must adjust the pointer so * that we get to the beginning of the data which has * been malloc'ed. */ if (mt_ptr->bufftoggle < 0) free(mt_ptr->buffer + mt_ptr->bufftoggle); else free(mt_ptr->buffer); } #ifdef DP FPRINTF(stderr, "<< iomt_close\n"); #endif iomt_closesp(mt_ptr->access_id); dv->state = dev_closed; } return; } fis-gtm-V6.0-003/sr_port/iomt_dummy.c0000644000032200000250000000110612201176157016361 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" short iomt_dummy(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout) { return 0; } fis-gtm-V6.0-003/sr_port/iomt_eof.c0000644000032200000250000000153112201176157016001 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iomt_eof.c - Write an EOF marker to tape. */ #include "mdef.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" #include "io_params.h" void iomt_eof (io_desc *dev) { d_mt_struct *mt_ptr; iomt_flush (dev); iomt_qio (dev, IO_WRITEOF, 0); mt_ptr = (d_mt_struct *) dev->dev_sp; mt_ptr->last_op = ((mt_ptr->last_op == mt_eof || mt_ptr->last_op == mt_eof2) ? mt_eof2 : mt_eof); return; } fis-gtm-V6.0-003/sr_port/iomt_erase.c0000644000032200000250000000146112201176157016331 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iomt_erase.c - Erase tape. */ #include "mdef.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" void iomt_erase (io_desc *dev) { static readonly int4 mask = IO_WRITELBLK | IO_M_ERASE; d_mt_struct *mt_ptr; iomt_flush (dev); iomt_rewind (dev); iomt_qio (dev, mask, 0); mt_ptr = (d_mt_struct *) dev->dev_sp; mt_ptr->last_op = mt_rewind; return; } fis-gtm-V6.0-003/sr_port/iomt_flush.c0000644000032200000250000000224312201176157016352 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" void iomt_flush (io_desc *dv) { unsigned char *cp; d_mt_struct *mt_ptr; mt_ptr = (d_mt_struct *) dv->dev_sp; if (mt_ptr->last_op == mt_write) { if (mt_ptr->rec.len) { iomt_wteol (1, dv); assert (mt_ptr->rec.len == 0); } if (mt_ptr->stream) cp = mt_ptr->buffptr; else cp = (unsigned char *) mt_ptr->rec.addr; if (!mt_ptr->fixed && !mt_ptr->stream) cp -= MT_RECHDRSIZ; if (cp > mt_ptr->buffer) { if (cp >= mt_ptr->bufftop) assert (cp == mt_ptr->bufftop); else memset (cp, (mt_ptr->stream ? 0 : '^'), mt_ptr->bufftop - cp); iomt_wrtblk (dv); iomt_wrtinit (dv); } } return; } fis-gtm-V6.0-003/sr_port/iomt_getrec.c0000644000032200000250000000357212201176157016510 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" GBLREF io_pair io_curr_device; void iomt_getrec (io_desc *dv) { #ifdef __MVS__ #pragma convlit(suspend) #endif error_def (ERR_MTRDTHENWRT); error_def (ERR_MTRECTOOBIG); error_def (ERR_MTRECTOOSM); unsigned char *cp, *cx, fill_char; d_mt_struct *mt_ptr; int x, ln; mt_ptr = (d_mt_struct *) dv->dev_sp; cp = mt_ptr->buffptr; if (!mt_ptr->stream) fill_char = '^'; ln = (int)(mt_ptr->bufftop - cp); if (ln < 0) rts_error (VARLSTCNT (1) ERR_MTRECTOOBIG); else if (ln == 0) { iomt_readblk (dv); cp = mt_ptr->buffer; ln = (int)(mt_ptr->bufftop - cp); } else if (*cp == fill_char) { if (!mt_ptr->fixed || !skpc (fill_char, ln, (char *)cp)) { iomt_readblk (dv); cp = mt_ptr->buffer; ln = (int)(mt_ptr->bufftop - cp); } } if (mt_ptr->fixed) { mt_ptr->rec.len = (ln < mt_ptr->record_sz) ? ln : mt_ptr->record_sz; } else if (!mt_ptr->stream) { x = *cp++ - '0'; x = x * 10 + (*cp++ - '0'); x = x * 10 + (*cp++ - '0'); x = x * 10 + (*cp++ - '0') - MT_RECHDRSIZ; if (x < 0) rts_error (VARLSTCNT (1) ERR_MTRECTOOSM); if (x > mt_ptr->record_sz || x > ln) rts_error (VARLSTCNT (1) ERR_MTRECTOOBIG); mt_ptr->rec.len = x; } mt_ptr->rec.addr = (char *) cp; mt_ptr->buffptr = (unsigned char *) (mt_ptr->rec.addr + mt_ptr->rec.len); mt_ptr->last_op = mt_read; return; #ifdef __MVS__ #pragma convlit(resume) #endif } fis-gtm-V6.0-003/sr_port/iomt_rddoslab.c0000644000032200000250000000340612201176157017025 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_stdio.h" #include "io.h" #include "iosp.h" #include "iottdef.h" #include "iomtdef.h" void iomt_rddoslab (io_desc *dv) { static readonly unsigned char label[] = {149, 84, 248, 102, 79, 192, 1, 1, 155, 0, 0, 0, 0, 0}; uint4 status, status1; iosb io_status_blk; d_mt_struct *mt_ptr; error_def (ERR_MTIS); error_def (ERR_MTDOSLAB); int inlen; unsigned char *incp; inlen = sizeof (label); mt_ptr = (d_mt_struct *) dv->dev_sp; incp = (unsigned char *) malloc (mt_ptr->block_sz); io_status_blk.status = 0; #ifdef UNIX if (mt_ptr->mode != MT_M_READ) { status = iomt_reopen (dv, MT_M_READ, FALSE); } #endif status = iomt_rdlblk (mt_ptr, IO_READLBLK, &io_status_blk, incp, mt_ptr->block_sz); if (status != SS_NORMAL || (status1 = io_status_blk.status) != SS_NORMAL) { if (status1 == SS_ENDOFTAPE) dv->dollar.za = 1; else dv->dollar.za = 9; free (incp); rts_error (VARLSTCNT (4) ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); } else dv->dollar.za = 0; if (io_status_blk.char_ct != sizeof (label) || memcmp (incp, label, sizeof (label))) { dv->dollar.za = 9; free (incp); rts_error (VARLSTCNT (6) ERR_MTDOSLAB, 0, ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); } free (incp); return; } fis-gtm-V6.0-003/sr_port/iomt_rdone.c0000644000032200000250000000411312201176157016336 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" #include "iosp.h" GBLREF io_pair io_curr_device; int iomt_rdone(mint *v, int4 t) { error_def(ERR_MTRDTHENWRT); unsigned char x; io_desc *dv; d_mt_struct *mt_ptr; dv = io_curr_device.in; mt_ptr = (d_mt_struct *)dv->dev_sp; #ifdef UNIX if (mt_ptr->mode != MT_M_READ) { uint4 status; status = iomt_reopen(dv, MT_M_READ, FALSE); if (status != SS_NORMAL) rts_error(VARLSTCNT (1) status); } #endif switch (mt_ptr->last_op) { case mt_rewind: if (mt_ptr->labeled == MTLAB_DOS11) iomt_rddoslab(dv); else if (mt_ptr->labeled == MTLAB_ANSI) iomt_rdansistart (dv); /* CAUTION: FALL THROUGH */ case mt_null: if (iomt_readblk(dv)) { if (!mt_ptr->stream) iomt_getrec(dv); } break; case mt_read: break; default: rts_error(VARLSTCNT (1) ERR_MTRDTHENWRT); } if (io_curr_device.in->dollar.zeof) { *v = -1; return TRUE; } if (mt_ptr->stream) { if (mt_ptr->buffptr >= mt_ptr->bufftop) { iomt_readblk (dv); if (io_curr_device.in->dollar.zeof) { *v = -1; return TRUE; } } iomt_rdstream(1, &x, dv); if (io_curr_device.in->dollar.zeof) *v = -1; else if (mt_ptr->rec.len == 0) { *v = 11; io_curr_device.in->dollar.x = 0; io_curr_device.in->dollar.y++; } else *v = (unsigned int)x; } else { if (mt_ptr->rec.len == 0) { *v = 13; io_curr_device.in->dollar.x = 0; io_curr_device.in->dollar.y++; mt_ptr->last_op = mt_null; return TRUE; } *v = (unsigned int)(*mt_ptr->rec.addr++); mt_ptr->rec.len--; } mt_ptr->last_op = mt_read; return TRUE; } fis-gtm-V6.0-003/sr_port/iomt_rdstream.c0000644000032200000250000000305712201176157017056 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" GBLREF io_pair io_curr_device; #define NL 0 void iomt_rdstream (uint4 len, void *str, io_desc *dv) { unsigned char *cp, *cx; uint4 maxreclen; bool endrec; d_mt_struct *mt_ptr; mt_ptr = (d_mt_struct *) dv->dev_sp; maxreclen = (len < mt_ptr->record_sz) ? len : mt_ptr->record_sz; cp = cx = (unsigned char *)str; endrec = FALSE; while (!endrec) { for (; mt_ptr->buffptr < mt_ptr->bufftop && cx - cp < maxreclen;) { switch (*mt_ptr->buffptr) { case NATIVE_CR: case NL: mt_ptr->buffptr++; continue; case NATIVE_VT: case NATIVE_FF: *cx++ = *mt_ptr->buffptr; /* CAUTION : FALL-THROUGH */ case NATIVE_LF: mt_ptr->buffptr++; endrec = TRUE; break; default: *cx++ = *mt_ptr->buffptr++; continue; } break; } if (mt_ptr->buffptr >= mt_ptr->bufftop && !endrec) { iomt_readblk (dv); if (dv->dollar.zeof) endrec = TRUE; } else endrec = TRUE; } mt_ptr->rec.addr = (char *) cp; mt_ptr->rec.len = INTCAST(cx - cp); mt_ptr->last_op = mt_read; } fis-gtm-V6.0-003/sr_port/iomt_read.c0000644000032200000250000000426612201176157016153 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_stdio.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" #include "stringpool.h" #include "iosp.h" GBLREF spdesc stringpool; GBLREF io_pair io_curr_device; int iomt_read(mval *v, int4 t) { error_def(ERR_MTRDTHENWRT); io_desc *dv; d_mt_struct *mt_ptr; #ifdef DP FPRINTF(stderr, ">> iomt_read\n"); #endif assert(stringpool.free >= stringpool.base); assert(stringpool.free <= stringpool.top); dv = io_curr_device.in; mt_ptr = (d_mt_struct *) dv->dev_sp; ENSURE_STP_FREE_SPACE(mt_ptr->record_sz); v->str.addr = (char *) stringpool.free; #ifdef UNIX if (mt_ptr->mode != MT_M_READ) { uint4 status; status = iomt_reopen(dv, MT_M_READ, FALSE); if (status != SS_NORMAL) return (status); } #endif switch (mt_ptr->last_op) { case mt_rewind: if (mt_ptr->labeled == MTLAB_DOS11) iomt_rddoslab (dv); else if (mt_ptr->labeled == MTLAB_ANSI) iomt_rdansistart (dv); /* CAUTION: FALL THROUGH */ case mt_null: if (iomt_readblk(dv)) { if (mt_ptr->stream) iomt_rdstream(mt_ptr->record_sz, v->str.addr, dv); else iomt_getrec(dv); } break; case mt_read: if (mt_ptr->stream) iomt_rdstream(mt_ptr->record_sz, v->str.addr, dv); else iomt_getrec(dv); break; default: rts_error(VARLSTCNT (1) ERR_MTRDTHENWRT); } if (io_curr_device.in->dollar.zeof) { v->str.len = 0; return TRUE; } if (!mt_ptr->stream) memcpy(v->str.addr, mt_ptr->rec.addr, mt_ptr->rec.len); v->str.len = mt_ptr->rec.len; io_curr_device.in->dollar.x = 0; io_curr_device.in->dollar.y++; mt_ptr->last_op = (mt_ptr->buffptr >= mt_ptr->bufftop) ? mt_null : mt_read; #ifdef DP FPRINTF(stderr, "<< iomt_read\n"); #endif return TRUE; } fis-gtm-V6.0-003/sr_port/iomt_readblk.c0000644000032200000250000000464312201176157016643 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "io_params.h" #include "io.h" #include "iosp.h" #include "iottdef.h" #include "iomtdef.h" #include "movtc.h" LITREF unsigned char LIB_AB_EBC_ASC[]; int iomt_readblk (io_desc *dv) { int4 status; unsigned short ct; iosb io_status_blk; d_mt_struct *mt_ptr; error_def (ERR_IOEOF); error_def (ERR_MTRDBADBLK); mt_ptr = (d_mt_struct *) dv->dev_sp; #ifdef DP FPRINTF(stderr, ">> iomt_read_blk\n"); #endif #ifdef UNIX if (mt_ptr->mode != MT_M_READ) { status = iomt_reopen (dv, MT_M_READ, FALSE); if (status != SS_NORMAL) { return (status); } } #endif status = iomt_rdlblk (mt_ptr, mt_ptr->read_mask, &io_status_blk, mt_ptr->buffer, mt_ptr->block_sz); if (status != SS_NORMAL) rts_error (VARLSTCNT (1) status); switch (io_status_blk.status) { case SS_NORMAL: /****************** * This test is nooped ... if not, it would raise an error when the input block size did not * match the declared block size. * if (io_status_blk.char_ct != mt_ptr->block_sz) * rts_error(VARLSTCNT(4) ERR_MTRDBADBLK,2,io_status_blk.char_ct, mt_ptr->block_sz); ******************/ mt_ptr->bufftop = mt_ptr->buffer + io_status_blk.char_ct; dv->dollar.za = 0; break; case SS_ENDOFFILE: if (mt_ptr->labeled == MTLAB_ANSI && !dv->dollar.zeof) iomt_rdansiend (dv); dv->dollar.zeof = TRUE; dv->dollar.za = 0; if (dv->error_handler.len > 0) rts_error (VARLSTCNT (1) ERR_IOEOF); return FALSE; case SS_ENDOFTAPE: dv->dollar.za = 1; rts_error (VARLSTCNT (1) io_status_blk.status); default: dv->dollar.za = 9; rts_error (VARLSTCNT (1) io_status_blk.status); } if (dv->dollar.zeof) { dv->dollar.zeof = FALSE; dv->dollar.x = 0; dv->dollar.y = 0; } if (mt_ptr->ebcdic) movtc (mt_ptr->block_sz, mt_ptr->buffer, LIB_AB_EBC_ASC, mt_ptr->buffer); if (!dv->dollar.za) mt_ptr->buffptr = mt_ptr->buffer; #ifdef DP FPRINTF(stderr, "<< iomt_readblk\n"); #endif return TRUE; } fis-gtm-V6.0-003/sr_port/iomt_readfl.c0000644000032200000250000000442512201176157016472 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_stdio.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" #include "iosp.h" GBLREF io_pair io_curr_device; int iomt_readfl(mval *v, int4 l, int4 t) { error_def (ERR_MTRDTHENWRT); io_desc *dv; d_mt_struct *mt_ptr; dv = io_curr_device.in; mt_ptr = (d_mt_struct *) dv->dev_sp; #ifdef UNIX if (mt_ptr->mode != MT_M_READ) { unsigned short status; status = iomt_reopen(dv, MT_M_READ, FALSE); if (status != SS_NORMAL) return (status); } #endif switch (mt_ptr->last_op) { case mt_rewind: if (mt_ptr->labeled == MTLAB_DOS11) iomt_rddoslab(dv); else if (mt_ptr->labeled == MTLAB_ANSI) iomt_rdansistart(dv); /* CAUTION: FALL THROUGH */ case mt_null: if (iomt_readblk(dv)) { if (mt_ptr->stream) iomt_rdstream(l, v->str.addr, dv); else iomt_getrec(dv); } break; case mt_read: if (mt_ptr->stream) iomt_rdstream(l, v->str.addr, dv); break; default: rts_error(VARLSTCNT (1) ERR_MTRDTHENWRT); } if (io_curr_device.in->dollar.zeof) { v->str.len = 0; return TRUE; } if (mt_ptr->stream) { v->str.len = mt_ptr->rec.len; mt_ptr->last_op = (mt_ptr->buffptr >= mt_ptr->bufftop) ? mt_null : mt_read; } else { if (mt_ptr->rec.len <= l) { memcpy(v->str.addr, mt_ptr->rec.addr, mt_ptr->rec.len); v->str.len = mt_ptr->rec.len; io_curr_device.in->dollar.x = 0; io_curr_device.in->dollar.y++; mt_ptr->last_op = (mt_ptr->buffptr >= mt_ptr->bufftop) ? mt_null : mt_read; mt_ptr->rec.len = 0; } else { memcpy(v->str.addr, mt_ptr->rec.addr, l); v->str.len = l; mt_ptr->rec.addr += l; mt_ptr->rec.len -= l; io_curr_device.in->dollar.x += l; mt_ptr->last_op = mt_read; } if (mt_ptr->rec.len <= 0 && mt_ptr->last_op == mt_read) iomt_getrec(dv); } return TRUE; } fis-gtm-V6.0-003/sr_port/iomt_rewind.c0000644000032200000250000000241512201176157016522 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" #include "io_params.h" void iomt_rewind (io_desc *dev) { d_mt_struct *mt_ptr; mt_ptr = (d_mt_struct *) dev->dev_sp; if (mt_ptr->labeled == MTLAB_ANSI) { if (mt_ptr->last_op == mt_write) { iomt_tm (dev); iomt_wtansilab (dev, MTL_EOF1 | MTL_EOF2); iomt_tm (dev); iomt_tm (dev); } } else { if (mt_ptr->last_op == mt_write) { iomt_flush (dev); iomt_eof (dev); } #ifdef VMS if (mt_ptr->last_op == mt_eof) iomt_eof (dev); #else /* check to see if this device requires an extra filemark */ if (mt_ptr->cap.req_extra_filemark && mt_ptr->last_op == mt_eof) iomt_eof (dev); #endif } iomt_qio (dev, IO_REWIND, 0); mt_ptr->last_op = mt_rewind; dev->dollar.zeof = FALSE; dev->dollar.x = 0; dev->dollar.y = 0; return; } fis-gtm-V6.0-003/sr_port/iomt_skipfile.c0000644000032200000250000000247512201176157017046 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" #include "io_params.h" void iomt_skipfile (io_desc *dev, int count) { d_mt_struct *mt_ptr; error_def (ERR_MTRDTHENWRT); mt_ptr = (d_mt_struct *) dev->dev_sp; if (mt_ptr->last_op == mt_write) { if (count > 0) rts_error (VARLSTCNT (1) ERR_MTRDTHENWRT); iomt_flush (dev); iomt_eof (dev); #ifdef UNIX if (mt_ptr->cap.req_extra_filemark) { iomt_eof (dev); count -= 2; } else #endif count--; } else if (mt_ptr->last_op == mt_eof) { if (count > 0) rts_error (VARLSTCNT (1) ERR_MTRDTHENWRT); #ifdef UNIX if (mt_ptr->cap.req_extra_filemark) { iomt_eof (dev); count -= 1; } #endif } else if (mt_ptr->last_op == mt_eof2 && count > 0) { rts_error (VARLSTCNT (1) ERR_MTRDTHENWRT); } iomt_qio (dev, IO_SKIPFILE, count); mt_ptr->last_op = mt_null; return; } fis-gtm-V6.0-003/sr_port/iomt_skiprecord.c0000644000032200000250000000267112201176157017403 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" #include "io_params.h" void iomt_skiprecord (io_desc *dev, int count) { d_mt_struct *mt_ptr; error_def (ERR_MTRDTHENWRT); mt_ptr = (d_mt_struct *) dev->dev_sp; if (mt_ptr->last_op == mt_write) { if (count > 0) rts_error (VARLSTCNT (1) ERR_MTRDTHENWRT); iomt_flush (dev); iomt_eof (dev); #ifdef UNIX if (mt_ptr->cap.req_extra_filemark) { iomt_eof (dev); iomt_qio (dev, IO_SKIPFILE, (unsigned int)-2); } else #endif iomt_qio (dev, IO_SKIPFILE, (unsigned int)-1); } else if (mt_ptr->last_op == mt_eof) { if (count > 0) rts_error (VARLSTCNT (1) ERR_MTRDTHENWRT); #ifdef UNIX if (mt_ptr->cap.req_extra_filemark) { iomt_eof (dev); iomt_qio (dev, IO_SKIPFILE, (unsigned int)-1); } #endif } else if (mt_ptr->last_op == mt_eof2 && count > 0) { rts_error (VARLSTCNT (1) ERR_MTRDTHENWRT); } iomt_qio (dev, IO_SKIPRECORD, count); mt_ptr->last_op = mt_null; return; } fis-gtm-V6.0-003/sr_port/iomt_use.c0000644000032200000250000001313712201176157016031 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_iconv.h" #include "gtm_string.h" #include "copy.h" #include "io_params.h" #include "io.h" #include "iosp.h" #include "iottdef.h" #include "iomtdef.h" #include "nametabtyp.h" #include "stringpool.h" #include "namelook.h" static readonly nametabent mtlab_names[] = { {3, "ANS"}, {4,"ANSI"}, {3, "DOS"}, {5, "DOS11"} }; static readonly unsigned char mtlab_index[27] = { 0, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4 ,4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ,4, 4, 4 }; static readonly char mtlab_type[]={MTLAB_ANSI, MTLAB_ANSI, MTLAB_DOS11, MTLAB_DOS11}; static readonly nametabent mtwtlab_names[] = { {4, "EOF1"}, {4,"EOF2"}, {4, "HDR1"}, {4, "HDR2"}, {4, "VOL1"} }; static readonly unsigned char mtwtlab_index[27] = { 0, 0, 0, 0, 0, 2, 2, 2, 4, 4, 4, 4, 4 ,4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5 ,5, 5, 5 }; static readonly char mtwtlab_type[]={MTL_EOF1, MTL_EOF2, MTL_HDR1, MTL_HDR2, MTL_VOL1}; LITREF unsigned char io_params_size[]; void iomt_use(io_desc *iod, mval *pp) { unsigned char ch, len; int lab_type; int4 length, width; int4 skips; d_mt_struct *mt_ptr, *out_ptr; io_desc *d_in, *d_out; char *tab; int p_offset; error_def(ERR_MTINVLAB); error_def(ERR_DEVPARMNEG); error_def(ERR_UNIMPLOP); p_offset = 0; d_in = iod->pair.in; d_out = iod->pair.out; mt_ptr = (d_mt_struct *)iod->dev_sp; out_ptr = (d_mt_struct *)d_out->dev_sp; while (*(pp->str.addr + p_offset) != iop_eol) { switch (ch = *(pp->str.addr + p_offset++)) { case iop_ebcdic: mt_ptr->ebcdic = TRUE; break; case iop_noebcdic: mt_ptr->ebcdic = FALSE; break; case iop_newversion: mt_ptr->newversion = TRUE; break; case iop_label: len = *(pp->str.addr + p_offset); tab = pp->str.addr + p_offset + 1; if ((lab_type = namelook(mtlab_index, mtlab_names, tab, len)) < 0) rts_error(VARLSTCNT(1) ERR_MTINVLAB); mt_ptr->labeled = mtlab_type[lab_type]; break; case iop_nolabel: mt_ptr->labeled = FALSE; break; case iop_rdcheckdata: mt_ptr->read_mask |= IO_M_DATACHECK; break; case iop_nordcheckdata: mt_ptr->read_mask &= (~(IO_M_DATACHECK)); break; case iop_wtcheckdata: mt_ptr->write_mask |= IO_M_DATACHECK; break; case iop_nowtcheckdata: mt_ptr->write_mask &= (~(IO_M_DATACHECK)); break; case iop_inhretry: mt_ptr->write_mask |= IO_M_INHRETRY; mt_ptr->read_mask |= IO_M_INHRETRY; break; case iop_retry: mt_ptr->write_mask &= ~IO_M_INHRETRY; mt_ptr->read_mask &= ~IO_M_INHRETRY; break; case iop_inhextgap: mt_ptr->write_mask |= IO_M_INHEXTGAP; break; case iop_extgap: mt_ptr->write_mask &= ~IO_M_INHEXTGAP; break; case iop_length: GET_LONG(length, (pp->str.addr + p_offset)); if (length < 0) rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); iod->length = length; break; case iop_width: GET_LONG(width, (pp->str.addr + p_offset)); if (width < 0) rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); if (width == 0) { iod->wrap = FALSE; iod->width = mt_ptr->record_sz; } else if (width <= mt_ptr->record_sz) { iomt_flush(iod); iod->width = width; iod->wrap = TRUE; } break; case iop_wrap: out_ptr->wrap = TRUE; break; case iop_nowrap: out_ptr->wrap = FALSE; break; case iop_skipfile: GET_LONG(skips, (pp->str.addr + p_offset)); iomt_skipfile(iod, skips); break; case iop_unload: assert(FALSE); break; case iop_rewind: iomt_rewind(iod); break; case iop_erasetape: iomt_erase(iod); break; case iop_space: GET_LONG(skips, (pp->str.addr + p_offset)); iomt_skiprecord(iod, skips); break; case iop_writeof: iomt_eof(iod); break; case iop_writetm: iomt_tm(iod); break; case iop_writelb: len = *(pp->str.addr + p_offset); tab = pp->str.addr + p_offset + 1; if ((lab_type = namelook(mtwtlab_index, mtwtlab_names, tab, len)) < 0) rts_error(VARLSTCNT(1) ERR_MTINVLAB); iomt_wtansilab(iod, mtwtlab_type[lab_type]); break; case iop_next: rts_error(VARLSTCNT(1) ERR_UNIMPLOP); break; case iop_exception: iod->error_handler.len = *(pp->str.addr + p_offset); iod->error_handler.addr = (char *)(pp->str.addr + p_offset + 1); s2pool(&iod->error_handler); break; case iop_ipchset: { #if defined(KEEP_zOS_EBCDIC) || defined(VMS) if ( (iconv_t)0 != iod->input_conv_cd ) { ICONV_CLOSE_CD(iod->input_conv_cd); } SET_CODE_SET(iod->in_code_set, (char *)(pp->str.addr + p_offset + 1)); if (DEFAULT_CODE_SET != iod->in_code_set) ICONV_OPEN_CD(iod->input_conv_cd, (char *)(pp->str.addr + p_offset + 1), INSIDE_CH_SET); #endif break; } case iop_opchset: { #if defined(KEEP_zOS_EBCDIC) || defined(VMS) if ( (iconv_t) 0 != iod->output_conv_cd ) { ICONV_CLOSE_CD(iod->output_conv_cd); } SET_CODE_SET(iod->out_code_set, (char *)(pp->str.addr + p_offset + 1)); if (DEFAULT_CODE_SET != iod->out_code_set) ICONV_OPEN_CD(iod->output_conv_cd, INSIDE_CH_SET, (char *)(pp->str.addr + p_offset + 1)); #endif break; } default: break; } p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ? (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]); } } fis-gtm-V6.0-003/sr_port/iomt_vlflush.c0000644000032200000250000000241312201176157016713 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" GBLREF io_pair io_curr_device; void iomt_vlflush(io_desc *dv) { int len; unsigned char *cp, fill_char; d_mt_struct *mt_ptr; mt_ptr = (d_mt_struct *) dv->dev_sp; assert(mt_ptr->fixed == FALSE); if (!mt_ptr->stream) { fill_char = '^'; len = mt_ptr->rec.len + MT_RECHDRSIZ; cp = (unsigned char *) ( mt_ptr->rec.addr - MT_RECHDRSIZ); memcpy(mt_ptr->buffer + mt_ptr->bufftoggle, cp, len); memset(cp, fill_char, mt_ptr->bufftop - cp); } iomt_wrtblk(dv); mt_ptr->buffer += mt_ptr->bufftoggle; mt_ptr->bufftop += mt_ptr->bufftoggle; mt_ptr->bufftoggle = -mt_ptr->bufftoggle; mt_ptr->rec.addr = (char *) mt_ptr->buffer; mt_ptr->buffptr = mt_ptr->buffer; if (!mt_ptr->stream) mt_ptr->rec.addr += MT_RECHDRSIZ; return; } fis-gtm-V6.0-003/sr_port/iomt_write.c0000644000032200000250000000457412201176157016374 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" #include "iosp.h" GBLREF io_pair io_curr_device; void iomt_write (mstr *v) { error_def (ERR_MTRDONLY); io_desc *io_ptr; unsigned char *inpt; int inlen, outlen, n; unsigned char *outcp; d_mt_struct *mt_ptr; io_ptr = io_curr_device.out; mt_ptr = (d_mt_struct *) io_ptr->dev_sp; if (mt_ptr->read_only) rts_error (VARLSTCNT (1) ERR_MTRDONLY); #ifdef UNIX if (mt_ptr->mode != MT_M_WRITE) { uint4 status; status = iomt_reopen (io_ptr, MT_M_WRITE, FALSE); } #endif if (mt_ptr->last_op != mt_write) iomt_wrtinit (io_ptr); inlen = v->len; outlen = io_ptr->width - mt_ptr->rec.len; if (!mt_ptr->wrap && inlen > outlen) inlen = outlen; if (!inlen) return; for (inpt = (unsigned char *) v->addr;; inpt += n) { if (mt_ptr->stream) { outcp = mt_ptr->buffptr; n = (outcp + inlen > mt_ptr->bufftop) ? (int)(mt_ptr->bufftop - outcp) : inlen; if (n <= 0) { iomt_vlflush (io_ptr); outcp = (unsigned char *) mt_ptr->rec.addr; } } else { outcp = (unsigned char *) mt_ptr->rec.addr + mt_ptr->rec.len; n = (inlen > outlen) ? outlen : inlen; if (mt_ptr->fixed) assert (outcp + n <= mt_ptr->bufftop); else { if (outcp + n >= mt_ptr->bufftop) { iomt_vlflush (io_ptr); outcp = (unsigned char *) (mt_ptr->rec.addr + mt_ptr->rec.len); } } } memcpy (outcp, inpt, n); mt_ptr->buffptr = outcp + n; mt_ptr->rec.len += n; io_ptr->dollar.x += n; if ((inlen -= n) <= 0) break; if (!mt_ptr->stream) { iomt_wteol (1, io_ptr); outlen = io_ptr->width - mt_ptr->rec.len; } } if (mt_ptr->stream && io_ptr->dollar.x >= io_ptr->width && io_ptr->wrap) { io_ptr->dollar.y += (io_ptr->dollar.x / io_ptr->width); if (io_ptr->length) io_ptr->dollar.y %= io_ptr->length; io_ptr->dollar.x %= io_ptr->width; } return; } fis-gtm-V6.0-003/sr_port/iomt_wrtblk.c0000644000032200000250000000333512201176157016541 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2004 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "io.h" #include "iosp.h" #include "iottdef.h" #include "iomtdef.h" #ifdef UNIX #include #endif #include "movtc.h" LITREF unsigned char LIB_AB_ASC_EBC[]; void iomt_wrtblk (io_desc *dv) { uint4 status; iosb io_status_blk; d_mt_struct *mt_ptr; error_def (ERR_MTIS); #ifdef DP FPRINTF(stderr, ">> iomt_wrtblk\n"); #endif mt_ptr = (d_mt_struct *) dv->dev_sp; if (mt_ptr->ebcdic) movtc (mt_ptr->block_sz, mt_ptr->buffer, LIB_AB_ASC_EBC, mt_ptr->buffer); io_status_blk.status = 0; #ifdef UNIX if (mt_ptr->mode != MT_M_WRITE) { status = iomt_reopen (dv, MT_M_WRITE, FALSE); if (status != SS_NORMAL) return; } #endif status = iomt_wtlblk (mt_ptr->access_id, mt_ptr->write_mask, &io_status_blk, mt_ptr->buffer, mt_ptr->block_sz); if ((status != SS_NORMAL) || ((status = io_status_blk.status) != SS_NORMAL)) { if (status == SS_ENDOFTAPE) dv->dollar.za = 1; else { dv->dollar.za = 9; #ifdef UNIX rts_error (VARLSTCNT (6) errno, 0, ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); #else /* VAX */ rts_error(VARLSTCNT(4) ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); #endif } } else dv->dollar.za = 0; #ifdef DP FPRINTF(stderr, "<< iomt_wrtblk\n"); #endif return; } fis-gtm-V6.0-003/sr_port/iomt_wrtinit.c0000644000032200000250000000325512201176157016735 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" #include "iosp.h" #include "copy.h" int iomt_wrtinit (io_desc *dv) { unsigned char *cp; uint4 *quadbyteptr; int x, y; d_mt_struct *mt_ptr; static readonly unsigned char litzeros[4] = {'0', '0', '0', '0'}; mt_ptr = (d_mt_struct *) dv->dev_sp; #ifdef UNIX if (mt_ptr->mode != MT_M_WRITE) { uint4 status; status = iomt_reopen (dv, MT_M_WRITE, FALSE); if (status != SS_NORMAL) { return (status); } } #endif mt_ptr->bufftop = mt_ptr->buffer + mt_ptr->block_sz; mt_ptr->buffptr = mt_ptr->buffer; if (mt_ptr->fixed || mt_ptr->stream) { mt_ptr->rec.addr = (char *) mt_ptr->buffer; mt_ptr->rec.len = 0; } else { quadbyteptr = (uint4 *) mt_ptr->buffer; GET_LONGP(quadbyteptr, &litzeros[0]); quadbyteptr++; mt_ptr->rec.addr = (char *) quadbyteptr; mt_ptr->rec.len = 0; } if (mt_ptr->labeled && mt_ptr->last_op == mt_rewind) { if (mt_ptr->labeled == MTLAB_DOS11) iomt_wtdoslab (dv); else if (mt_ptr->labeled == MTLAB_ANSI) { iomt_wtansilab (dv, MTL_VOL1 | MTL_HDR1 | MTL_HDR2); iomt_tm (dv); } else GTMASSERT; } dv->dollar.za = 0; mt_ptr->last_op = mt_write; return SS_NORMAL; } fis-gtm-V6.0-003/sr_port/iomt_wtdoslab.c0000644000032200000250000000310512201176157017046 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "io.h" #include "iosp.h" #include "iottdef.h" #include "iomtdef.h" void iomt_wtdoslab (io_desc *dv) { static readonly unsigned char label[] = {149, 84, 248, 102, 79, 192, 1, 1, 155, 0, 0, 0, 0, 0}; uint4 status; iosb io_status_blk; unsigned char outcp[SIZEOF(label)]; d_mt_struct *mt_ptr; error_def (ERR_MTIS); error_def (ERR_MTRDONLY); mt_ptr = (d_mt_struct *) dv->dev_sp; if (mt_ptr->read_only) rts_error (VARLSTCNT (1) ERR_MTRDONLY); #ifdef UNIX if (mt_ptr->mode != MT_M_WRITE) { status = iomt_reopen (dv, MT_M_WRITE, FALSE); if (status != SS_NORMAL) return; } #endif memcpy(&outcp[0], &label[0], SIZEOF(outcp)); io_status_blk.status = 0; status = iomt_wtlblk(mt_ptr->access_id, IO_WRITELBLK, &io_status_blk, outcp, SIZEOF(outcp)); if ((status != SS_NORMAL) || ((status = io_status_blk.status) != SS_NORMAL)) { if (status == SS_ENDOFTAPE) dv->dollar.za = 1; else dv->dollar.za = 9; rts_error (VARLSTCNT (4) ERR_MTIS, 2, dv->trans_name->len, dv->trans_name->dollar_io); } else dv->dollar.za = 0; return; } fis-gtm-V6.0-003/sr_port/iomt_wteol.c0000644000032200000250000000606412201176157016370 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_stdio.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" #include "iosp.h" #include "copy.h" #define EBCDIC_LITZERO '\360' #define ASCII_LITZERO '0' #ifdef __MVS__ #define MT_LITZERO EBCDIC_LITZERO #else #define MT_LITZERO ASCII_LITZERO #endif void iomt_wteol (int4 cnt, io_desc *dv) { unsigned char *cp; uint4 *quadbyteptr; d_mt_struct *mt_ptr; error_def (ERR_MTRDONLY); int i, x, y; static readonly unsigned char litzeros[4] = {MT_LITZERO, MT_LITZERO, MT_LITZERO, MT_LITZERO}; mt_ptr = (d_mt_struct *) dv->dev_sp; if (mt_ptr->read_only) rts_error (VARLSTCNT (1) ERR_MTRDONLY); #ifdef UNIX if (mt_ptr->mode != MT_M_WRITE) { uint4 status; status = iomt_reopen (dv, MT_M_WRITE, FALSE); if (status != SS_NORMAL) { /*return(status);*/ return; } } #endif if (mt_ptr->last_op != mt_write) iomt_wrtinit (dv); for (i = 0; i < cnt; i++) { if (mt_ptr->fixed) { x = mt_ptr->record_sz - mt_ptr->rec.len; if (x > 0) memset (mt_ptr->rec.addr + mt_ptr->rec.len, SP, x); mt_ptr->rec.addr += mt_ptr->record_sz; mt_ptr->rec.len = 0; if (mt_ptr->rec.addr >= (char *) mt_ptr->bufftop) { assert (mt_ptr->rec.addr == (char *) mt_ptr->bufftop); iomt_wrtblk (dv); mt_ptr->rec.addr = (char *) mt_ptr->buffer; } } else if (!mt_ptr->stream) { cp = (unsigned char *) mt_ptr->rec.addr; x = mt_ptr->rec.len; quadbyteptr = (uint4 *) (cp + x); x += MT_RECHDRSIZ; y = x / 10; *--cp = x - y * 10 + MT_LITZERO; if (x = y) { *--cp = x - (y /= 10) * 10 + MT_LITZERO; if (x = y) { *--cp = x - (y /= 10) * 10 + MT_LITZERO; if (x = y) { *--cp = x - (y / 10) * 10 + MT_LITZERO; } } } if (((unsigned char *) quadbyteptr) + MT_RECHDRSIZ > mt_ptr->bufftop) { cp = (unsigned char *) (mt_ptr->rec.addr + mt_ptr->rec.len); x = (int)(mt_ptr->bufftop - cp); assert (x >= 0); if (x > 0) memset (cp, '^', x); iomt_wrtblk (dv); quadbyteptr = (uint4 *) mt_ptr->buffer; } GET_LONGP(quadbyteptr, &litzeros[0]); quadbyteptr++; mt_ptr->rec.addr = (char *) quadbyteptr; mt_ptr->rec.len = 0; } else { assert (mt_ptr->stream); mt_ptr->rec.len = 0; if (mt_ptr->buffptr >= mt_ptr->bufftop) iomt_vlflush (dv); *mt_ptr->buffptr++ = NATIVE_CR; if (mt_ptr->buffptr >= mt_ptr->bufftop) iomt_vlflush (dv); *mt_ptr->buffptr++ = NATIVE_LF; if (mt_ptr->buffptr >= mt_ptr->bufftop) iomt_vlflush (dv); } } dv->dollar.x = 0; dv->dollar.y += cnt; if (dv->length) dv->dollar.y %= dv->length; return; } fis-gtm-V6.0-003/sr_port/iomt_wtff.c0000644000032200000250000000200612201176157016174 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "iottdef.h" #include "iomtdef.h" #include "iosp.h" GBLREF io_pair io_curr_device; void iomt_wtff (void) { io_desc *dv; d_mt_struct *mt_ptr; dv = io_curr_device.out; mt_ptr = (d_mt_struct *) dv->dev_sp; #ifdef UNIX if (mt_ptr->mode != MT_M_WRITE) { uint4 status; status = iomt_reopen (dv, MT_M_WRITE, FALSE); if (status != SS_NORMAL) return; } #endif iomt_wtone (12); if (!mt_ptr->stream) iomt_wteol (1, dv); mt_ptr->rec.len = 0; io_curr_device.out->dollar.x = 0; io_curr_device.out->dollar.y = 0; } fis-gtm-V6.0-003/sr_port/iomt_wtone.c0000644000032200000250000000120612201176157016363 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" GBLREF boolean_t gtm_utf8_mode; void iomt_wtone(int ch) { mstr temp; char c; c = (int)ch; temp.len = 1; temp.addr = &c; iomt_write(&temp); return; } fis-gtm-V6.0-003/sr_port/ionl_close.c0000644000032200000250000000105512201176157016327 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" void ionl_close(io_desc *dv, mval *p) { dv->state = dev_closed; return; } fis-gtm-V6.0-003/sr_port/ionl_dummy.c0000644000032200000250000000110612201176157016352 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" short ionl_dummy(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout) { return 0; } fis-gtm-V6.0-003/sr_port/ionl_flush.c0000644000032200000250000000101312201176157016335 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" void ionl_flush(io_desc *iod) { return; } fis-gtm-V6.0-003/sr_port/ionl_open.c0000644000032200000250000000414412201176157016165 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "errno.h" #include "gtm_unistd.h" #include "io_params.h" #include "io.h" #include "stringpool.h" #include "gtmio.h" #define DEF_NL_WIDTH 255 #define DEF_NL_LENGTH 66 LITREF unsigned char io_params_size[]; short ionl_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout) { unsigned char ch; io_desc *d_in, *d_out, *ioptr; int p_offset, status; p_offset = 0; /* If UNIX, then /dev/null was actually opened by io_open_try so we have to close it since we don't use the device, we just simulate it by doing nothing on writes except maintaining the appropriate pointers. We test for fd >= 0 since the less than zero values mean no device was opened. */ UNIX_ONLY( if (0 <= fd) CLOSEFILE_RESET(fd, status); /* resets "fd" to FD_INVALID */ ); ioptr = dev_name->iod; ioptr->state = dev_open; d_in = ioptr->pair.in; d_out = ioptr->pair.out; ioptr->length = DEF_NL_LENGTH; ioptr->width = DEF_NL_WIDTH; ioptr->wrap = TRUE; ioptr->dollar.za = 0; ioptr->dollar.zeof = FALSE; ioptr->dollar.x = 0; ioptr->dollar.y = 0; while (*(pp->str.addr + p_offset) != iop_eol) { if ((ch = *(pp->str.addr + p_offset++)) == iop_wrap) d_out->wrap = TRUE; if ((ch = *(pp->str.addr + p_offset++)) == iop_nowrap) d_out->wrap = FALSE; if ((ch = *(pp->str.addr + p_offset++)) == iop_exception) { ioptr->error_handler.len = *(pp->str.addr + p_offset); ioptr->error_handler.addr = (char *)(pp->str.addr + p_offset + 1); s2pool(&ioptr->error_handler); break; } p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ? (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]); } return TRUE; } fis-gtm-V6.0-003/sr_port/ionl_rdone.c0000644000032200000250000000114712201176157016333 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* ionl_rdone.c */ #include "mdef.h" #include "io.h" int ionl_rdone(mint *val, int4 timeout) { mval tmp; *val = -1; return ionl_readfl(&tmp, 1, timeout); } fis-gtm-V6.0-003/sr_port/ionl_read.c0000644000032200000250000000107112201176157016133 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" int ionl_read(mval *val, int4 timeout) { return ionl_readfl(val, 1, timeout); } fis-gtm-V6.0-003/sr_port/ionl_readfl.c0000644000032200000250000000160112201176157016454 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" GBLREF io_pair io_curr_device; int ionl_readfl(mval *val, int4 width, int4 timeout) { io_desc *dv; error_def(ERR_IOEOF); val->str.len = 0; dv = io_curr_device.in; dv->dollar.x = 0; dv->dollar.y++; if (dv->dollar.zeof || (dv->error_handler.len > 0)) { dv->dollar.zeof = TRUE; dv->dollar.za = 9; rts_error(VARLSTCNT(1) ERR_IOEOF); } dv->dollar.za = 0; dv->dollar.zeof = TRUE; return TRUE; } fis-gtm-V6.0-003/sr_port/ionl_use.c0000644000032200000250000000775012201176157016026 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_iconv.h" #include "gtm_stdlib.h" #include "copy.h" #include "io_params.h" #include "io.h" #include "iosp.h" #include "iottdef.h" #include "nametabtyp.h" #include "stringpool.h" #include "namelook.h" LITREF nametabent filter_names[]; LITREF unsigned char filter_index[27]; LITREF unsigned char io_params_size[]; void ionl_use(io_desc *iod, mval *pp) { unsigned char ch, len; int fil_type; int4 width, length; io_desc *d_in, *d_out; char *tab; int p_offset; error_def(ERR_TTINVFILTER); error_def(ERR_DEVPARMNEG); p_offset = 0; d_in = iod->pair.in; d_out = iod->pair.out; assert(iod->state == dev_open); while (*(pp->str.addr + p_offset) != iop_eol) { switch (ch = *(pp->str.addr + p_offset++)) { case iop_exception: iod->error_handler.len = *(pp->str.addr + p_offset); iod->error_handler.addr = (char *)(pp->str.addr + p_offset + 1); s2pool(&iod->error_handler); break; case iop_filter: len = *(pp->str.addr + p_offset); tab = pp->str.addr + p_offset + 1; if ((fil_type = namelook(filter_index, filter_names, tab, len)) < 0) { rts_error(VARLSTCNT(1) ERR_TTINVFILTER); return; } switch (fil_type) { case 0: iod->write_filter |= CHAR_FILTER; break; case 1: iod->write_filter |= ESC1; break; case 2: iod->write_filter &= ~CHAR_FILTER; break; case 3: iod->write_filter &= ~ESC1; break; } break; case iop_nofilter: iod->write_filter = 0; break; case iop_length: GET_LONG(length, pp->str.addr + p_offset); if (length < 0) rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); d_out->length = length; break; case iop_width: GET_LONG(width, pp->str.addr + p_offset); if (width < 0) rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); if (width == 0) { d_out->wrap = FALSE; d_out->width = TTDEF_PG_WIDTH; } else { d_out->width = width; d_out->wrap = TRUE; } break; case iop_wrap: d_out->wrap = TRUE; break; case iop_nowrap: d_out->wrap = FALSE; break; case iop_x: { int4 col; GET_LONG(col, pp->str.addr + p_offset); d_out->dollar.x = col; if ((int4)(d_out->dollar.x) < 0) d_out->dollar.x = 0; if (d_out->dollar.x > d_out->width && d_out->wrap) d_out->dollar.x %= d_out->width; break; } case iop_y: { int4 row; GET_LONG(row, (pp->str.addr + p_offset)); d_out->dollar.y = row; if ((int4)(d_out->dollar.y) < 0) d_out->dollar.y = 0; if (d_out->length) d_out->dollar.y %= d_out->length; break; } case iop_ipchset: { #if defined(KEEP_zOS_EBCDIC) || defined(VMS) if ( (iconv_t)0 != iod->input_conv_cd ) { ICONV_CLOSE_CD(iod->input_conv_cd); } SET_CODE_SET(iod->in_code_set, (char *)(pp->str.addr + p_offset + 1)); if (DEFAULT_CODE_SET != iod->in_code_set) ICONV_OPEN_CD(iod->input_conv_cd, (char *)(pp->str.addr + p_offset + 1), INSIDE_CH_SET); #endif break; } case iop_opchset: { #if defined(KEEP_zOS_EBCDIC) || defined(VMS) if ( (iconv_t) 0 != iod->output_conv_cd ) { ICONV_CLOSE_CD(iod->output_conv_cd); } SET_CODE_SET(iod->out_code_set, (char *)(pp->str.addr + p_offset + 1)); if (DEFAULT_CODE_SET != iod->out_code_set) ICONV_OPEN_CD(iod->output_conv_cd, INSIDE_CH_SET, (char *)(pp->str.addr + p_offset + 1)); #endif break; } } p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ? (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]); } return; } fis-gtm-V6.0-003/sr_port/ionl_write.c0000644000032200000250000000132212201176157016351 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "dollarx.h" GBLREF io_pair io_curr_device; void ionl_write(mstr *v) { io_desc *io_ptr; io_ptr = io_curr_device.out; io_ptr->dollar.zeof = FALSE; dollarx(io_ptr, (uchar_ptr_t)v->addr, (uchar_ptr_t)v->addr + v->len); return; } fis-gtm-V6.0-003/sr_port/ionl_wteol.c0000644000032200000250000000313212201176157016352 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "io.h" #include "iottdef.h" /* essentially the same as iott_wteol */ void ionl_wteol(int4 val, io_desc *io_ptr) { mstr eol; int eol_cnt; assert(val); io_ptr->esc_state = START; eol.len = STRLEN(NATIVE_TTEOL); eol.addr = (char *)NATIVE_TTEOL; for (eol_cnt = val; eol_cnt--; ) { io_ptr->dollar.x = 0; /* so that ionl_write doesn't try to wrap (based on escape state and width) */ ionl_write(&eol); } /* $X is maintained in VMS without the below assignment (resetting to 0) because the NATIVE_TTEOL is \015\012 * and the (\015) triggers appropriate maintenance of $X. In UNIX, NATIVE_TTEOL is \012, so * FILTER=CHARACTER effectively turns off all $X maintenance (except for WRAP logic). * In VMS the below assignment is not necessary, but harmless; it is always logically correct. */ io_ptr->dollar.x = 0; if (!(io_ptr->write_filter & CHAR_FILTER)) { /* If no FILTER and EOL, also maintain $Y; * If FILTER, dollarx() of the linefeed character \012 takes care of this maintenance. */ io_ptr->dollar.y += val; if (io_ptr->length) io_ptr->dollar.y %= io_ptr->length; } return; } fis-gtm-V6.0-003/sr_port/ionl_wtff.c0000644000032200000250000000127412201176157016173 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" GBLREF io_pair io_curr_device; void ionl_wtff(void) { io_curr_device.out->esc_state = START; io_curr_device.out->dollar.zeof = FALSE; io_curr_device.out->dollar.x = 0; io_curr_device.out->dollar.y = 0; return; } fis-gtm-V6.0-003/sr_port/ionl_wtone.c0000644000032200000250000000114412201176157016355 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" void ionl_wtone(int v) { mstr temp; char p; p = (char)v; temp.len = 1; temp.addr = &p; ionl_write(&temp); return; } fis-gtm-V6.0-003/sr_port/iop.h0000644000032200000250000002771512201176157015010 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iop.h, to be included when io parameters need enumeration */ /* structure: enum_value, enum_mnemonic, data_element_size, legal_operations , source_value_type */ /* last entry = n_iops is the size of the table */ /* Must add entries at the end in order to avoid a recompile */ IOP_DESC(0, iop_eol, 0, 0, 0), IOP_DESC(1, iop_canctlo, 0, IOP_USE_OK, 0), IOP_DESC(2, iop_cenable, 0, IOP_USE_OK, 0), IOP_DESC(3, iop_nocenable, 0, IOP_USE_OK, 0), IOP_DESC(4, iop_clearscreen, 0, IOP_USE_OK, 0), IOP_DESC(5, iop_convert, 0, IOP_USE_OK, 0), IOP_DESC(6, iop_noconvert, 0, IOP_USE_OK, 0), IOP_DESC(7, iop_downscroll, 0, IOP_USE_OK, 0), IOP_DESC(8, iop_echo, 0, IOP_USE_OK, 0), IOP_DESC(9, iop_noecho, 0, IOP_USE_OK, 0), IOP_DESC(10, iop_eraseline, 0, IOP_USE_OK, 0), IOP_DESC(11, iop_field, SIZEOF(short), IOP_USE_OK, IOP_SRC_INT), IOP_DESC(12, iop_terminator, SIZEOF(int4) * 8, IOP_USE_OK, IOP_SRC_LNGMSK), IOP_DESC(13, iop_upscroll, 0, IOP_USE_OK, 0), IOP_DESC(14, iop_width, SIZEOF(int4), IOP_USE_OK, IOP_SRC_INT), IOP_DESC(15, iop_blocksize, SIZEOF(int4), IOP_OPEN_OK, IOP_SRC_INT), IOP_DESC(16, iop_ctrap, SIZEOF(int4), IOP_USE_OK, IOP_SRC_MSK), IOP_DESC(17, iop_x, SIZEOF(int4), IOP_USE_OK, IOP_SRC_INT), IOP_DESC(18, iop_y, SIZEOF(int4), IOP_USE_OK, IOP_SRC_INT), IOP_DESC(19, iop_escape, 0, IOP_USE_OK, 0), IOP_DESC(20, iop_noescape, 0, IOP_USE_OK, 0), IOP_DESC(21, iop_allocation, SIZEOF(int4), IOP_OPEN_OK, IOP_SRC_INT), IOP_DESC(22, iop_contiguous, 0, IOP_OPEN_OK, 0), IOP_DESC(23, iop_delete, 0, IOP_CLOSE_OK, 0), IOP_DESC(24, iop_extension, SIZEOF(unsigned short), IOP_OPEN_OK, IOP_SRC_INT), IOP_DESC(25, iop_newversion, 0, IOP_OPEN_OK, 0), IOP_DESC(26, iop_nosequential, 0, IOP_OPEN_OK, 0), IOP_DESC(27, iop_s_protection, SIZEOF(char), IOP_OPEN_OK|IOP_CLOSE_OK, IOP_SRC_PRO), IOP_DESC(28, iop_w_protection, SIZEOF(char), IOP_OPEN_OK|IOP_CLOSE_OK, IOP_SRC_PRO), IOP_DESC(29, iop_g_protection, SIZEOF(char), IOP_OPEN_OK|IOP_CLOSE_OK, IOP_SRC_PRO), IOP_DESC(30, iop_o_protection, SIZEOF(char), IOP_OPEN_OK|IOP_CLOSE_OK, IOP_SRC_PRO), IOP_DESC(31, iop_readonly, 0, IOP_OPEN_OK, 0), IOP_DESC(32, iop_recordsize, SIZEOF(int4), IOP_OPEN_OK, IOP_SRC_INT), IOP_DESC(33, iop_shared, 0, IOP_OPEN_OK, 0), IOP_DESC(34, iop_spool, 0, IOP_CLOSE_OK, 0), IOP_DESC(35, iop_submit, 0, IOP_CLOSE_OK, 0), IOP_DESC(36, iop_rfa, 0, IOP_USE_OK, 0), IOP_DESC(37, iop_space, SIZEOF(int4), IOP_USE_OK|IOP_CLOSE_OK, IOP_SRC_INT), IOP_DESC(38, iop_queue, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(39, iop_rename, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(40, iop_uic, IOP_VAR_SIZE, IOP_OPEN_OK|IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(41, iop_wrap, 0, IOP_OPEN_OK|IOP_USE_OK, 0), IOP_DESC(42, iop_nowrap, 0, IOP_OPEN_OK|IOP_USE_OK, 0), IOP_DESC(43, iop_rewind, 0, IOP_OPEN_OK|IOP_USE_OK|IOP_CLOSE_OK, 0), IOP_DESC(44, iop_exception, IOP_VAR_SIZE, IOP_OPEN_OK|IOP_USE_OK|IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(45, iop_ebcdic, 0, IOP_OPEN_OK|IOP_USE_OK, 0), IOP_DESC(46, iop_label, IOP_VAR_SIZE, IOP_OPEN_OK | IOP_USE_OK, IOP_SRC_STR), IOP_DESC(47, iop_nolabel, 0, IOP_OPEN_OK | IOP_USE_OK, 0), IOP_DESC(48, iop_newtape, 0, 0, 0), IOP_DESC(49, iop_mount, 0, IOP_OPEN_OK, 0), IOP_DESC(50, iop_fixed, 0, IOP_OPEN_OK, 0), IOP_DESC(51, iop_erasetape, 0, IOP_OPEN_OK | IOP_USE_OK | IOP_CLOSE_OK, 0), IOP_DESC(52, iop_next, 0, IOP_USE_OK, 0), IOP_DESC(53, iop_writeof, 0, IOP_USE_OK|IOP_CLOSE_OK, 0), IOP_DESC(54, iop_noreadonly, 0, IOP_OPEN_OK, 0), IOP_DESC(55, iop_rdcheckdata, 0, IOP_OPEN_OK|IOP_USE_OK, 0), IOP_DESC(56, iop_nordcheckdata, 0, IOP_OPEN_OK|IOP_USE_OK, 0), IOP_DESC(57, iop_wtcheckdata, 0, IOP_OPEN_OK|IOP_USE_OK, 0), IOP_DESC(58, iop_nowtcheckdata, 0, IOP_OPEN_OK|IOP_USE_OK, 0), IOP_DESC(59, iop_inhretry, 0, IOP_OPEN_OK|IOP_USE_OK, 0), IOP_DESC(60, iop_inhextgap, 0, IOP_OPEN_OK|IOP_USE_OK, 0), IOP_DESC(61, iop_unload, 0, IOP_CLOSE_OK, 0), IOP_DESC(62, iop_skipfile, SIZEOF(int4), IOP_USE_OK, IOP_SRC_INT), IOP_DESC(63, iop_writeonly, 0, IOP_OPEN_OK, 0), IOP_DESC(64, iop_nowriteonly, 0, IOP_OPEN_OK, 0), IOP_DESC(65, iop_wait, 0, IOP_USE_OK, 0), IOP_DESC(66, iop_tmpmbx, 0, IOP_OPEN_OK, 0), IOP_DESC(67, iop_prmmbx, 0, IOP_OPEN_OK, 0), IOP_DESC(68, iop_append, 0, IOP_OPEN_OK, 0), IOP_DESC(69, iop_nowait, 0, IOP_USE_OK, 0), IOP_DESC(70, iop_nofixed, 0, IOP_OPEN_OK, 0), IOP_DESC(71, iop_stream, 0, IOP_OPEN_OK, 0), IOP_DESC(72, iop_nostream, 0, IOP_OPEN_OK, 0), IOP_DESC(73, iop_flush, 0, IOP_USE_OK, 0), IOP_DESC(74, iop_length, SIZEOF(int4), IOP_USE_OK, IOP_SRC_INT), IOP_DESC(75, iop_typeahead, 0, IOP_USE_OK, 0), IOP_DESC(76, iop_notypeahead, 0, IOP_USE_OK, 0), IOP_DESC(77, iop_editing, 0, IOP_USE_OK, 0), IOP_DESC(78, iop_noediting, 0, IOP_USE_OK, 0), IOP_DESC(79, iop_hostsync, 0, IOP_USE_OK, 0), IOP_DESC(80, iop_nohostsync, 0, IOP_USE_OK, 0), IOP_DESC(81, iop_insert, 0, IOP_USE_OK, 0), IOP_DESC(82, iop_noinsert, 0, IOP_USE_OK, 0), IOP_DESC(83, iop_pasthru, 0, IOP_USE_OK, 0), IOP_DESC(84, iop_nopasthru, 0, IOP_USE_OK, 0), IOP_DESC(85, iop_readsync, 0, IOP_USE_OK, 0), IOP_DESC(86, iop_noreadsync, 0, IOP_USE_OK, 0), IOP_DESC(87, iop_ttsync, 0, IOP_USE_OK, 0), IOP_DESC(88, iop_nottsync, 0, IOP_USE_OK, 0), IOP_DESC(89, iop_after, SIZEOF(int4) * 2, IOP_CLOSE_OK, IOP_SRC_TIME), IOP_DESC(90, iop_burst, 0, IOP_CLOSE_OK, 0), IOP_DESC(91, iop_characteristic, SIZEOF(int4), IOP_CLOSE_OK, IOP_SRC_INT), IOP_DESC(92, iop_copies, SIZEOF(int4), IOP_CLOSE_OK, IOP_SRC_INT), IOP_DESC(93, iop_cli, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(94, iop_flag, 0, IOP_CLOSE_OK, 0), IOP_DESC(95, iop_form, SIZEOF(int4), IOP_CLOSE_OK, IOP_SRC_INT), IOP_DESC(96, iop_header, 0, IOP_CLOSE_OK, 0), IOP_DESC(97, iop_hold, 0, IOP_CLOSE_OK, 0), IOP_DESC(98, iop_lowercase, 0, IOP_CLOSE_OK, 0), IOP_DESC(99, iop_name, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(100, iop_cpulimit, SIZEOF(int4), IOP_CLOSE_OK, IOP_SRC_INT), IOP_DESC(101, iop_noburst, 0, IOP_CLOSE_OK, 0), IOP_DESC(102, iop_print, 0, IOP_CLOSE_OK, 0), IOP_DESC(103, iop_noprint, 0, IOP_CLOSE_OK, 0), IOP_DESC(104, iop_noflag, 0, IOP_CLOSE_OK, 0), IOP_DESC(105, iop_noheader, 0, IOP_CLOSE_OK, 0), IOP_DESC(106, iop_nohold, 0, IOP_CLOSE_OK, 0), IOP_DESC(107, iop_nolowercase, 0, IOP_CLOSE_OK, 0), IOP_DESC(108, iop_nonotify, 0, IOP_CLOSE_OK, 0), IOP_DESC(109, iop_nopassall, 0, IOP_CLOSE_OK, 0), IOP_DESC(110, iop_norestart, 0, IOP_CLOSE_OK, 0), IOP_DESC(111, iop_noused_1, 0, 0, 0), IOP_DESC(112, iop_note, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(113, iop_notify, 0, IOP_CLOSE_OK, 0), IOP_DESC(114, iop_notrailer, 0, IOP_CLOSE_OK, 0), IOP_DESC(115, iop_operator, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(116, iop_firstpage, SIZEOF(int4), IOP_CLOSE_OK, IOP_SRC_INT), IOP_DESC(117, iop_passall, 0, IOP_CLOSE_OK, 0), IOP_DESC(118, iop_priority, SIZEOF(int4), IOP_CLOSE_OK, IOP_SRC_INT), IOP_DESC(119, iop_remote, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(120, iop_restart, 0, IOP_CLOSE_OK, 0), IOP_DESC(121, iop_setup, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(122, iop_trailer, 0, IOP_CLOSE_OK, 0), IOP_DESC(123, iop_user, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(124, iop_logfile, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(125, iop_logqueue, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(126, iop_lastpage, SIZEOF(int4), IOP_CLOSE_OK, IOP_SRC_INT), IOP_DESC(127, iop_page, 0, IOP_CLOSE_OK, 0), IOP_DESC(128, iop_nopage, 0, IOP_CLOSE_OK, 0), IOP_DESC(129, iop_doublespace, 0, IOP_CLOSE_OK, 0), IOP_DESC(130, iop_nodoublespace, 0, IOP_CLOSE_OK, 0), IOP_DESC(131, iop_p1, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(132, iop_p2, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(133, iop_p3, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(134, iop_p4, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(135, iop_p5, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(136, iop_p6, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(137, iop_p7, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(138, iop_p8, IOP_VAR_SIZE, IOP_CLOSE_OK, IOP_SRC_STR), IOP_DESC(139, iop_filter, IOP_VAR_SIZE, IOP_USE_OK, IOP_SRC_STR), IOP_DESC(140, iop_nofilter, 0, IOP_USE_OK, 0), IOP_DESC(141, iop_writetm, 0, IOP_USE_OK | IOP_CLOSE_OK, 0), IOP_DESC(142, iop_writelb, IOP_VAR_SIZE, IOP_USE_OK, IOP_SRC_STR), IOP_DESC(143, iop_truncate, 0, IOP_USE_OK | IOP_OPEN_OK, 0), IOP_DESC(144, iop_notruncate, 0, IOP_USE_OK | IOP_OPEN_OK, 0), IOP_DESC(145, iop_extgap, 0, IOP_USE_OK | IOP_OPEN_OK, 0), IOP_DESC(146, iop_noebcdic, 0, IOP_USE_OK | IOP_OPEN_OK, 0), IOP_DESC(147, iop_retry, 0, IOP_USE_OK | IOP_OPEN_OK, 0), IOP_DESC(148, iop_nl, 0, IOP_OPEN_OK, 0), IOP_DESC(149, iop_noterminator, 0, IOP_USE_OK, 0), IOP_DESC(150, iop_sequential, 0, IOP_OPEN_OK, 0), IOP_DESC(151, iop_fifo, 0, IOP_OPEN_OK, 0), IOP_DESC(152, iop_canonical, 0, IOP_OPEN_OK | IOP_USE_OK, 0), IOP_DESC(153, iop_nocanonical, 0, IOP_OPEN_OK | IOP_USE_OK, 0), IOP_DESC(154, iop_socket, IOP_VAR_SIZE, IOP_OPEN_OK | IOP_CLOSE_OK | IOP_USE_OK, IOP_SRC_STR), IOP_DESC(155, iop_listen, 0, IOP_OPEN_OK | IOP_CLOSE_OK, 0), IOP_DESC(156, iop_urgent, 0, IOP_USE_OK, 0), IOP_DESC(157, iop_nourgent, 0, IOP_USE_OK, 0), IOP_DESC(158, iop_delimiter, IOP_VAR_SIZE, IOP_OPEN_OK | IOP_USE_OK, IOP_SRC_STR), IOP_DESC(159, iop_connect, IOP_VAR_SIZE, IOP_OPEN_OK | IOP_USE_OK, IOP_SRC_STR), IOP_DESC(160, iop_ioerror, IOP_VAR_SIZE, IOP_OPEN_OK | IOP_USE_OK, IOP_SRC_STR), IOP_DESC(161, iop_attach, IOP_VAR_SIZE, IOP_OPEN_OK | IOP_USE_OK, IOP_SRC_STR), IOP_DESC(162, iop_detach, IOP_VAR_SIZE, IOP_USE_OK, IOP_SRC_STR), IOP_DESC(163, iop_zlisten, IOP_VAR_SIZE, IOP_OPEN_OK | IOP_CLOSE_OK | IOP_USE_OK, IOP_SRC_STR), IOP_DESC(164, iop_ipchset, IOP_VAR_SIZE, IOP_OPEN_OK, IOP_SRC_STR), IOP_DESC(165, iop_opchset, IOP_VAR_SIZE, IOP_OPEN_OK, IOP_SRC_STR), IOP_DESC(166, iop_nodelimiter, 0, IOP_OPEN_OK | IOP_USE_OK, 0), IOP_DESC(167, iop_zdelay, 0, IOP_OPEN_OK | IOP_USE_OK, 0), IOP_DESC(168, iop_znodelay, 0, IOP_OPEN_OK | IOP_USE_OK, 0), IOP_DESC(169, iop_zbfsize, SIZEOF(int4), IOP_OPEN_OK | IOP_USE_OK, IOP_SRC_INT), IOP_DESC(170, iop_zibfsize, SIZEOF(int4), IOP_OPEN_OK | IOP_USE_OK, IOP_SRC_INT), IOP_DESC(171, iop_zff, IOP_VAR_SIZE, IOP_OPEN_OK | IOP_USE_OK, IOP_SRC_STR), IOP_DESC(172, iop_znoff, 0, IOP_OPEN_OK | IOP_USE_OK, 0), IOP_DESC(173, iop_zlength, SIZEOF(int4), IOP_USE_OK, IOP_SRC_INT), IOP_DESC(174, iop_zwidth, SIZEOF(int4), IOP_USE_OK, IOP_SRC_INT), IOP_DESC(175, iop_zwrap, 0, IOP_OPEN_OK|IOP_USE_OK, 0), IOP_DESC(176, iop_znowrap, 0, IOP_OPEN_OK|IOP_USE_OK, 0), IOP_DESC(177, iop_bigrecord, 0, IOP_OPEN_OK, 0), IOP_DESC(178, iop_nobigrecord, 0, IOP_OPEN_OK, 0), IOP_DESC(179, iop_rfm, IOP_VAR_SIZE, IOP_OPEN_OK, IOP_SRC_STR), IOP_DESC(180, iop_m, 0, IOP_OPEN_OK, 0), IOP_DESC(181, iop_utf8, 0, IOP_OPEN_OK, 0), IOP_DESC(182, iop_utf16, 0, IOP_OPEN_OK, 0), IOP_DESC(183, iop_utf16be, 0, IOP_OPEN_OK, 0), IOP_DESC(184, iop_utf16le, 0, IOP_OPEN_OK, 0), IOP_DESC(185, iop_pad, SIZEOF(int4), IOP_OPEN_OK, IOP_SRC_INT), IOP_DESC(186, iop_chset, IOP_VAR_SIZE, IOP_OPEN_OK, IOP_SRC_STR), IOP_DESC(187, iop_morereadtime, SIZEOF(int4), IOP_OPEN_OK | IOP_USE_OK, IOP_SRC_INT), IOP_DESC(188, iop_shell, IOP_VAR_SIZE, IOP_OPEN_OK, IOP_SRC_STR), IOP_DESC(189, iop_command, IOP_VAR_SIZE, IOP_OPEN_OK, IOP_SRC_STR), IOP_DESC(190, iop_stderr, IOP_VAR_SIZE, IOP_OPEN_OK, IOP_SRC_STR), IOP_DESC(191, iop_independent, 0, IOP_OPEN_OK, 0), IOP_DESC(192, iop_parse, 0, IOP_OPEN_OK, 0), IOP_DESC(193, iop_destroy, 0, IOP_CLOSE_OK, 0), IOP_DESC(194, iop_nodestroy, 0, IOP_CLOSE_OK, 0), IOP_DESC(195, iop_rundown, 0, IOP_CLOSE_OK, 0), IOP_DESC(196, iop_follow, 0, IOP_OPEN_OK|IOP_USE_OK, 0), IOP_DESC(197, iop_nofollow, 0, IOP_OPEN_OK|IOP_USE_OK, 0), IOP_DESC(198, iop_empterm, 0, IOP_OPEN_OK|IOP_USE_OK, 0), IOP_DESC(199, iop_noempterm, 0, IOP_OPEN_OK|IOP_USE_OK, 0), IOP_DESC(200, n_iops, 0, 0, 0) fis-gtm-V6.0-003/sr_port/iop_parms_size.c0000644000032200000250000000127512201176157017230 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io_params.h" /* io_params_size contains a table of argument sizes for each io_param */ /* enumerated in io_params. */ #define IOP_DESC(a,b,c,d,e) c LITDEF unsigned char io_params_size[] = { #include "iop.h" }; fis-gtm-V6.0-003/sr_port/iorm_wtff.c0000644000032200000250000000142112201176157016172 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #define FORM_FEED "\014" GBLREF io_pair io_curr_device; void iorm_wtff(void) { mstr temp; io_desc *iod; iod = io_curr_device.out; iorm_flush(iod); temp.len = SIZEOF(FORM_FEED) - 1; temp.addr = FORM_FEED; iorm_write(&temp); iorm_wteol(1,iod); iod->dollar.x = 0; iod->dollar.y = 0; } fis-gtm-V6.0-003/sr_port/iorm_wtone.c0000644000032200000250000000276312201176157016372 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #ifdef UNICODE_SUPPORTED #include "gtm_utf8.h" #endif GBLREF io_pair io_curr_device; GBLREF boolean_t gtm_utf8_mode; void iorm_wtone(int ch) { mstr temp; char c; #ifdef UNICODE_SUPPORTED unsigned char uni_buf[GTM_MB_LEN_MAX], *endptr; #endif if (!gtm_utf8_mode || !IS_UTF_CHSET(io_curr_device.out->ochset)) { c = (char)ch; temp.len = 1; temp.addr = &c; } #ifdef UNICODE_SUPPORTED else { switch (io_curr_device.out->ochset) { case CHSET_UTF8: endptr = UTF8_WCTOMB(ch, uni_buf); break; case CHSET_UTF16: /* iorm_write will write BE BOM if first write */ /* continue as if UTF16BE */ case CHSET_UTF16BE: endptr = UTF16BE_WCTOMB(ch, uni_buf); break; case CHSET_UTF16LE: endptr = UTF16LE_WCTOMB(ch, uni_buf); break; default: GTMASSERT; } temp.addr = (char *)uni_buf; temp.len = INTCAST(endptr - uni_buf); assert(0 < temp.len); /* we validated the code point already in op_wtone() */ } #endif UNICODE_ONLY(temp.char_len = 1;) iorm_write(&temp); return; } fis-gtm-V6.0-003/sr_port/iormdefsp.h0000644000032200000250000000141112201176157016172 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef IORMDEFSP_H #define IORMDEFSP_H #define EBCDIC_RMEOL "\25" /* #pragma(suspend) not working in macros */ #define ASCII_RMEOL "\n" #if defined(KEEP_zOS_EBCDIC) || defined(VMS) #define RMEOL ((ascii != iod->out_code_set) ? EBCDIC_RMEOL : ASCII_RMEOL ) #else #define RMEOL ASCII_RMEOL #endif #endif /* IORMDEFSP_H */ fis-gtm-V6.0-003/sr_port/iosocket_bind.c0000644000032200000250000001403612201176157017020 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_bind.c */ #include "mdef.h" #include #include "gtm_time.h" #include "gtm_socket.h" #include "gtm_inet.h" #include "gtm_netdb.h" #include "gtm_ipv6.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "gt_timer.h" #include "io.h" #include "iotimer.h" #include "iotcpdef.h" #include "iosocketdef.h" #include "iotcproutine.h" #include "gtm_stdlib.h" #define BOUND "BOUND" #define IPV6_UNCERTAIN 2 GBLREF tcp_library_struct tcp_routines; error_def(ERR_GETNAMEINFO); error_def(ERR_GETSOCKNAMERR); error_def(ERR_GETSOCKOPTERR); error_def(ERR_SETSOCKOPTERR); error_def(ERR_SOCKBIND); error_def(ERR_SOCKINIT); error_def(ERR_TEXT); boolean_t iosocket_bind(socket_struct *socketptr, int4 timepar, boolean_t update_bufsiz) { int temp_1 = 1; char *errptr; int4 errlen, msec_timeout, real_errno; short len; in_port_t actual_port; boolean_t no_time_left = FALSE; d_socket_struct *dsocketptr; struct addrinfo *ai_ptr; char port_buffer[NI_MAXSERV]; int errcode; ABS_TIME cur_time, end_time; GTM_SOCKLEN_TYPE addrlen; GTM_SOCKLEN_TYPE sockbuflen; dsocketptr = socketptr->dev; ai_ptr = (struct addrinfo*)(&socketptr->local.ai); assert(NULL != dsocketptr); dsocketptr->iod->dollar.key[0] = '\0'; if (FD_INVALID != socketptr->temp_sd) { socketptr->sd = socketptr->temp_sd; socketptr->temp_sd = FD_INVALID; } if (timepar != NO_M_TIMEOUT) { msec_timeout = timeout2msec(timepar); sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, msec_timeout, &end_time); } do { temp_1 = 1; if (-1 == tcp_routines.aa_setsockopt(socketptr->sd, SOL_SOCKET, SO_REUSEADDR, &temp_1, SIZEOF(temp_1))) { real_errno = errno; errptr = (char *)STRERROR(real_errno); errlen = STRLEN(errptr); SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, RTS_ERROR_LITERAL("SO_REUSEADDR"), real_errno, errlen, errptr); return FALSE; } #ifdef TCP_NODELAY temp_1 = socketptr->nodelay ? 1 : 0; if (-1 == tcp_routines.aa_setsockopt(socketptr->sd, IPPROTO_TCP, TCP_NODELAY, &temp_1, SIZEOF(temp_1))) { real_errno = errno; errptr = (char *)STRERROR(real_errno); errlen = STRLEN(errptr); SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, RTS_ERROR_LITERAL("TCP_NODELAY"), real_errno, errlen, errptr); return FALSE; } #endif if (update_bufsiz) { if (-1 == tcp_routines.aa_setsockopt(socketptr->sd, SOL_SOCKET, SO_RCVBUF, &socketptr->bufsiz, SIZEOF(socketptr->bufsiz))) { real_errno = errno; errptr = (char *)STRERROR(real_errno); errlen = STRLEN(errptr); SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, RTS_ERROR_LITERAL("SO_RCVBUF"), real_errno, errlen, errptr); return FALSE; } } else { sockbuflen = SIZEOF(socketptr->bufsiz); if (-1 == tcp_routines.aa_getsockopt(socketptr->sd, SOL_SOCKET, SO_RCVBUF, &socketptr->bufsiz, &sockbuflen)) { real_errno = errno; errptr = (char *)STRERROR(real_errno); errlen = STRLEN(errptr); SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, RTS_ERROR_LITERAL("SO_RCVBUF"), real_errno, errlen, errptr); return FALSE; } } temp_1 = tcp_routines.aa_bind(socketptr->sd, SOCKET_LOCAL_ADDR(socketptr), ai_ptr->ai_addrlen); if (temp_1 < 0) { real_errno = errno; no_time_left = TRUE; switch (real_errno) { case EADDRINUSE: if (NO_M_TIMEOUT != timepar) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (cur_time.at_sec > 0) no_time_left = FALSE; } break; case EINTR: break; default: SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKBIND, 0, real_errno, 0); break; } if (no_time_left) return FALSE; hiber_start(100); tcp_routines.aa_close(socketptr->sd); if (-1 == (socketptr->sd = tcp_routines.aa_socket(ai_ptr->ai_family,ai_ptr->ai_socktype, ai_ptr->ai_protocol))) { real_errno = errno; errptr = (char *)STRERROR(real_errno); errlen = STRLEN(errptr); SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, real_errno, errlen, errptr); return FALSE; } } } while (temp_1 < 0); /* obtain actual port from the bound address if port 0 was specified */ addrlen = SOCKET_ADDRLEN(socketptr, ai_ptr, local); if (-1 == tcp_routines.aa_getsockname(socketptr->sd, SOCKET_LOCAL_ADDR(socketptr), &addrlen)) { real_errno = errno; errptr = (char *)STRERROR(real_errno); errlen = STRLEN(errptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, real_errno, errlen, errptr); return FALSE; } assert(ai_ptr->ai_addrlen == addrlen); GETNAMEINFO(SOCKET_LOCAL_ADDR(socketptr), addrlen, NULL, 0, port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode); if (0 != errcode) { SOCKET_FREE(socketptr); RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); return FALSE; } actual_port = ATOI(port_buffer); if (0 == socketptr->local.port) socketptr->local.port = actual_port; assert(socketptr->local.port == actual_port); socketptr->state = socket_bound; len = SIZEOF(BOUND) - 1; memcpy(&dsocketptr->iod->dollar.key[0], BOUND, len); dsocketptr->iod->dollar.key[len++] = '|'; memcpy(&dsocketptr->iod->dollar.key[len], socketptr->handle, socketptr->handle_len); len += socketptr->handle_len; dsocketptr->iod->dollar.key[len++] = '|'; SPRINTF(&dsocketptr->iod->dollar.key[len], "%d", socketptr->local.port); return TRUE; } fis-gtm-V6.0-003/sr_port/iosocket_close.c0000644000032200000250000000732712201176157017216 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_close.c - close a socket connection * Parameters- * iod -- I/O descriptor for the current device. * * pp -- mval that carries the device parameters * */ #include "mdef.h" #include "gtm_string.h" #include "gtm_iconv.h" #include "gtm_stdio.h" #include "gtm_socket.h" #include "gtm_inet.h" #include "copy.h" #include "io_params.h" #include "io.h" #include "iotcpdef.h" #include "iotcproutine.h" #include "gt_timer.h" #include "iosocketdef.h" #include "stringpool.h" GBLREF tcp_library_struct tcp_routines; GBLREF io_desc *active_device; LITREF unsigned char io_params_size[]; error_def(ERR_SOCKNOTFND); void iosocket_close(io_desc *iod, mval *pp) { boolean_t socket_specified = FALSE; unsigned char ch; int handle_len; d_socket_struct *dsocketptr; socket_struct *socketptr; char sock_handle[MAX_HANDLE_LEN]; int4 ii, jj, start, end, index; int p_offset = 0; boolean_t socket_destroy = FALSE; assert(iod->type == gtmsocket); dsocketptr = (d_socket_struct *)iod->dev_sp; while (iop_eol != (ch = *(pp->str.addr + p_offset++))) { switch (ch) { case iop_exception: iod->error_handler.len = *(pp->str.addr + p_offset); iod->error_handler.addr = (char *)(pp->str.addr + p_offset + 1); s2pool(&iod->error_handler); break; case iop_socket: handle_len = (short)(*(pp->str.addr + p_offset)); assert(handle_len > 0); memcpy(sock_handle, (char *)(pp->str.addr + p_offset + 1), handle_len); socket_specified = TRUE; break; case iop_ipchset: #if defined(KEEP_zOS_EBCDIC) || defined(VMS) if ( (iconv_t)0 != iod->input_conv_cd ) { ICONV_CLOSE_CD(iod->input_conv_cd); } SET_CODE_SET(iod->in_code_set, (char *)(pp->str.addr + p_offset + 1)); if (DEFAULT_CODE_SET != iod->in_code_set) ICONV_OPEN_CD(iod->input_conv_cd, INSIDE_CH_SET, (char *)(pp->str.addr + p_offset + 1)); #endif break; case iop_opchset: #if defined(KEEP_zOS_EBCDIC) || defined(VMS) if ( (iconv_t)0 != iod->output_conv_cd ) { ICONV_CLOSE_CD(iod->output_conv_cd); } SET_CODE_SET(iod->out_code_set, (char *)(pp->str.addr + p_offset + 1)); if (DEFAULT_CODE_SET != iod->out_code_set) ICONV_OPEN_CD(iod->output_conv_cd, (char *)(pp->str.addr + p_offset + 1), INSIDE_CH_SET); #endif break; case iop_destroy: socket_destroy = TRUE; break; case iop_nodestroy: socket_destroy = FALSE; break; default: break; } p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ? (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]); } if (socket_specified) { if (0 > (index = iosocket_handle(sock_handle, &handle_len, FALSE, dsocketptr))) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKNOTFND, 2, handle_len, sock_handle); return; } start = end = index; } else { start = dsocketptr->n_socket - 1; end = 0; } for (ii = start; ii >= end; ii--) { socketptr = dsocketptr->socket[ii]; tcp_routines.aa_close(socketptr->sd); SOCKET_FREE(socketptr); if (dsocketptr->current_socket >= ii) dsocketptr->current_socket--; for (jj = ii + 1; jj <= dsocketptr->n_socket - 1; jj++) dsocketptr->socket[jj - 1] = dsocketptr->socket[jj]; dsocketptr->n_socket--; } if (!socket_specified) { iod->state = dev_closed; if (socket_destroy) { active_device = 0; iosocket_destroy(iod); } } } fis-gtm-V6.0-003/sr_port/iosocket_connect.c0000644000032200000250000004215112201176177017536 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_connect.c */ #include "mdef.h" #include #include "gtm_time.h" #include "gtm_socket.h" #include "gtm_inet.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "stringpool.h" #include "gt_timer.h" #include "io.h" #include "iotimer.h" #include "iotcpdef.h" #include "iosocketdef.h" #include "iotcproutine.h" #include #include "stack_frame.h" #include "mv_stent.h" #include "outofband.h" #include "gtm_netdb.h" #include "gtm_ipv6.h" #define ESTABLISHED "ESTABLISHED" GBLREF tcp_library_struct tcp_routines; GBLREF volatile int4 outofband; GBLREF boolean_t dollar_zininterrupt; GBLREF stack_frame *frame_pointer; GBLREF unsigned char *stackbase, *stacktop, *msp, *stackwarn; GBLREF mv_stent *mv_chain; GBLREF int socketus_interruptus; GBLREF d_socket_struct *newdsocket; /* in case jobinterrupt */ GBLREF int4 gtm_max_sockets; error_def(ERR_GETNAMEINFO); error_def(ERR_GETSOCKOPTERR); error_def(ERR_OPENCONN); error_def(ERR_SETSOCKOPTERR); error_def(ERR_SOCKINIT); error_def(ERR_STACKCRIT); error_def(ERR_STACKOFLOW); error_def(ERR_TEXT); error_def(ERR_ZINTRECURSEIO); boolean_t iosocket_connect(socket_struct *sockptr, int4 timepar, boolean_t update_bufsiz) { int temp_1; char *errptr; int4 errlen, msec_timeout, save_errno, last_errno; int d_socket_struct_len, res, nfds, sockerror; fd_set writefds; boolean_t no_time_left = FALSE; boolean_t need_connect, need_socket, need_select; short len; io_desc *iod; d_socket_struct *dsocketptr, *real_dsocketptr; socket_interrupt *sockintr, *real_sockintr; ABS_TIME cur_time, end_time; struct timeval *sel_time; mv_stent *mv_zintdev; struct addrinfo *remote_ai_ptr, *raw_ai_ptr; int errcode, real_errno; char ipaddr[SA_MAXLEN + 1]; GTM_SOCKLEN_TYPE sockbuflen; DBGSOCK((stdout, "socconn: ************* Entering socconn - timepar: %d\n",timepar)); /* check for validity */ dsocketptr = sockptr->dev; assert(NULL != dsocketptr); sockintr = &dsocketptr->sock_save_state; iod = dsocketptr->iod; real_dsocketptr = (d_socket_struct *)iod->dev_sp; /* not newdsocket which is not saved on error */ real_sockintr = &real_dsocketptr->sock_save_state; iod->dollar.key[0] = '\0'; need_socket = need_connect = TRUE; need_select = FALSE; /* Check for restart */ if (dsocketptr->mupintr) { /* We have a pending read restart of some sort - check we aren't recursing on this device */ if (sockwhich_invalid == sockintr->who_saved) GTMASSERT; /* Interrupt should never have an invalid save state */ if (dollar_zininterrupt) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); if (sockwhich_connect != sockintr->who_saved) GTMASSERT; /* ZINTRECURSEIO should have caught */ DBGSOCK((stdout, "socconn: *#*#*#*#*#*#*# Restarted interrupted connect\n")); mv_zintdev = io_find_mvstent(iod, FALSE); if (mv_zintdev) { if (sockintr->end_time_valid) /* Restore end_time for timeout */ end_time = sockintr->end_time; if ((socket_connect_inprogress == sockptr->state) && (FD_INVALID != sockptr->sd)) { need_select = TRUE; need_socket = need_connect = FALSE; /* sd still good */ } /* Done with this mv_stent. Pop it off if we can, else mark it inactive. */ if (mv_chain == mv_zintdev) POP_MV_STENT(); /* pop if top of stack */ else { /* else mark it unused, see iosocket_open for use */ mv_zintdev->mv_st_cont.mvs_zintdev.buffer_valid = FALSE; mv_zintdev->mv_st_cont.mvs_zintdev.io_ptr = NULL; } DBGSOCK((stdout, "socconn: mv_stent found - endtime: %d/%d\n", end_time.at_sec, end_time.at_usec)); } else DBGSOCK((stdout, "socconn: no mv_stent found !!\n")); real_dsocketptr->mupintr = dsocketptr->mupintr = FALSE; real_sockintr->who_saved = sockintr->who_saved = sockwhich_invalid; } else if (timepar != NO_M_TIMEOUT) { msec_timeout = timeout2msec(timepar); sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, msec_timeout, &end_time); } real_sockintr->end_time_valid = sockintr->end_time_valid = FALSE; last_errno = 0; remote_ai_ptr = (struct addrinfo*)(&(sockptr->remote.ai)); do { /* If the connect was failed, we may have already changed the remote. * So, the remote ai_addr should be restored. */ assertpro(NULL != sockptr->remote.ai_head); memcpy(remote_ai_ptr, sockptr->remote.ai_head, SIZEOF(struct addrinfo)); if (need_socket && (FD_INVALID != sockptr->sd)) { tcp_routines.aa_close(sockptr->sd); sockptr->sd = FD_INVALID; } assert(FD_INVALID == -1); if (need_socket) { real_errno = -2; for (raw_ai_ptr = remote_ai_ptr; NULL != raw_ai_ptr; raw_ai_ptr = raw_ai_ptr->ai_next) { if (-1 == (sockptr->sd = tcp_routines.aa_socket(raw_ai_ptr->ai_family, raw_ai_ptr->ai_socktype, raw_ai_ptr->ai_protocol))) real_errno = errno; else { real_errno = 0; break; } } if (0 != real_errno) { if (NULL != sockptr->remote.ai_head) { freeaddrinfo(sockptr->remote.ai_head); sockptr->remote.ai_head = NULL; } assertpro(-2 != real_errno); errptr = (char *)STRERROR(real_errno); errlen = STRLEN(errptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return FALSE; } assertpro(NULL != raw_ai_ptr);/* either there is an IPv6 or an IPv4 address */ memcpy(remote_ai_ptr, raw_ai_ptr, SIZEOF(struct addrinfo)); SOCKET_AI_TO_REMOTE_ADDR(sockptr, raw_ai_ptr); remote_ai_ptr->ai_addr = SOCKET_REMOTE_ADDR(sockptr); remote_ai_ptr->ai_addrlen = raw_ai_ptr->ai_addrlen; remote_ai_ptr->ai_next = NULL; need_socket = FALSE; temp_1 = 1; if (-1 == tcp_routines.aa_setsockopt(sockptr->sd, SOL_SOCKET, SO_REUSEADDR, &temp_1, SIZEOF(temp_1))) { save_errno = errno; errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */ sockptr->sd = FD_INVALID; if (NULL != sockptr->remote.ai_head) { freeaddrinfo(sockptr->remote.ai_head); sockptr->remote.ai_head = NULL; } rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, RTS_ERROR_LITERAL("SO_REUSEADDR"), save_errno, errlen, errptr); return FALSE; } #ifdef TCP_NODELAY temp_1 = sockptr->nodelay ? 1 : 0; if (-1 == tcp_routines.aa_setsockopt(sockptr->sd, IPPROTO_TCP, TCP_NODELAY, &temp_1, SIZEOF(temp_1))) { save_errno = errno; errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */ sockptr->sd = FD_INVALID; if (NULL != sockptr->remote.ai_head) { freeaddrinfo(sockptr->remote.ai_head); sockptr->remote.ai_head = NULL; } rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, RTS_ERROR_LITERAL("TCP_NODELAY"), save_errno, errlen, errptr); return FALSE; } #endif if (update_bufsiz) { if (-1 == tcp_routines.aa_setsockopt(sockptr->sd, SOL_SOCKET, SO_RCVBUF, &sockptr->bufsiz, SIZEOF(sockptr->bufsiz))) { save_errno = errno; errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */ sockptr->sd = FD_INVALID; if (NULL != sockptr->remote.ai_head) { freeaddrinfo(sockptr->remote.ai_head); sockptr->remote.ai_head = NULL; } rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, RTS_ERROR_LITERAL("SO_RCVBUF"), save_errno, errlen, errptr); return FALSE; } } else { sockbuflen = SIZEOF(sockptr->bufsiz); if (-1 == tcp_routines.aa_getsockopt(sockptr->sd, SOL_SOCKET, SO_RCVBUF, &sockptr->bufsiz, &sockbuflen)) { save_errno = errno; errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */ sockptr->sd = FD_INVALID; if (NULL != sockptr->remote.ai_head) { freeaddrinfo(sockptr->remote.ai_head); sockptr->remote.ai_head = NULL; } rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, RTS_ERROR_LITERAL("SO_RCVBUF"), save_errno, errlen, errptr); return FALSE; } } } save_errno = res = 0; if (need_connect) { /* Use plain connect to allow jobinterrupt */ assert(FD_INVALID != sockptr->sd); res = connect(sockptr->sd, SOCKET_REMOTE_ADDR(sockptr), remote_ai_ptr->ai_addrlen); if (res < 0) { save_errno = errno; no_time_left = FALSE; need_connect = TRUE; switch (save_errno) { case EISCONN: save_errno = 0; res = 0; /* since it is connected already, treat as if success */ need_connect = FALSE; break; case EINTR: if (outofband && 0 != timepar) { /* handle outofband unless zero timeout */ save_errno = 0; need_socket = need_connect = FALSE; break; } /* else fall through */ case EINPROGRESS: case EALREADY: # if (defined(__osf__) && defined(__alpha)) || defined(__sun) || defined(__vms) case EWOULDBLOCK: # endif need_socket = need_connect = FALSE; if (0 != timepar) need_select = TRUE; /* fall through */ case ETIMEDOUT: /* the other side bound but not listening */ case ECONNREFUSED: if (!no_time_left && 0 != timepar && NO_M_TIMEOUT != timepar) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (cur_time.at_sec <= 0) no_time_left = TRUE; } if (0 == timepar) no_time_left = TRUE; else if (!no_time_left) { if (ETIMEDOUT == save_errno || ECONNREFUSED == save_errno) need_connect = need_socket = TRUE; save_errno = 0; res = -1; /* do the outer loop again */ } if (no_time_left) save_errno = 0; break; default: break; } } /* if connect failed */ } if (need_select) { sockerror = 0; do { /* unless outofband loop on select if connection continuing */ if (NO_M_TIMEOUT == timepar) sel_time = NULL; else { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (cur_time.at_sec > 0) sel_time = (struct timeval *)&cur_time; else { /* timed out so done */ save_errno = res = 0; no_time_left = TRUE; break; } } FD_ZERO(&writefds); FD_SET(sockptr->sd, &writefds); res = select(sockptr->sd + 1, NULL, &writefds, NULL, sel_time); if (0 < res) { /* check for socket error */ sockbuflen = SIZEOF(sockerror); res = getsockopt(sockptr->sd, SOL_SOCKET, SO_ERROR, &sockerror, &sockbuflen); if (0 == res && 0 == sockerror) { /* got it */ save_errno = 0; break; } else if (0 == res && 0 != sockerror) { if (EINTR == sockerror) { /* loop on select */ save_errno = 0; continue; } else { /* return socket error */ if (ECONNREFUSED == sockerror || ETIMEDOUT == sockerror) { /* try until timeout */ last_errno = sockerror; save_errno = 0; need_socket = need_connect = TRUE; need_select = FALSE; res = -1; } else save_errno = sockerror; break; } } else { save_errno = errno; /* error on getsockopt */ break; } } else if (0 == res) { /* select timed out */ save_errno = 0; no_time_left = TRUE; break; } else if (EINTR != errno) { save_errno = errno; break; } else if (outofband) { save_errno = 0; break; } } while (TRUE); /* do select */ } if (save_errno) { if (FD_INVALID != sockptr->sd) { tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */ sockptr->sd = FD_INVALID; } if (NULL != sockptr->remote.ai_head) { freeaddrinfo(sockptr->remote.ai_head); sockptr->remote.ai_head = NULL; } errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); if (dev_open == iod->state) { iod->dollar.za = 9; memcpy(iod->dollar.device, ONE_COMMA, SIZEOF(ONE_COMMA)); memcpy(&iod->dollar.device[SIZEOF(ONE_COMMA) - 1], errptr, errlen + 1); /* + 1 for null */ } if (sockptr->ioerror) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_OPENCONN, 0, ERR_TEXT, 2, errlen, errptr); errno = save_errno; return FALSE; } if (no_time_left) { if (NULL != sockptr->remote.ai_head) { freeaddrinfo(sockptr->remote.ai_head); sockptr->remote.ai_head = NULL; } return FALSE; /* caller will close socket */ } if (res < 0 && outofband) /* if connected delay outofband */ { DBGSOCK((stdout, "socconn: outofband interrupt received (%d) -- " "queueing mv_stent for wait intr\n", outofband)); if (need_connect) { /* no connect in progress */ tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */ sockptr->sd = FD_INVALID; sockptr->state = socket_created; } else sockptr->state = socket_connect_inprogress; if (NULL != sockptr->remote.ai_head) { freeaddrinfo(sockptr->remote.ai_head); sockptr->remote.ai_head = NULL; } real_sockintr->who_saved = sockintr->who_saved = sockwhich_connect; if (NO_M_TIMEOUT != timepar) { real_sockintr->end_time = sockintr->end_time = end_time; real_sockintr->end_time_valid = sockintr->end_time_valid = TRUE; } else real_sockintr->end_time_valid = sockintr->end_time_valid = FALSE; real_sockintr->newdsocket = sockintr->newdsocket = newdsocket; real_dsocketptr->mupintr = dsocketptr->mupintr = TRUE; d_socket_struct_len = SIZEOF(d_socket_struct) + (SIZEOF(socket_struct) * (gtm_max_sockets - 1)); ENSURE_STP_FREE_SPACE(d_socket_struct_len); PUSH_MV_STENT(MVST_ZINTDEV); mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = FALSE; mv_chain->mv_st_cont.mvs_zintdev.io_ptr = NULL; mv_chain->mv_st_cont.mvs_zintdev.socketptr = sockptr; /* for sd and to free structure */ mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.len = d_socket_struct_len; mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr = (char *)stringpool.free; memcpy (stringpool.free, (unsigned char *)newdsocket, d_socket_struct_len); stringpool.free += d_socket_struct_len; mv_chain->mv_st_cont.mvs_zintdev.io_ptr = iod; mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = TRUE; socketus_interruptus++; DBGSOCK((stdout, "socconn: mv_stent queued - endtime: %d/%d interrupts: %d\n", end_time.at_sec, end_time.at_usec, socketus_interruptus)); outofband_action(FALSE); GTMASSERT; /* Should *never* return from outofband_action */ return FALSE; /* For the compiler.. */ } hiber_start(100); } while (res < 0); sockptr->state = socket_connected; sockptr->first_read = sockptr->first_write = TRUE; /* update dollar_key */ len = SIZEOF(ESTABLISHED) - 1; memcpy(&iod->dollar.key[0], ESTABLISHED, len); iod->dollar.key[len++] = '|'; memcpy(&iod->dollar.key[len], sockptr->handle, sockptr->handle_len); len += sockptr->handle_len; iod->dollar.key[len++] = '|'; /* translate internal address to numeric ip address */ assert(FALSE == need_socket); if (NULL != sockptr->remote.ai_head) { freeaddrinfo(sockptr->remote.ai_head); sockptr->remote.ai_head = NULL; } GETNAMEINFO(SOCKET_REMOTE_ADDR(sockptr), remote_ai_ptr->ai_addrlen, ipaddr, SA_MAXLEN, NULL, 0, NI_NUMERICHOST, errcode); if (0 != errcode) { if (FD_INVALID != sockptr->sd) { tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */ sockptr->sd = FD_INVALID; } RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); return FALSE; } STRNDUP(ipaddr, SA_MAXLEN, sockptr->remote.saddr_ip); strncpy(&iod->dollar.key[len], sockptr->remote.saddr_ip, DD_BUFLEN - 1 - len); iod->dollar.key[DD_BUFLEN-1] = '\0'; /* In case we fill the buffer */ return TRUE; } fis-gtm-V6.0-003/sr_port/iosocket_create.c0000644000032200000250000001710512201176157017347 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_create.c */ /* this module takes care of * 1. allocate the space * 2. for passive: local.sa & local.ai * for active : remote.sa & remote.ai * for $principal: via getsockname and getsockpeer * 3. socketptr->protocol * 4. socketptr->sd (initialized to -1) unless already open via inetd * 5. socketptr->passive * 6. socketptr->state (initialized to created) unless already open */ #include "mdef.h" #include #include "gtm_ctype.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "gtm_netdb.h" #include "gtm_socket.h" #include "gtm_inet.h" #include "gtm_ipv6.h" #include "gtm_stdlib.h" #include "io.h" #include "iotcproutine.h" #include "iotcpdef.h" #include "gt_timer.h" #include "iosocketdef.h" #include "min_max.h" #include "gtm_caseconv.h" #include "util.h" GBLREF tcp_library_struct tcp_routines; error_def(ERR_GETSOCKNAMERR); error_def(ERR_GETADDRINFO); error_def(ERR_GETNAMEINFO); error_def(ERR_INVPORTSPEC); error_def(ERR_INVADDRSPEC); error_def(ERR_PROTNOTSUP); error_def(ERR_TEXT); error_def(ERR_SOCKINIT); /* PORT_PROTO_FORMAT defines the format for : */ #define PORT_PROTO_FORMAT "%hu:%3[^:]" #define SEPARATOR ':' socket_struct *iosocket_create(char *sockaddr, uint4 bfsize, int file_des) { socket_struct *socketptr; socket_struct *prev_socketptr; socket_struct *socklist_head; bool passive = FALSE; unsigned short port; int ii, save_errno, tmplen, errlen; char temp_addr[SA_MAXLITLEN], tcp[4], *adptr; const char *errptr; struct addrinfo *ai_ptr; struct addrinfo hints, *addr_info_ptr = NULL; int af; int sd; int errcode; char port_buffer[NI_MAXSERV]; int port_buffer_len; int colon_cnt; char *last_2colon; int addrlen; GTM_SOCKLEN_TYPE tmp_addrlen; if (0 > file_des) { /* no socket descriptor yet */ memset(&hints, 0, SIZEOF(hints)); colon_cnt = 0; for (ii = strlen(sockaddr) - 1; 0 <= ii; ii--) { if (SEPARATOR == sockaddr[ii]) { colon_cnt++; if (2 == colon_cnt) { last_2colon = &sockaddr[ii]; break; } } } if (0 == colon_cnt) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC); return NULL; } if (1 == colon_cnt) { /* for listening socket or broadcasting socket */ if (SSCANF(sockaddr, PORT_PROTO_FORMAT, &port, tcp) < 2) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC); return NULL; } passive = TRUE; /* We always first try using IPv6 address, if supported */ af = ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET); if (-1 == (sd = tcp_routines.aa_socket(af, SOCK_STREAM, IPPROTO_TCP))) { /* Try creating IPv4 socket */ af = AF_INET; if (-1 == (sd = tcp_routines.aa_socket(af, SOCK_STREAM, IPPROTO_TCP))) { save_errno = errno; errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, save_errno, errlen, errptr); return NULL; } } SERVER_HINTS(hints, af); port_buffer_len = 0; I2A(port_buffer, port_buffer_len, port); port_buffer[port_buffer_len]='\0'; if (0 != (errcode = getaddrinfo(NULL, port_buffer, &hints, &addr_info_ptr))) { tcp_routines.aa_close(sd); RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode); return NULL; } SOCKET_ALLOC(socketptr); socketptr->local.port = port; socketptr->temp_sd = sd; socketptr->sd = FD_INVALID; ai_ptr = &(socketptr->local.ai); memcpy(ai_ptr, addr_info_ptr, SIZEOF(struct addrinfo)); SOCKET_AI_TO_LOCAL_ADDR(socketptr, addr_info_ptr); ai_ptr->ai_addr = SOCKET_LOCAL_ADDR(socketptr); ai_ptr->ai_addrlen = addr_info_ptr->ai_addrlen; ai_ptr->ai_next = NULL; freeaddrinfo(addr_info_ptr); } else { /* connection socket */ assert(2 == colon_cnt); if (SSCANF(last_2colon + 1, PORT_PROTO_FORMAT, &port, tcp) < 2) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC); return NULL; } /* for connection socket */ SPRINTF(port_buffer, "%hu", port); addrlen = last_2colon - sockaddr; if ('[' == sockaddr[0]) { if (NULL == memchr(sockaddr, ']', addrlen)) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC); return NULL; } addrlen -= 2; memcpy(temp_addr, &sockaddr[1], addrlen); } else memcpy(temp_addr, sockaddr, addrlen); temp_addr[addrlen] = 0; CLIENT_HINTS(hints); if (0 != (errcode = getaddrinfo(temp_addr, port_buffer, &hints, &addr_info_ptr))) { RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode); return NULL; } /* we will test all address families in iosocket_connect() */ SOCKET_ALLOC(socketptr); socketptr->remote.ai_head = addr_info_ptr; socketptr->remote.port = port; socketptr->sd = socketptr->temp_sd = FD_INVALID; /* don't mess with 0 */ } lower_to_upper((uchar_ptr_t)tcp, (uchar_ptr_t)tcp, SIZEOF("TCP") - 1); if (0 == MEMCMP_LIT(tcp, "TCP")) { socketptr->protocol = socket_tcpip; } else { SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PROTNOTSUP, 2, MIN(strlen(tcp), SIZEOF("TCP") - 1), tcp); return NULL; } socketptr->state = socket_created; SOCKET_BUFFER_INIT(socketptr, bfsize); socketptr->passive = passive; socketptr->moreread_timeout = DEFAULT_MOREREAD_TIMEOUT; return socketptr; } else { /* socket already setup by inetd */ SOCKET_ALLOC(socketptr); socketptr->sd = file_des; socketptr->temp_sd = FD_INVALID; ai_ptr = &(socketptr->local.ai); tmp_addrlen = SIZEOF(struct sockaddr_storage); if (-1 == tcp_routines.aa_getsockname(socketptr->sd, SOCKET_LOCAL_ADDR(socketptr), &tmp_addrlen)) { save_errno = errno; errptr = (char *)STRERROR(save_errno); tmplen = STRLEN(errptr); SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, save_errno, tmplen, errptr); return NULL; } ai_ptr->ai_addrlen = tmp_addrlen; /* extract port information */ GETNAMEINFO(SOCKET_LOCAL_ADDR(socketptr), tmp_addrlen, NULL, 0, port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode); if (0 != errcode) { SOCKET_FREE(socketptr); RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); return NULL; } socketptr->local.port = ATOI(port_buffer); tmp_addrlen = SIZEOF(struct sockaddr_storage); if (-1 == getpeername(socketptr->sd, SOCKET_REMOTE_ADDR(socketptr), &tmp_addrlen)) { save_errno = errno; errptr = (char *)STRERROR(save_errno); tmplen = STRLEN(errptr); SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, save_errno, tmplen, errptr); return NULL; } socketptr->remote.ai.ai_addrlen = tmp_addrlen; assert(0 != SOCKET_REMOTE_ADDR(socketptr)->sa_family); GETNAMEINFO(SOCKET_REMOTE_ADDR(socketptr), socketptr->remote.ai.ai_addrlen, NULL, 0, port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode); if (0 != errcode) { SOCKET_FREE(socketptr); RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); return NULL; } socketptr->remote.port = ATOI(port_buffer); socketptr->state = socket_connected; socketptr->protocol = socket_tcpip; SOCKET_BUFFER_INIT(socketptr, bfsize); socketptr->passive = passive; socketptr->moreread_timeout = DEFAULT_MOREREAD_TIMEOUT; return socketptr; } } fis-gtm-V6.0-003/sr_port/iosocket_delimiter.c0000644000032200000250000001411412201176157020057 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_delimiter.c */ #include "mdef.h" #include "gtm_socket.h" #include "gtm_string.h" #include "gtm_inet.h" #include "io.h" #include "iottdef.h" #include "iotcpdef.h" #include "gt_timer.h" #include "iosocketdef.h" #include "gtm_conv.h" #include "gtm_utf8.h" GBLREF boolean_t gtm_utf8_mode; GBLREF UConverter *chset_desc[]; error_def(ERR_DELIMSIZNA); boolean_t iosocket_delimiter(unsigned char *delimiter_buffer, int4 delimiter_len, socket_struct *socketptr, boolean_t rm) { int counter, ii, c_len; unsigned char *c, *top, delimiter[MAX_DELIM_LEN + 1]; /* free the previous delimiters if any */ for (ii = 0; ii < socketptr->n_delimiter; ii++) { free(socketptr->delimiter[ii].addr); if (socketptr->idelimiter[ii].addr != socketptr->delimiter[ii].addr) free(socketptr->idelimiter[ii].addr); } if (0 < socketptr->n_delimiter && socketptr->odelimiter0.addr != socketptr->delimiter[0].addr) free(socketptr->odelimiter0.addr); socketptr->n_delimiter = 0; socketptr->delim0containsLF = FALSE; if (rm) return TRUE; /* fill in the new delimiters */ counter = ii = 0; c = &delimiter_buffer[0]; top = c + delimiter_len; while ((c < top) && (ii < MAX_N_DELIMITER)) { switch(delimiter[counter++] = *c++) { case ':' : /* end of the previous delimiter and start the next one */ if (1 < counter) { if (gtm_utf8_mode) { /* Check if delimiter has any invalid UTF-8 characters */ c_len = utf8_len_strict(delimiter, counter - 1); } else c_len = counter - 1; socketptr->delimiter[ii].addr = (char *)malloc(counter - 1); memcpy(socketptr->delimiter[ii].addr, delimiter, counter - 1); socketptr->delimiter[ii].len = counter - 1; UNICODE_ONLY(socketptr->delimiter[ii].char_len = c_len); socketptr->idelimiter[ii] = socketptr->delimiter[ii]; if (0 == ii) socketptr->odelimiter0 = socketptr->delimiter[0]; socketptr->n_delimiter++; ii++; } counter = 0; break; case '/' : /* escape */ delimiter[counter - 1] = *c++; /* Escaping a delim character doesn't appear to be documented anywhere. Nonetheless, the assumption is that the only use is to escape ':' which is a one byte character in UTF-8. So, this logic will work. However, if there is a change in what can be escaped (say, escape a character that is > 1 byte in length), this logic has to change. Vinaya, 2007/09/07 */ break; case NATIVE_LF : /* Only NATIVE_LF is accepted as line terminator although Unicode defines other line terminators */ if (0 == ii) socketptr->delim0containsLF = TRUE; break; default: /* look at the next character */ break; } if ((c == top) && (0 < counter)) { if (gtm_utf8_mode) /* Check if delimiter has any invalid UTF-8 character */ c_len = utf8_len_strict(delimiter, counter); /* triggers badchar error for invalid sequence */ else c_len = counter; socketptr->delimiter[ii].addr = (char *)malloc(counter); memcpy(socketptr->delimiter[ii].addr, delimiter, counter); socketptr->delimiter[ii].len = counter; UNICODE_ONLY(socketptr->delimiter[ii].char_len = c_len); socketptr->idelimiter[ii] = socketptr->delimiter[ii]; if (0 == ii) socketptr->odelimiter0 = socketptr->delimiter[0]; socketptr->n_delimiter++; ii++; } if (counter > MAX_DELIM_LEN) { rts_error(VARLSTCNT(1) ERR_DELIMSIZNA); return FALSE; } } return TRUE; } void iosocket_delim_conv(socket_struct *socketptr, gtm_chset_t to_chset) { static char *conv_buff = NULL; int conv_len, delim_index, new_delim_len; assert(0 != socketptr->n_delimiter); assert(CHSET_UTF16BE == to_chset || CHSET_UTF16LE == to_chset); assert(gtm_utf8_mode); if (NULL == conv_buff) conv_buff = malloc(MAX_DELIM_LEN); for (delim_index = 0; delim_index < socketptr->n_delimiter; delim_index++) { conv_len = MAX_DELIM_LEN; new_delim_len = gtm_conv(chset_desc[CHSET_UTF8], chset_desc[to_chset], &socketptr->delimiter[delim_index], conv_buff, &conv_len); assert(MAX_DELIM_LEN > new_delim_len); if (MAX_DELIM_LEN < new_delim_len) { rts_error(VARLSTCNT(1) ERR_DELIMSIZNA); return; } socketptr->idelimiter[delim_index].len = new_delim_len; UNICODE_ONLY(socketptr->idelimiter[delim_index].char_len = socketptr->delimiter[delim_index].char_len); socketptr->idelimiter[delim_index].addr = malloc(new_delim_len); memcpy(socketptr->idelimiter[delim_index].addr, conv_buff, new_delim_len); } return; } void iosocket_delimiter_copy(socket_struct *from, socket_struct *to) { int delim_index; if (0 == (to->n_delimiter = from->n_delimiter)) return; for (delim_index = 0; delim_index < from->n_delimiter; delim_index++) { to->delimiter[delim_index] = from->delimiter[delim_index]; /* copy all fields */ to->delimiter[delim_index].addr = malloc(from->delimiter[delim_index].len); /* re-allocate buffer */ memcpy(to->delimiter[delim_index].addr, from->delimiter[delim_index].addr, from->delimiter[delim_index].len); to->idelimiter[delim_index] = to->delimiter[delim_index]; /* copy all fields */ if (from->delimiter[delim_index].addr != from->idelimiter[delim_index].addr) { /* has been converted */ to->idelimiter[delim_index].addr = malloc(from->idelimiter[delim_index].len); /* re-allocate buffer */ memcpy(to->idelimiter[delim_index].addr, from->idelimiter[delim_index].addr, from->idelimiter[delim_index].len); } } to->odelimiter0 = to->delimiter[0]; if (from->odelimiter0.addr != from->delimiter[0].addr) { /* has been converted */ to->odelimiter0.addr = malloc(from->odelimiter0.len); memcpy(to->odelimiter0.addr, from->odelimiter0.addr, from->odelimiter0.len); } return; } fis-gtm-V6.0-003/sr_port/iosocket_destroy.c0000644000032200000250000000252612201176157017576 0ustar librarygtc/**************************************************************** * * * Copyright 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_unistd.h" #include "gtm_socket.h" #include "io.h" #include "iotcpdef.h" #include "iotcproutine.h" #include "iosocketdef.h" #include "gtmio.h" GBLREF io_log_name *io_root_log_name; void iosocket_destroy (io_desc *ciod) { io_log_name **lpp, *lp; /* logical name pointers */ d_socket_struct *dsocketptr; assertpro(ciod->type == gtmsocket); assertpro(ciod->state == dev_closed); dsocketptr = (d_socket_struct *) ciod->dev_sp; assertpro(dsocketptr != NULL); for (lpp = &io_root_log_name, lp = *lpp; lp; lp = *lpp) { if (lp->iod->pair.in == ciod) { /* The only device that may be "split" is the principal device. Since it is permanently open, * it will never get here. */ assert(lp->iod == ciod); assert(lp->iod->pair.out == ciod); *lpp = (*lpp)->next; free(lp); } else lpp = &lp->next; } free(dsocketptr); free(ciod); } fis-gtm-V6.0-003/sr_port/iosocket_flush.c0000644000032200000250000000407712201176157017231 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_flush.c */ #include "mdef.h" #include "gtm_socket.h" #include "gtm_inet.h" #include #include "gtm_stdio.h" #include "gtm_string.h" #include "io.h" #include "iotcpdef.h" #include "iotcproutine.h" #include "gt_timer.h" #include "iosocketdef.h" GBLREF tcp_library_struct tcp_routines; error_def(ERR_SOCKWRITE); error_def(ERR_TEXT); error_def(ERR_CURRSOCKOFR); void iosocket_flush(io_desc *iod) { #ifdef C9A06001531 /* pending change request C9A06001531 */ d_socket_struct *dsocketptr; socket_struct *socketptr; int on = 1, off = 0; char *errptr; int4 errlen; assert(gtmsocket == iod->type); dsocketptr = (d_socket_struct *)iod->dev_sp; socketptr = dsocketptr->socket[dsocketptr->current_socket]; if (dsocketptr->current_socket >= dsocketptr->n_socket) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket); return; } memcpy(iod->dollar.device, "0", SIZEOF("0")); if ( -1 == tcp_routines.aa_setsockopt(socketptr->sd, SOL_SOCKET, TCP_NODELAY, &on, SIZEOF(on)) || (-1 == tcp_routines.aa_setsockopt(socketptr->sd, SOL_SOCKET, TCP_NODELAY, &off, SIZEOF(off)))) { errptr = (char *)STRERROR(errno); errlen = strlen(errptr); iod->dollar.za = 9; MEMCPY_LIT(iod->dollar.device, "1,"); memcpy(&iod->dollar.device[SIZEOF("1,") - 1], errptr, errlen + 1); /* we want the null */ if (socketptr->ioerror) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKWRITE, 0, ERR_TEXT, 2, errlen, errptr); return; } #endif return; } fis-gtm-V6.0-003/sr_port/iosocket_handle.c0000644000032200000250000000353012201176157017334 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_handle.c */ /* newhandle == TRUE * * create a new handle * return the old dsocketptr->n_socket * (i.e. number of socket) * (i.e. index of the new socket) * * newhandle == FALSE * * check if the handle exist * yes ==> return the index * no ==> return -1 * (return the number of sockets would provide more information, but can cause * confliction with index = 0 * 0 ==> socket exist and index is 0 * 0 ==> there are 0 sockets exist) */ #include "mdef.h" #include "gtm_time.h" #include "gtm_socket.h" #include "gtm_inet.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "io_params.h" #include "io.h" #include "iotcproutine.h" #include "iotcpdef.h" #include "gt_timer.h" #include "iosocketdef.h" int4 iosocket_handle(char *handle, int *len, boolean_t newhandle, d_socket_struct *dsocketptr) { boolean_t unique; int4 ii, counter = 0, loop_flag = 1; while(loop_flag) { if (newhandle) { SPRINTF(handle, "h%ld%d", time((time_t *)0), counter); *len = (short)strlen(handle); } ii = 0; unique = TRUE; while(ii < dsocketptr->n_socket) { if ((*len == dsocketptr->socket[ii]->handle_len) && (0 == memcmp(handle, dsocketptr->socket[ii]->handle, *len))) { unique = FALSE; break; } ii++; } if (!newhandle) return (unique ? -1 : ii); if (unique) return ii; counter++; } /* it will never reach here */ return -1; } fis-gtm-V6.0-003/sr_port/iosocket_iocontrol.c0000644000032200000250000000576712201176157020127 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_iocontrol.c */ #include "mdef.h" #include "gtm_socket.h" #include "gtm_inet.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "io.h" #include "iotimer.h" #include "iotcpdef.h" #include "gt_timer.h" #include "iosocketdef.h" #include "gtm_caseconv.h" #include "stringpool.h" GBLREF spdesc stringpool; GBLREF io_pair io_curr_device; error_def(ERR_INVCTLMNE); void iosocket_iocontrol(mstr *d) { char action[MAX_DEVCTL_LENGTH]; unsigned short depth; /* serve as depth for LISTEN and timeout for WAIT */ int length, n, timeout; if (0 == d->len) return; /* The contents of d->addr are passed to us from op_iocontrol. That routine sets up these parms * but does not zero terminate the string we are passing to SSCANF. If this is not a complex parm * with parens (as is the case with WRITE /WAIT type statements), SSCANF() will get into trouble * if the stringpool contains extra junk. For that reason, we now add a null terminator and make * sure the argument is not too big to parse into our buffer above. */ assert(d->addr == (char *)stringpool.free); /* Verify string is where we think it is so we don't corrupt something */ assert(MAX_DEVCTL_LENGTH > d->len); assert(IS_IN_STRINGPOOL(d->addr, d->len)); *(d->addr + d->len) = '\0'; if (0 == (n = SSCANF(d->addr, "%[^(](%hu)", &action[0], &depth))) memcpy(&action[0], d->addr, d->len); if (0 == (length = STRLEN(&action[0]))) return; lower_to_upper((uchar_ptr_t)&action[0], (uchar_ptr_t)&action[0], length); if (0 == memcmp(&action[0], "LISTEN", length)) { if (2 > n) depth = DEFAULT_LISTEN_DEPTH; iosocket_listen(io_curr_device.out, depth); } else if (0 == memcmp(&action[0], "WAIT", length)) { timeout = depth; if (2 > n) timeout = NO_M_TIMEOUT; iosocket_wait(io_curr_device.out, timeout); /* depth really means timeout here. */ } else rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVCTLMNE); return; } void iosocket_dlr_device(mstr *d) { io_desc *iod; int len; iod = io_curr_device.out; len = STRLEN(iod->dollar.device); /* verify internal buffer has enough space for $DEVICE string value */ assert((int)d->len > len); memcpy(d->addr, iod->dollar.device, len); d->len = len; return; } void iosocket_dlr_key(mstr *d) { io_desc *iod; int len; iod = io_curr_device.out; len = STRLEN(iod->dollar.key); /* verify internal buffer has enough space for $DEVICE string value */ assert((int)d->len > len); if (len > 0) memcpy(d->addr, iod->dollar.key, len); d->len = len; return; } fis-gtm-V6.0-003/sr_port/iosocket_listen.c0000644000032200000250000000507512201176157017405 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_listen.c */ /* checks the socket state -- socket_bind */ /* checks the socket type -- passive */ /* start listening */ #include "mdef.h" #include #include "gtm_inet.h" #include "gtm_socket.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "io_params.h" #include "io.h" #include "iotcproutine.h" #include "iotcpdef.h" #include "gt_timer.h" #include "iosocketdef.h" GBLREF tcp_library_struct tcp_routines; error_def(ERR_CURRSOCKOFR); error_def(ERR_LISTENPASSBND); error_def(ERR_LQLENGTHNA); error_def(ERR_SOCKLISTEN); error_def(ERR_TEXT); #define LISTENING "LISTENING" #define MAX_LISTEN_QUEUE_LENGTH 5 boolean_t iosocket_listen(io_desc *iod, unsigned short len) { char *errptr; int4 errlen; d_socket_struct *dsocketptr; socket_struct *socketptr; if (MAX_LISTEN_QUEUE_LENGTH < len) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_LQLENGTHNA, 1, len); return FALSE; } assert(gtmsocket == iod->type); dsocketptr = (d_socket_struct *)iod->dev_sp; socketptr = dsocketptr->socket[dsocketptr->current_socket]; if (dsocketptr->current_socket >= dsocketptr->n_socket) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket); return FALSE; } if ((socketptr->state != socket_bound) || (TRUE != socketptr->passive)) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LISTENPASSBND); return FALSE; } dsocketptr->iod->dollar.key[0] = '\0'; /* establish a queue of length len for incoming connections */ if (-1 == tcp_routines.aa_listen(socketptr->sd, len)) { errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKLISTEN, 0, ERR_TEXT, 2, errlen, errptr); return FALSE; } socketptr->state = socket_listening; len = SIZEOF(LISTENING) - 1; memcpy(&dsocketptr->iod->dollar.key[0], LISTENING, len); dsocketptr->iod->dollar.key[len++] = '|'; memcpy(&dsocketptr->iod->dollar.key[len], socketptr->handle, socketptr->handle_len); len += socketptr->handle_len; dsocketptr->iod->dollar.key[len++] = '|'; SPRINTF(&dsocketptr->iod->dollar.key[len], "%d", socketptr->local.port); return TRUE; } fis-gtm-V6.0-003/sr_port/iosocket_open.c0000644000032200000250000004272312201176157017051 0ustar librarygtc/**************************************************************** * * * Copyright 2012, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "gtm_string.h" #include "gtm_stdio.h" #include "gtm_socket.h" #include "gtm_inet.h" #include "gtm_time.h" #include "copy.h" #include "gt_timer.h" #include "io.h" #include "iotimer.h" #include "iotcp_select.h" #include "iotcpdef.h" #include "iotcproutine.h" #include "io_params.h" #include "iosocketdef.h" #include "gtm_caseconv.h" #include "stringpool.h" #include "gtm_conv.h" #include "gtm_utf8.h" #include "gtm_netdb.h" GBLREF tcp_library_struct tcp_routines; GBLREF d_socket_struct *socket_pool, *newdsocket; GBLREF io_pair io_std_device; /* standard device */ GBLREF boolean_t gtm_utf8_mode; GBLREF int4 gtm_max_sockets; GBLREF boolean_t dollar_zininterrupt; LITREF unsigned char io_params_size[]; LITREF mstr chset_names[]; error_def(ERR_ABNCOMPTINC); error_def(ERR_ADDRTOOLONG); error_def(ERR_DELIMSIZNA); error_def(ERR_DELIMWIDTH); error_def(ERR_DEVPARINAP); error_def(ERR_DEVPARMNEG); error_def(ERR_GETNAMEINFO); error_def(ERR_ILLESOCKBFSIZE); error_def(ERR_MRTMAXEXCEEDED); error_def(ERR_SOCKETEXIST); error_def(ERR_SOCKMAX); error_def(ERR_TEXT); error_def(ERR_ZFF2MANY); error_def(ERR_ZINTRECURSEIO); #define ESTABLISHED "ESTABLISHED" short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 timepar) { char addr[SA_MAXLITLEN], *errptr, sockaddr[SA_MAXLITLEN], temp_addr[SA_MAXLITLEN], dev_type[MAX_DEV_TYPE_LEN]; unsigned char ch, *c, *next, *top; int handle_len, moreread_timeout, len; unsigned short port; int4 errlen, msec_timeout, real_errno, p_offset = 0, zff_len, delimiter_len; int d_socket_struct_len; ABS_TIME cur_time, end_time; io_desc *ioptr; fd_set tcp_fd; uint4 bfsize = DEFAULT_SOCKET_BUFFER_SIZE, ibfsize; d_socket_struct *dsocketptr; socket_struct *socketptr; mv_stent *mv_zintdev; boolean_t zint_conn_restart = FALSE; socket_interrupt *sockintr; mstr chset_mstr; boolean_t attach_specified = FALSE, listen_specified = FALSE, connect_specified = FALSE, ioerror_specified = FALSE, delay_specified = FALSE, nodelay_specified = FALSE, ibfsize_specified = FALSE, moreread_specified = FALSE, is_principal = FALSE, /* called from inetd */ ichset_specified, ochset_specified; unsigned char delimiter_buffer[MAX_N_DELIMITER * (MAX_DELIM_LEN + 1)], zff_buffer[MAX_ZFF_LEN]; char ioerror, ip[3], tcp[4], sock_handle[MAX_HANDLE_LEN], delimiter[MAX_DELIM_LEN + 1]; int socketptr_delim_len; char ipaddr[SA_MAXLEN]; int errcode; struct addrinfo *ai_ptr, *remote_ai_ptr; ioptr = dev->iod; assert((params) *(pp->str.addr + p_offset) < (unsigned char)n_iops); assert(ioptr != 0); assert(ioptr->state >= 0 && ioptr->state < n_io_dev_states); assert(ioptr->type == gtmsocket); if ((ioptr->state == dev_closed) && mspace && mspace->str.len && mspace->str.addr) { lower_to_upper((uchar_ptr_t)dev_type, (uchar_ptr_t)mspace->str.addr, mspace->str.len); if (STR_LIT_LEN("SOCKET") != mspace->str.len || 0 != memcmp(dev_type, "SOCKET", STR_LIT_LEN("SOCKET"))) { if (ioptr->dev_sp) free(ioptr->dev_sp); ioptr->state = dev_never_opened; } } d_socket_struct_len = SIZEOF(d_socket_struct) + (SIZEOF(socket_struct) * (gtm_max_sockets - 1)); if (ioptr->state == dev_never_opened) { dsocketptr = ioptr->dev_sp = (void *)malloc(d_socket_struct_len); ioptr->newly_created = TRUE; memset(dsocketptr, 0, d_socket_struct_len); dsocketptr->iod = ioptr; } else dsocketptr = (d_socket_struct *)ioptr->dev_sp; if (ioptr->state == dev_never_opened) { ioptr->state = dev_closed; ioptr->width = TCPDEF_WIDTH; ioptr->length = TCPDEF_LENGTH; ioptr->wrap = TRUE; if (-1 == iotcp_fillroutine()) assert(FALSE); if (!io_std_device.in) /* called from io_init */ is_principal = TRUE; } if (dsocketptr->mupintr) { /* check if connect was interrupted */ sockintr = &dsocketptr->sock_save_state; if (sockwhich_invalid == sockintr->who_saved) GTMASSERT; /* Interrupt should never have an invalid save state */ if (dollar_zininterrupt) { dsocketptr->mupintr = FALSE; sockintr->who_saved = sockwhich_invalid; rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); } if (sockwhich_connect != sockintr->who_saved) GTMASSERT; /* ZINTRECURSEIO should have caught */ mv_zintdev = io_find_mvstent(dsocketptr->iod, FALSE); if (mv_zintdev && mv_zintdev->mv_st_cont.mvs_zintdev.buffer_valid) { /* mupintr will be reset and mvstent popped in iosocket_connect */ connect_specified = TRUE; ibfsize_specified = sockintr->ibfsize_specified; assert(newdsocket); assert(newdsocket == sockintr->newdsocket); memcpy(newdsocket, (d_socket_struct *)mv_zintdev->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr, d_socket_struct_len); socketptr = newdsocket->socket[newdsocket->current_socket]; assert(socketptr == (socket_struct *)mv_zintdev->mv_st_cont.mvs_zintdev.socketptr); zint_conn_restart = TRUE; /* skip what we already did, state == dev_closed */ } } else { ioptr->dollar.zeof = FALSE; if (NULL == newdsocket) newdsocket = (d_socket_struct *)malloc(d_socket_struct_len); memcpy(newdsocket, dsocketptr, d_socket_struct_len); memcpy(ioptr->dollar.device, "0", SIZEOF("0")); zff_len = -1; /* indicates neither ZFF nor ZNOFF specified */ delimiter_len = -1; /* indicates neither DELIM nor NODELIM specified */ ichset_specified = ochset_specified = FALSE; while (iop_eol != (ch = *(pp->str.addr + p_offset++))) { switch(ch) { case iop_delimiter: delimiter_len = (int4)(unsigned char)*(pp->str.addr + p_offset); if (((MAX_DELIM_LEN + 1) * MAX_N_DELIMITER) >= delimiter_len) memcpy(delimiter_buffer, (pp->str.addr + p_offset + 1), delimiter_len); else rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DELIMSIZNA); break; case iop_ipchset: UNICODE_ONLY( if (gtm_utf8_mode) { /* Only change ipchset if in UTF8 mode */ chset_mstr.addr = (char *)(pp->str.addr + p_offset + 1); chset_mstr.len = *(pp->str.addr + p_offset); SET_ENCODING(ioptr->ichset, &chset_mstr); ichset_specified = TRUE; } ); break; case iop_opchset: UNICODE_ONLY( if (gtm_utf8_mode) { /* Only change ipchset if in UTF8 mode */ chset_mstr.addr = (char *)(pp->str.addr + p_offset + 1); chset_mstr.len = *(pp->str.addr + p_offset); SET_ENCODING(ioptr->ochset, &chset_mstr); ochset_specified = TRUE; } ); break; case iop_chset: UNICODE_ONLY( if (gtm_utf8_mode) { /* Only change ipchset/opchset if in UTF8 mode */ chset_mstr.addr = (char *)(pp->str.addr + p_offset + 1); chset_mstr.len = *(pp->str.addr + p_offset); SET_ENCODING(ioptr->ichset, &chset_mstr); ioptr->ochset = ioptr->ichset; ichset_specified = ochset_specified = TRUE; } ); break; /* Note the following 4 cases (iop_m/utf16/utf16be/utf16le) have no corresponding device parameter but are included here because they can be easily used in internal processing. */ case iop_m: UNICODE_ONLY( ioptr->ichset = ioptr->ochset = CHSET_M; ichset_specified = ochset_specified = TRUE; ); break; case iop_utf16: UNICODE_ONLY( if (gtm_utf8_mode) { /* Only change chset if in UTF8 mode */ ioptr->ichset = ioptr->ochset = CHSET_UTF16; ichset_specified = ochset_specified = TRUE; } ); break; case iop_utf16be: UNICODE_ONLY( if (gtm_utf8_mode) { /* Only change chset if in UTF8 mode */ ioptr->ichset = ioptr->ochset = CHSET_UTF16BE; ichset_specified = ochset_specified = TRUE; } ); break; case iop_utf16le: UNICODE_ONLY( if (gtm_utf8_mode) { /* Only change chset if in UTF8 mode */ ioptr->ichset = ioptr->ochset = CHSET_UTF16LE; ichset_specified = ochset_specified = TRUE; } ); break; /**********************************/ case iop_nodelimiter: delimiter_len = 0; break; case iop_zdelay: delay_specified = TRUE; break; case iop_znodelay: nodelay_specified = TRUE; break; case iop_zbfsize: GET_ULONG(bfsize, pp->str.addr + p_offset); if ((0 == bfsize) || (MAX_SOCKET_BUFFER_SIZE < bfsize)) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, bfsize); break; case iop_zibfsize: ibfsize_specified = TRUE; GET_ULONG(ibfsize, pp->str.addr + p_offset); if ((0 == ibfsize) || (MAX_INTERNAL_SOCBUF_SIZE < ibfsize)) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, bfsize); break; case iop_zlisten: listen_specified = TRUE; len = (int)(*(pp->str.addr + p_offset)); if (len < SA_MAXLITLEN) { memset(sockaddr, 0, SIZEOF(sockaddr)); memcpy(sockaddr, pp->str.addr + p_offset + 1, len); } else rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ADDRTOOLONG, 4, len, pp->str.addr + p_offset + 1, len, SA_MAXLITLEN); break; case iop_connect: connect_specified = TRUE; len = (int)(*(pp->str.addr + p_offset)); if (len < SA_MAXLITLEN) { memset(sockaddr, 0, SIZEOF(sockaddr)); memcpy(sockaddr, pp->str.addr + p_offset + 1, len); } else rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ADDRTOOLONG, 4, len, pp->str.addr + p_offset + 1, len, SA_MAXLITLEN); break; case iop_ioerror: ioerror_specified = TRUE; ioerror = *(pp->str.addr + p_offset + 1); /* the first char decides */ break; case iop_exception: ioptr->error_handler.len = *(pp->str.addr + p_offset); ioptr->error_handler.addr = (char *)(pp->str.addr + p_offset + 1); s2pool(&ioptr->error_handler); break; case iop_attach: attach_specified = TRUE; handle_len = (int)(*(pp->str.addr + p_offset)); if (handle_len > MAX_HANDLE_LEN) handle_len = MAX_HANDLE_LEN; memcpy(sock_handle, pp->str.addr + p_offset + 1, handle_len); break; case iop_socket: rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARINAP); break; case iop_zff: if (MAX_ZFF_LEN >= (zff_len = (int4)(unsigned char)*(pp->str.addr + p_offset))) memcpy(zff_buffer, (char *)(pp->str.addr + p_offset + 1), zff_len); else rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZFF2MANY, 2, zff_len, MAX_ZFF_LEN); break; case iop_znoff: zff_len = 0; break; case iop_wrap: ioptr->wrap = TRUE; break; case iop_nowrap: ioptr->wrap = FALSE; break; case iop_morereadtime: /* Time in milliseconds socket read will wait for more data before returning */ GET_LONG(moreread_timeout, pp->str.addr + p_offset); if (-1 == moreread_timeout) moreread_timeout = DEFAULT_MOREREAD_TIMEOUT; else if (-1 > moreread_timeout) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG); else if (MAX_MOREREAD_TIMEOUT < moreread_timeout) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MRTMAXEXCEEDED, 1, MAX_MOREREAD_TIMEOUT); moreread_specified = TRUE; break; default: break; } p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ? (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]); } if (!ichset_specified) ioptr->ichset = (gtm_utf8_mode) ? CHSET_UTF8 : CHSET_M; if (!ochset_specified) ioptr->ochset = (gtm_utf8_mode) ? CHSET_UTF8 : CHSET_M; if (CHSET_M != ioptr->ichset && CHSET_UTF16 != ioptr->ichset) get_chset_desc(&chset_names[ioptr->ichset]); if (CHSET_M != ioptr->ochset && CHSET_UTF16 != ioptr->ochset) get_chset_desc(&chset_names[ioptr->ochset]); if (listen_specified && connect_specified) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("CONNECT"), LEN_AND_LIT("ZLISTEN"), LEN_AND_LIT("OPEN")); return FALSE; } if (delay_specified && nodelay_specified) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("DELAY"), LEN_AND_LIT("NODELAY"), LEN_AND_LIT("OPEN")); return FALSE; } if (listen_specified || connect_specified || is_principal) { if (NULL == (socketptr = iosocket_create(sockaddr, bfsize, is_principal ? file_des : -1))) return FALSE; assert(listen_specified == socketptr->passive); if (ioerror_specified) socketptr->ioerror = ('T' == ioerror || 't' == ioerror); socketptr->nodelay = nodelay_specified; /* defaults to DELAY */ if (ibfsize_specified) socketptr->bufsiz = ibfsize; if (moreread_specified) { socketptr->moreread_timeout = moreread_timeout; socketptr->def_moreread_timeout = TRUE; /* iosocket_readfl.c needs to know user specified */ } /* socket handle -- also check for duplication */ if (attach_specified) { if (iosocket_handle(sock_handle, &handle_len, FALSE, newdsocket) >= 0) { if (FD_INVALID != socketptr->temp_sd) tcp_routines.aa_close(socketptr->temp_sd); SOCKET_FREE(socketptr); assert(ioptr->newly_created == FALSE); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKETEXIST, 2, handle_len, sock_handle); return FALSE; } } else iosocket_handle(sock_handle, &handle_len, TRUE, dsocketptr); socketptr->handle_len = handle_len; memcpy(socketptr->handle, sock_handle, handle_len); /* parse the delimiter: delimiter_buffer ==> socketptr->delimiter[...] */ if (0 <= delimiter_len) iosocket_delimiter(delimiter_buffer, delimiter_len, socketptr, (0 == delimiter_len)); if (ioptr->wrap && 0 != socketptr->n_delimiter && ioptr->width < socketptr->delimiter[0].len) { socketptr_delim_len = socketptr->delimiter[0].len; SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DELIMWIDTH, 2, ioptr->width, socketptr_delim_len); assert(FALSE); } /* connects newdsocket and socketptr (the new socket) */ if (gtm_max_sockets <= newdsocket->n_socket) { assert(ioptr->newly_created == FALSE); if (FD_INVALID != socketptr->temp_sd) tcp_routines.aa_close(socketptr->temp_sd); SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets); return FALSE; } socketptr->dev = newdsocket; newdsocket->socket[newdsocket->n_socket++] = socketptr; newdsocket->current_socket = newdsocket->n_socket - 1; } if (0 <= zff_len && /* ZFF or ZNOFF specified */ 0 < (socketptr->zff.len = zff_len)) /* assign the new ZFF len, might be 0 from ZNOFF, or ZFF="" */ { /* ZFF="non-zero-len-string" specified */ if (gtm_utf8_mode) /* Check if ZFF has any invalid UTF-8 character */ { /* Note: the ZFF string originates from the source program, so is in UTF-8 mode or M mode regardless * of OCHSET of this device. ZFF is output on WRITE # command, and MUST contain valid UTF-8 sequence. */ utf8_len_strict(zff_buffer, zff_len); /* triggers badchar error for invalid sequence */ } if (NULL == socketptr->zff.addr) /* we rely on socketptr->zff.addr being set to 0 in iosocket_create() */ socketptr->zff.addr = (char *)malloc(MAX_ZFF_LEN); memcpy(socketptr->zff.addr, zff_buffer, zff_len); } } /* action */ if ((listen_specified && (!iosocket_bind(socketptr, timepar, ibfsize_specified))) || (connect_specified && (!iosocket_connect(socketptr, timepar, ibfsize_specified)))) { if (socketptr->sd > 0) (void)tcp_routines.aa_close(socketptr->sd); SOCKET_FREE(socketptr); return FALSE; } else if (is_principal) { /* fill in what bind or connect would */ ai_ptr = &(socketptr->local.ai); remote_ai_ptr = &(socketptr->remote.ai); /* translate internal address to numeric ip address */ GETNAMEINFO(SOCKET_LOCAL_ADDR(socketptr), ai_ptr->ai_addrlen, ipaddr, SIZEOF(ipaddr), NULL, 0, NI_NUMERICHOST, errcode); if (0 != errcode) { RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); return FALSE; } STRNDUP(ipaddr, SIZEOF(ipaddr), socketptr->local.saddr_ip); GETNAMEINFO(SOCKET_REMOTE_ADDR(socketptr), remote_ai_ptr->ai_addrlen, ipaddr, SIZEOF(ipaddr), NULL, 0, NI_NUMERICHOST, errcode); if (0 != errcode) { RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); return FALSE; } STRNDUP(ipaddr, SIZEOF(ipaddr), socketptr->remote.saddr_ip); len = SIZEOF(ESTABLISHED) - 1; memcpy(&ioptr->dollar.key[0], ESTABLISHED, len); ioptr->dollar.key[len++] = '|'; memcpy(&ioptr->dollar.key[len], socketptr->handle, socketptr->handle_len); len += socketptr->handle_len; ioptr->dollar.key[len++] = '|'; strncpy(&ioptr->dollar.key[len], socketptr->remote.saddr_ip, DD_BUFLEN - 1 - len); ioptr->dollar.key[DD_BUFLEN-1] = '\0'; /* In case we fill the buffer */ } /* commit the changes to the list */ if (listen_specified || connect_specified || is_principal) { socketptr->dev = dsocketptr; memcpy(dsocketptr, newdsocket, d_socket_struct_len); } ioptr->newly_created = FALSE; ioptr->state = dev_open; return TRUE; } fis-gtm-V6.0-003/sr_port/iosocket_poolinit.c0000644000032200000250000000304012201176157017732 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_poolinit.c */ #include "mdef.h" #include "gtm_string.h" #include #include "gtm_socket.h" #include "gtm_inet.h" #include "io.h" #include "io_params.h" #include "iotimer.h" #include "iotcpdef.h" #include "gt_timer.h" #include "iosocketdef.h" #include "op.h" GBLREF d_socket_struct *socket_pool; static char socketpoolv[] = "socketpool"; static char socketpoolp = '\0'; static char socketpoolm[] = "socket"; void iosocket_poolinit(void) { mval sockv, sockp, sockm; int t; io_log_name *nl; memset(&sockv, 0, SIZEOF(mval)); memset(&sockp, 0, SIZEOF(mval)); memset(&sockm, 0, SIZEOF(mval)); sockv.mvtype = MV_STR; sockv.str.len = SIZEOF(socketpoolv) - 1; sockv.str.addr = &socketpoolv[0]; sockp.mvtype = MV_STR; sockp.str.len = SIZEOF(socketpoolp); sockp.str.addr = &socketpoolp; sockm.mvtype = MV_STR; sockm.str.len = SIZEOF(socketpoolm) - 1; sockm.str.addr = &socketpoolm[0]; t = NO_M_TIMEOUT; op_open(&sockv, &sockp, t, &sockm); nl = get_log_name(&sockv.str, NO_INSERT); assert(NULL != nl); socket_pool = (d_socket_struct *)(nl->iod->dev_sp); } fis-gtm-V6.0-003/sr_port/iosocket_rdone.c0000644000032200000250000000302312201176157017205 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_rdone.c */ #include "mdef.h" #include "gtm_socket.h" #include "gtm_inet.h" #include "io.h" #include "gt_timer.h" #include "iotcpdef.h" #include "iosocketdef.h" #include "gtm_utf8.h" GBLREF io_pair io_curr_device; int iosocket_rdone(mint *v, int4 timeout) { mval tmp; int ret; uint4 codepoint; io_desc *iod; gtm_chset_t ichset; ret = iosocket_readfl(&tmp, 1, timeout); if (ret) { if (0 < tmp.str.len) { ichset = io_curr_device.in->ichset; switch(ichset) { case CHSET_M: codepoint = (unsigned char)tmp.str.addr[0]; break; case CHSET_UTF8: UTF8_MBTOWC(tmp.str.addr, tmp.str.addr + tmp.str.len, codepoint); break; case CHSET_UTF16BE: UTF16BE_MBTOWC(tmp.str.addr, tmp.str.addr + tmp.str.len, codepoint); break; case CHSET_UTF16LE: UTF16LE_MBTOWC(tmp.str.addr, tmp.str.addr + tmp.str.len, codepoint); break; default: GTMASSERT; } UNICODE_ONLY(assert(WEOF != codepoint)); } else /* Null length string returns 0 */ codepoint = 0; *v = (mint)(codepoint); } else *v = -1; return ret; } fis-gtm-V6.0-003/sr_port/iosocket_read.c0000644000032200000250000000134612201176157017017 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_read.c */ #include "mdef.h" #include "gtm_socket.h" #include "gtm_inet.h" #include "io.h" #include "gt_timer.h" #include "iotcpdef.h" #include "iosocketdef.h" int iosocket_read(mval *v, int4 timeout) { return iosocket_readfl(v, 0, timeout); /* 0 means not fixed length */ } fis-gtm-V6.0-003/sr_port/iosocket_readfl.c0000644000032200000250000010613112201176177017341 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_readfl.c */ #include "mdef.h" #include #include "gtm_stdio.h" #include "gtm_time.h" #ifdef __MVS__ #include #endif #include "gtm_socket.h" #include "gtm_inet.h" #include "gtm_string.h" #ifdef UNIX #include "gtm_fcntl.h" #include "eintr_wrappers.h" #endif #include "gt_timer.h" #include "io.h" #include "iotimer.h" #include "iotcpdef.h" #include "iotcproutine.h" #include "stringpool.h" #include "iosocketdef.h" #include "min_max.h" #include "outofband.h" #include "wake_alarm.h" #include "gtm_conv.h" #include "gtm_utf8.h" #include #include "stack_frame.h" #include "mv_stent.h" #include "send_msg.h" #include "error.h" #include "trace_table.h" GBLREF stack_frame *frame_pointer; GBLREF unsigned char *stackbase, *stacktop, *msp, *stackwarn; GBLREF mv_stent *mv_chain; GBLREF io_pair io_curr_device; #ifdef UNIX GBLREF io_pair io_std_device; GBLREF bool prin_in_dev_failure; #endif GBLREF bool out_of_time; GBLREF spdesc stringpool; GBLREF volatile int4 outofband; GBLREF mstr chset_names[]; GBLREF UConverter *chset_desc[]; GBLREF boolean_t dollar_zininterrupt; GBLREF int socketus_interruptus; GBLREF boolean_t gtm_utf8_mode; error_def(ERR_BOMMISMATCH); error_def(ERR_CURRSOCKOFR); error_def(ERR_GETSOCKOPTERR); error_def(ERR_IOEOF); error_def(ERR_MAXSTRLEN); error_def(ERR_NOSOCKETINDEV); error_def(ERR_SETSOCKOPTERR); error_def(ERR_STACKCRIT); error_def(ERR_STACKOFLOW); error_def(ERR_TEXT); error_def(ERR_ZINTRECURSEIO); UNIX_ONLY(error_def(ERR_NOPRINCIO);) #ifdef UNICODE_SUPPORTED /* Maintenance of $KEY, $DEVICE and $ZB on a badchar error */ void iosocket_readfl_badchar(mval *vmvalptr, int datalen, int delimlen, unsigned char *delimptr, unsigned char *strend) { int tmplen, len; unsigned char *delimend; io_desc *iod; d_socket_struct *dsocketptr; iod = io_curr_device.in; dsocketptr = (d_socket_struct *)(iod->dev_sp); vmvalptr->str.len = datalen; vmvalptr->str.addr = (char *)stringpool.free; if (0 < datalen) { /* Return how much input we got */ if ((CHSET_M != iod->ichset) && (CHSET_UTF8 != iod->ichset)) { DBGSOCK2((stdout, "socrflbc: Converting UTF16xx data back to UTF8 for internal use\n")); vmvalptr->str.len = gtm_conv(chset_desc[iod->ichset], chset_desc[CHSET_UTF8], &vmvalptr->str, NULL, NULL); vmvalptr->str.addr = (char *)stringpool.free; } stringpool.free += vmvalptr->str.len; } if ((NULL != strend) && (NULL != delimptr)) { /* First find the end of the delimiter (max of 4 bytes) */ if (0 == delimlen) { for (delimend = delimptr; (GTM_MB_LEN_MAX >= delimlen) && (delimend < strend); ++delimend, ++delimlen) { if (UTF8_VALID(delimend, strend, tmplen)) break; } } if (0 < delimlen) { /* Set $KEY and $ZB with the failing badchar */ memcpy(iod->dollar.zb, delimptr, MIN(delimlen, ESC_LEN - 1)); iod->dollar.zb[MIN(delimlen, ESC_LEN - 1)] = '\0'; memcpy(iod->dollar.key, delimptr, MIN(delimlen, DD_BUFLEN - 1)); iod->dollar.key[MIN(delimlen, DD_BUFLEN - 1)] = '\0'; } } len = SIZEOF(ONE_COMMA) - 1; memcpy(iod->dollar.device, ONE_COMMA, len); memcpy(&iod->dollar.device[len], BADCHAR_DEVICE_MSG, SIZEOF(BADCHAR_DEVICE_MSG)); } #endif /* VMS uses the UCX interface; should support others that emulate it * width == 0 is a flag for non-fixed length read. timeout is in seconds */ int iosocket_readfl(mval *v, int4 width, int4 timeout) { int ret, byteperchar; boolean_t timed, vari, more_data, terminator, has_delimiter, requeue_done; boolean_t zint_restart, outofband_terminate, one_read_done, utf8_active; int flags, len, real_errno, save_errno, fcntl_res, errlen, charlen, stp_need; int bytes_read, orig_bytes_read, ii, max_bufflen, bufflen, chars_read, mb_len, match_delim; io_desc *iod; d_socket_struct *dsocketptr; socket_struct *socketptr; int4 msec_timeout; /* timeout in milliseconds */ TID timer_id; ABS_TIME cur_time, end_time, time_for_read, zero; char *errptr; unsigned char *buffptr, *c_ptr, *c_top, *inv_beg, *buffer_start, *old_stringpool_free; ssize_t status; gtm_chset_t ichset; mv_stent *mv_zintdev; socket_interrupt *sockintr; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(stringpool.free >= stringpool.base); assert(stringpool.free <= stringpool.top); iod = io_curr_device.in; TRCTBL_ENTRY(SOCKRFL_ENTRY, width, iod, (INTPTR_T)socketus_interruptus, NULL); ichset = iod->ichset; assert(dev_open == iod->state); assert(gtmsocket == iod->type); dsocketptr = (d_socket_struct *)(iod->dev_sp); if (0 >= dsocketptr->n_socket) { iod->dollar.za = 9; rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOSOCKETINDEV); return 0; } if (dsocketptr->n_socket <= dsocketptr->current_socket) { iod->dollar.za = 9; rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket); return 0; } utf8_active = NON_UNICODE_ONLY(FALSE) UNICODE_ONLY(gtm_utf8_mode ? IS_UTF_CHSET(ichset) : FALSE); byteperchar = UNICODE_ONLY(utf8_active ? GTM_MB_LEN_MAX :) 1; if (0 == width) { /* op_readfl won't do this; must be a call from iosocket_read */ vari = TRUE; width = MAX_STRLEN; } else { vari = FALSE; width = (width < MAX_STRLEN) ? width : MAX_STRLEN; } /* If width is set to MAX_STRLEN, we might be overly generous (assuming every char is just one byte) we must check if byte * length crosses the MAX_STRLEN boundary */ socketptr = dsocketptr->socket[dsocketptr->current_socket]; assert(socketptr); sockintr = &dsocketptr->sock_save_state; assert(sockintr); outofband_terminate = FALSE; one_read_done = FALSE; zint_restart = FALSE; /* Check if new or resumed read */ if (dsocketptr->mupintr) { /* We have a pending read restart of some sort */ assertpro(sockwhich_invalid != sockintr->who_saved); /* Interrupt should never have an invalid save state */ /* Check we aren't recursing on this device */ if (dollar_zininterrupt) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); assertpro(sockwhich_readfl == sockintr->who_saved); /* ZINTRECURSEIO should have caught */ DBGSOCK((stdout, "socrfl: *#*#*#*#*#*#*# Restarted interrupted read\n")); dsocketptr->mupintr = FALSE; sockintr->who_saved = sockwhich_invalid; mv_zintdev = io_find_mvstent(iod, FALSE); assert(mv_zintdev); if (mv_zintdev) { if (mv_zintdev->mv_st_cont.mvs_zintdev.buffer_valid) { bytes_read = mv_zintdev->mv_st_cont.mvs_zintdev.curr_sp_buffer.len; assert(bytes_read == sockintr->bytes_read); if (bytes_read) { buffer_start = (unsigned char *)mv_zintdev->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr; zint_restart = TRUE; TRCTBL_ENTRY(SOCKRFL_MVS_ZINTR, bytes_read, buffer_start, stringpool.free, NULL); /* BYPASS_OK */ } else TRCTBL_ENTRY(SOCKRFL_MVS_ZINTR, 0, NULL, stringpool.free, NULL); /* BYPASS_OK found but empty */ } else { TRCTBL_ENTRY(SOCKRFL_MVS_ZINTR, 0, NULL, NULL, NULL); /* Indicate mvstent found but invalid */ assert(FALSE); DBGSOCK((stdout, "socrfl: Evidence of an interrupt, but it was invalid\n")); } /* Done with this mv_stent. Pop it off if we can, else mark it inactive. */ if (mv_chain == mv_zintdev) POP_MV_STENT(); /* pop if top of stack */ else { /* Else mark it unused */ mv_zintdev->mv_st_cont.mvs_zintdev.buffer_valid = FALSE; mv_zintdev->mv_st_cont.mvs_zintdev.curr_sp_buffer.len = 0; mv_zintdev->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr = NULL; } } else { sockintr->end_time_valid = FALSE; DBGSOCK((stdout, "socrfl: Evidence of an interrupt, but no MV_STENT\n")); TRCTBL_ENTRY(SOCKRFL_MVS_ZINTR, -1, NULL, NULL, NULL); /* Indicater mvstent entry not found */ } } else sockintr->end_time_valid = FALSE; if (!zint_restart) { /* Simple path (not restart or nothing read,) no worries * compute the worst case byte requirement knowing that width is in chars */ max_bufflen = (vari) ? MAX_STRBUFF_INIT : ((MAX_STRLEN > (width * byteperchar)) ? (width * byteperchar) : MAX_STRLEN); ENSURE_STP_FREE_SPACE(max_bufflen); bytes_read = 0; chars_read = 0; buffer_start = NULL; } else { max_bufflen = sockintr->max_bufflen; chars_read = sockintr->chars_read; assert(chars_read <= bytes_read); DBGSOCK((stdout, "socrfl: .. mv_stent found - bytes_read: %d chars_read: %d max_bufflen: %d" " interrupts: %d\n", bytes_read, chars_read, max_bufflen, socketus_interruptus)); DBGSOCK((stdout, "socrfl: .. timeout: %d\n", timeout)); DBGSOCK_ONLY2(if (sockintr->end_time_valid) DBGSOCK((stdout, "socrfl: .. endtime: %d/%d\n", end_time.at_sec, end_time.at_usec))); DBGSOCK((stdout, "socrfl: .. buffer address: 0x"lvaddr" stringpool: 0x"lvaddr"\n", buffer_start, stringpool.free)); if (stringpool.free != (buffer_start + bytes_read)) /* BYPASSOK */ { /* Not @ stringpool.free - must move what we have, so we need room for the whole anticipated message */ DBGSOCK2((stdout, "socrfl: .. Stuff put on string pool after our buffer\n")); stp_need = max_bufflen; } else { /* Previously read buffer piece is still last thing in stringpool, so we need room for the rest */ DBGSOCK2((stdout, "socrfl: .. Our buffer did not move in the stringpool\n")); stp_need = max_bufflen - bytes_read; assert(stp_need < max_bufflen); } TRCTBL_ENTRY(SOCKRFL_RESTARTED, chars_read, (INTPTR_T)max_bufflen, (INTPTR_T)stp_need, buffer_start); if (!IS_STP_SPACE_AVAILABLE(stp_need)) { /* Need more room */ DBGSOCK2((stdout, "socrfl: .. garbage collection done in restart after interrupt\n")); v->str.addr = (char *)buffer_start; /* Protect buffer from reclaim */ v->str.len = bytes_read; INVOKE_STP_GCOL(max_bufflen); buffer_start = (unsigned char *)v->str.addr; TRCTBL_ENTRY(SOCKRFL_RSTGC, 0, buffer_start, stringpool.free, NULL); } if ((buffer_start + bytes_read) < stringpool.free) /* BYPASSOK */ { /* Now need to move it to the top */ assert(stp_need == max_bufflen); memcpy(stringpool.free, buffer_start, bytes_read); /* BYPASSOK */ buffer_start = stringpool.free; /* BYPASSOK */ } else { /* It should still be just under the used space */ assert((buffer_start + bytes_read) == stringpool.free); /* BYPASSOK */ stringpool.free = buffer_start; /* backup the free pointer */ } v->str.len = 0; /* Clear incase interrupt or error -- don't want to hold this buffer */ /* At this point, our previous buffer is sitting at stringpool.free and can be * expanded if necessary. This is what the rest of the code is expecting. */ } TRCTBL_ENTRY(SOCKRFL_BEGIN, chars_read, buffer_start, stringpool.free, NULL); if (iod->dollar.x && (TCP_WRITE == socketptr->lastop)) { /* Switching from write to read */ assert(!zint_restart); if (!iod->dollar.za) iosocket_flush(iod); iod->dollar.x = 0; } socketptr->lastop = TCP_READ; ret = TRUE; has_delimiter = (0 < socketptr->n_delimiter); time_for_read.at_sec = 0; if (0 == timeout) time_for_read.at_usec = 0; else if (socketptr->def_moreread_timeout) time_for_read.at_usec = socketptr->moreread_timeout * 1000; else time_for_read.at_usec = INITIAL_MOREREAD_TIMEOUT * 1000; DBGSOCK((stdout, "socrfl: moreread_timeout = %d def_moreread_timeout= %d time = %d \n", socketptr->moreread_timeout, socketptr->def_moreread_timeout, time_for_read.at_usec)); timer_id = (TID)iosocket_readfl; out_of_time = FALSE; if (NO_M_TIMEOUT == timeout) { timed = FALSE; msec_timeout = NO_M_TIMEOUT; assert(!sockintr->end_time_valid); } else { timed = TRUE; msec_timeout = timeout2msec(timeout); if (msec_timeout > 0) { /* There is time to wait */ # ifdef UNIX /* Set blocking I/O */ FCNTL2(socketptr->sd, F_GETFL, flags); if (flags < 0) { iod->dollar.za = 9; save_errno = errno; errptr = (char *)STRERROR(errno); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, LEN_AND_LIT("F_GETFL FOR NON BLOCKING I/O"), save_errno, LEN_AND_STR(errptr)); } FCNTL3(socketptr->sd, F_SETFL, flags & (~(O_NDELAY | O_NONBLOCK)), fcntl_res); if (fcntl_res < 0) { iod->dollar.za = 9; save_errno = errno; errptr = (char *)STRERROR(errno); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("F_SETFL FOR NON BLOCKING I/O"), save_errno, LEN_AND_STR(errptr)); } # endif sys_get_curr_time(&cur_time); if (!sockintr->end_time_valid) add_int_to_abs_time(&cur_time, msec_timeout, &end_time); else { /* End_time taken from restart data. Compute what msec_timeout should be so timeout timer * gets set correctly below. */ end_time = sockintr->end_time; /* Restore end_time for timeout */ cur_time = sub_abs_time(&end_time, &cur_time); if (0 > cur_time.at_sec) { msec_timeout = -1; out_of_time = TRUE; } else msec_timeout = (int4)(cur_time.at_sec * 1000 + cur_time.at_usec / 1000); DBGSOCK((stdout, "socrfl: Taking timeout end time from read restart data - " "computed msec_timeout: %d\n", msec_timeout)); } if (0 < msec_timeout) start_timer(timer_id, msec_timeout, wake_alarm, 0, NULL); } else { out_of_time = TRUE; DBGSOCK((stdout, "socrfl: No timeout specified, assuming out_of_time\n")); } } sockintr->end_time_valid = FALSE; iod->dollar.key[0] = '\0'; iod->dollar.zb[0] = '\0'; more_data = TRUE; real_errno = 0; requeue_done = FALSE; DBGSOCK((stdout, "socrfl: ##################### Entering read loop ######################\n")); for (status = 0; status >= 0;) { DBGSOCK2((stdout, "socrfl: ********* Top of read loop - bytes_read: %d chars_read: %d " "buffered_length: %d\n", bytes_read, chars_read, socketptr->buffered_length)); DBGSOCK2((stdout, "socrfl: ********* read-width: %d vari: %d status: %d\n", width, vari, status)); if (bytes_read >= max_bufflen) { /* More buffer needed. Extend the stringpool buffer by doubling the size as much as we * extended previously */ DBGSOCK((stdout, "socrfl: Buffer expand1 bytes_read(%d) max_bufflen(%d)\n", bytes_read, max_bufflen)); assert(vari); max_bufflen += max_bufflen; if (MAX_STRLEN < max_bufflen) max_bufflen = MAX_STRLEN; if (!IS_STP_SPACE_AVAILABLE(max_bufflen)) { v->str.len = bytes_read; /* to keep the data read so far from being garbage collected */ v->str.addr = (char *)stringpool.free; stringpool.free += v->str.len; /* BYPASSOK */ assert(stringpool.free <= stringpool.top); /* BYPASSOK */ INVOKE_STP_GCOL(max_bufflen); old_stringpool_free = stringpool.free; /* BYPASSOK */ assert(stringpool.free == (unsigned char *)(v->str.addr + v->str.len)); /* BYPASSOK */ stringpool.free = (unsigned char *)v->str.addr; v->str.len = 0; /* If interrupted, don't hold onto old space */ TRCTBL_ENTRY(SOCKRFL_EXPBUFGC, bytes_read, stringpool.free, old_stringpool_free, /* BYPASSOK */ (UINTPTR_T)max_bufflen); } } if (has_delimiter || requeue_done || (socketptr->first_read && (CHSET_M != ichset))) { /* Delimiter scanning needs one char at a time. Question is how big is a char? * For the UTF character sets, we have a similar issue (with the same solution) in that * we need to make sure the entire BOM we may have is in the buffer. If the last read * caused chars to be requeued, we have to make sure that we read in one full character * (buffer likely contains only a partial char) in order to make forward progess. If we * didn't do this, we would just pull the partial char out of the buffer, notice its incompleteness * and requeue it again and again. Forcing a full char read lets us continue past this point. */ requeue_done = FALSE; /* housekeeping -- We don't want to come back here for this reason * until it happens again */ DBGSOCK_ONLY2(if (socketptr->first_read && (CHSET_M != ichset)) DBGSOCK((stdout, "socrfl: Prebuffering because ichset = UTF16\n")); else DBGSOCK((stdout, "socrfl: Prebuffering because we have delimiter or requeue\n"))); if (CHSET_M == iod->ichset) bufflen = 1; /* M mode, 1 char == 1 byte */ else { /* We need to make sure the read buffer contains a complete UTF character and to make sure * we know how long that character is so we can read it completely. The issue is that if we * read a partial utf character, the utf checking code below notices this and rebuffers it * so that it gets re-read on the next iteration. However, this then re-reads the same * partial character and we have a loop. We make a call here which takes a peek at the * first byte of the next character (and reads it in if necessary), determines how long the * character is and verifies that many characters are available in the buffer and returns the * character length to us to use for bufflen. */ charlen = (int)iosocket_snr_utf_prebuffer(iod, socketptr, 0, &time_for_read, (!vari || has_delimiter || 0 == chars_read)); DBGSOCK((stdout, "socrfl: charlen from iosocket_snr_utf_prebuffer = %d\n", charlen)); if (0 < charlen) { /* We know how long the next char is. If it fits in our buffer, then it is * the correct bufflen. If it won't, our buffer is full and we need to expand. */ if ((max_bufflen - bytes_read) < charlen) { DBGSOCK((stdout, "socrfl: Buffer expand2 - max_bufflen(%d) bytes_read(%d)\n", max_bufflen, bytes_read)); assert(vari); max_bufflen += max_bufflen; if (MAX_STRLEN < max_bufflen) max_bufflen = MAX_STRLEN; if (!IS_STP_SPACE_AVAILABLE(max_bufflen)) { v->str.len = bytes_read; /* To keep the data read so far from * being garbage collected */ v->str.addr = (char *)stringpool.free; stringpool.free += bytes_read; assert(stringpool.free <= stringpool.top); INVOKE_STP_GCOL(max_bufflen); old_stringpool_free = stringpool.free; assert(stringpool.free == (unsigned char *)(v->str.addr + v->str.len)); stringpool.free = (unsigned char *)v->str.addr; v->str.len = 0; /* If interrupted, don't hold onto old space */ TRCTBL_ENTRY(SOCKRFL_EXPBUFGC, bytes_read, stringpool.free, /* BYPASSOK */ old_stringpool_free, (UINTPTR_T)max_bufflen); } } bufflen = charlen; } else if (0 == charlen) { /* No data was available or there was a timeout. We set status to -3 here * so that we end up bypassing the call to iosocket_snr below which was to * do the actual IO. No need to repeat our lack of IO issue. */ DBGSOCK((stdout, "socrfl: Timeout or end of data stream\n")); status = -3; /* To differentiate from status=0 if prebuffer bypassed */ DEBUG_ONLY(bufflen = 0); /* Triggers assert in iosocket_snr if we end up there anyway */ } else { /* Something bad happened. Feed the error to the lower levels for proper handling */ DBGSOCK((stdout, "socrfl: Read error: status: %d errno: %d\n", charlen, errno)); status = charlen; DEBUG_ONLY(bufflen = 0); /* Triggers assert in iosocket_snr if we end up there anyway */ } } } else { bufflen = max_bufflen - bytes_read; DBGSOCK((stdout, "socrfl: Regular read .. bufflen = %d\n", bufflen)); status = 0; } buffptr = (stringpool.free + bytes_read); terminator = FALSE; if (0 <= status) /* An IO above in prebuffering may have failed in which case we do not want to reset status */ status = iosocket_snr(socketptr, buffptr, bufflen, 0, &time_for_read); else { DBGSOCK((stdout, "socrfl: Data read bypassed - status: %d\n", status)); } TRCTBL_ENTRY(SOCKRFL_RDSTATUS, status, (INTPTR_T)outofband, (INTPTR_T)out_of_time, (INTPTR_T)bytes_read); if (0 == status || -3 == status) /* -3 status can happen on EOB from prebuffering */ { DBGSOCK((stdout, "socrfl: No more data available\n")); more_data = FALSE; status = 0; /* Consistent treatment of no more data */ } else if (0 < status) { if (timeout && !socketptr->def_moreread_timeout && !one_read_done) { one_read_done = TRUE; DBGSOCK((stdout, "socrfl: before moreread_timeout = %d timeout = %d \n", socketptr->moreread_timeout,time_for_read.at_usec)); time_for_read.at_usec = DEFAULT_MOREREAD_TIMEOUT * 1000; DBGSOCK((stdout, "socrfl: after timeout = %d \n",time_for_read.at_usec)); } DBGSOCK((stdout, "socrfl: Bytes read: %d\n", status)); bytes_read += (int)status; UNIX_ONLY(if (iod == io_std_device.out) prin_in_dev_failure = FALSE); if (socketptr->first_read && (CHSET_M != ichset)) /* May have a BOM to defuse */ { if (CHSET_UTF8 != ichset) { /* When the type is UTF16xx, we need to check for a BOM at the beginning of the file. If * found it tells us which of UTF-16BE (default if no BOM) or UTF-16LE mode the data * is being written with. The call to iosocket_snr_utf_prebuffer() above should have made * sure that there were at least two chars available in the buffer if the char is a BOM. */ if (UTF16BE_BOM_LEN <= bytes_read) /* All UTF16xx BOM lengths are the same */ { if (0 == memcmp(buffptr, UTF16BE_BOM, UTF16BE_BOM_LEN)) { if (CHSET_UTF16LE == ichset) { iod->dollar.za = 9; rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_BOMMISMATCH, 4, chset_names[CHSET_UTF16BE].len, chset_names[CHSET_UTF16BE].addr, chset_names[CHSET_UTF16LE].len, chset_names[CHSET_UTF16LE].addr); } else { iod->ichset = ichset = CHSET_UTF16BE; bytes_read -= UTF16BE_BOM_LEN; /* Throw way BOM */ DBGSOCK2((stdout, "socrfl: UTF16BE BOM detected\n")); } } else if (0 == memcmp(buffptr, UTF16LE_BOM, UTF16LE_BOM_LEN)) { if (CHSET_UTF16BE == ichset) { iod->dollar.za = 9; rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_BOMMISMATCH, 4, chset_names[CHSET_UTF16LE].len, chset_names[CHSET_UTF16LE].addr, chset_names[CHSET_UTF16BE].len, chset_names[CHSET_UTF16BE].addr); } else { iod->ichset = ichset = CHSET_UTF16LE; bytes_read -= UTF16BE_BOM_LEN; /* Throw away BOM */ DBGSOCK2((stdout, "socrfl: UTF16LE BOM detected\n")); } } else { /* No BOM specified. If UTF16, default BOM to UTF16BE per Unicode * standard */ if (CHSET_UTF16 == ichset) { DBGSOCK2((stdout, "socrfl: UTF16BE BOM assumed\n")); iod->ichset = ichset = CHSET_UTF16BE; } } } else { /* Insufficient characters to form a BOM so no BOM present. Like above, if in * UTF16 mode, default to UTF16BE per the Unicode standard. */ if (CHSET_UTF16 == ichset) { DBGSOCK2((stdout, "socrfl: UTF16BE BOM assumed\n")); iod->ichset = ichset = CHSET_UTF16BE; } } } else { /* Check for UTF8 BOM. If found, just eliminate it. */ if ((UTF8_BOM_LEN <= bytes_read) && (0 == memcmp(buffptr, UTF8_BOM, UTF8_BOM_LEN))) { bytes_read -= UTF8_BOM_LEN; /* Throw way BOM */ DBGSOCK2((stdout, "socrfl: UTF8 BOM detected/ignored\n")); } } } if (socketptr->first_read) { if ((CHSET_UTF16BE == ichset) || (CHSET_UTF16LE == ichset)) { get_chset_desc(&chset_names[ichset]); if (has_delimiter) iosocket_delim_conv(socketptr, ichset); } socketptr->first_read = FALSE; } if (bytes_read && has_delimiter) { /* Check to see if it is a delimiter */ DBGSOCK((stdout, "socrfl: Searching for delimiter\n")); for (ii = 0; ii < socketptr->n_delimiter; ii++) { if (bytes_read < socketptr->idelimiter[ii].len) continue; if (0 == memcmp(socketptr->idelimiter[ii].addr, stringpool.free + bytes_read - socketptr->idelimiter[ii].len, socketptr->idelimiter[ii].len)) { terminator = TRUE; match_delim = ii; memcpy(iod->dollar.zb, socketptr->idelimiter[ii].addr, MIN(socketptr->idelimiter[ii].len, ESC_LEN - 1)); iod->dollar.zb[MIN(socketptr->idelimiter[ii].len, ESC_LEN - 1)] = '\0'; memcpy(iod->dollar.key, socketptr->idelimiter[ii].addr, MIN(socketptr->idelimiter[ii].len, DD_BUFLEN - 1)); iod->dollar.key[MIN(socketptr->idelimiter[ii].len, DD_BUFLEN - 1)] = '\0'; break; } } DBGSOCK_ONLY2( if (terminator) DBGSOCK((stdout, "socrfl: Delimiter found - match_delim: %d\n", match_delim)); else DBGSOCK((stdout, "socrfl: Delimiter not found\n")); ); } if (!terminator) more_data = TRUE; } else if ((EINTR == errno) && !out_of_time) /* Unrelated timer popped */ { status = 0; continue; } else { real_errno = errno; break; } if (bytes_read > MAX_STRLEN) { iod->dollar.za = 9; rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN); } orig_bytes_read = bytes_read; if (0 != bytes_read) { /* Find n chars read from [buffptr, buffptr + bytes_read) */ DBGSOCK((stdout, "socrfl: Start char scan - c_ptr: 0x"lvaddr" c_top: 0x"lvaddr"\n", buffptr, (buffptr + status))); for (c_ptr = buffptr, c_top = buffptr + status; c_ptr < c_top && chars_read < width; c_ptr += mb_len, chars_read++) { mb_len = 1; /* In case of CHSET_M */ if (!((CHSET_M == ichset) ? 1 : (CHSET_UTF8 == ichset) ? UTF8_VALID(c_ptr, c_top, mb_len) : (CHSET_UTF16BE == ichset) ? UTF16BE_VALID(c_ptr, c_top, mb_len) : UTF16LE_VALID(c_ptr, c_top, mb_len))) { /* This char is not valid unicode but this is only an error if entire char is * in the buffer. Else we ignore it and it is rebuffered further down. * First, we need to find its (real) length as xx_VALID set it to one when it * was determined to be invalid. */ mb_len = (CHSET_M == ichset) ? 0 : (CHSET_UTF8 == ichset) ? UTF8_MBFOLLOW(c_ptr) : (CHSET_UTF16BE == ichset) ? UTF16BE_MBFOLLOW(c_ptr, c_top) : UTF16LE_MBFOLLOW(c_ptr, c_top); mb_len++; /* Account for first byte of char */ if ((0 == mb_len) || ((c_ptr + mb_len) <= c_top)) { /* The entire char is in the buffer.. badchar */ # ifdef UNICODE_SUPPORTED if (CHSET_UTF8 == ichset) { iosocket_readfl_badchar(v, (int)((unsigned char *)c_ptr - stringpool.free), 0, c_ptr, c_top); UTF8_BADCHAR(0, c_ptr, c_top, 0, NULL); } else /* UTF16LE or UTF16BE */ { inv_beg = c_ptr; if ((c_ptr += 2) >= c_top) c_ptr = c_top; iosocket_readfl_badchar(v, (int)((unsigned char *)inv_beg - stringpool.free), (int)(c_ptr - inv_beg), inv_beg, c_top); UTF8_BADCHAR((int)(c_ptr - inv_beg), inv_beg, c_top, chset_names[ichset].len, chset_names[ichset].addr); } # endif } } if ((c_ptr + mb_len) > c_top) /* Verify entire char is in buffer */ break; } DBGSOCK((stdout, "socrfl: End char scan - c_ptr: 0x"lvaddr" c_top: 0x"lvaddr"\n", c_ptr, c_top)); if (c_ptr < c_top) /* Width size READ completed OR partial last char, push back bytes into input buffer */ { iosocket_unsnr(socketptr, c_ptr, c_top - c_ptr); bytes_read -= (int)(c_top - c_ptr); /* We will be re-reading these bytes */ requeue_done = TRUE; /* Force single (full) char read next time through */ DBGSOCK((stdout, "socrfl: Requeue of %d bytes done - adjusted bytes_read: %d\n", (c_top - c_ptr), bytes_read)); } } if (terminator) { assert(0 < bytes_read); bytes_read -= socketptr->idelimiter[match_delim].len; c_ptr -= socketptr->idelimiter[match_delim].len; UNICODE_ONLY(chars_read -= socketptr->idelimiter[match_delim].char_len); NON_UNICODE_ONLY(chars_read = bytes_read); DBGSOCK((stdout, "socrfl: Terminator found - bytes_read reduced by %d bytes to %d\n", socketptr->idelimiter[match_delim].len, bytes_read)); DBGSOCK((stdout, "socrfl: .. c_ptr also reduced to 0x"lvaddr"\n", c_ptr)); } /* If we read as much as we needed or if the buffer was totally full (last char or 3 might be part of an * incomplete character than can never be completed in this buffer) or if variable length, no delim with * chars available and no more data or outofband or have data including a terminator, we are then done. Note * that we are explicitly not handling jobinterrupt outofband here because it is handled above where it needs * to be done to be able to cleanly requeue any input (before delimiter procesing). */ if ((chars_read >= width) || (MAX_STRLEN <= orig_bytes_read) || (vari && !has_delimiter && (0 != chars_read) && !more_data) || ((0 < status) && terminator)) break; if (0 != outofband) { outofband_terminate = TRUE; break; } if (timed) { if (0 < msec_timeout) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (0 > cur_time.at_sec) { out_of_time = TRUE; cancel_timer(timer_id); DBGSOCK((stdout, "socrfl: Out of time detected and set\n")); break; } } else if (!more_data) break; } } if (EINTR == real_errno) status = 0; /* Don't treat a or timeout as an error */ if (timed) { if (0 < msec_timeout) { # ifdef UNIX FCNTL3(socketptr->sd, F_SETFL, flags, fcntl_res); if (fcntl_res < 0) { iod->dollar.za = 9; save_errno = errno; errptr = (char *)STRERROR(errno); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("F_SETFL FOR RESTORING SOCKET OPTIONS"), save_errno, LEN_AND_STR(errptr)); } # endif if (out_of_time) { ret = FALSE; DBGSOCK((stdout, "socrfl: Out of time to be returned (1)\n")); } else cancel_timer(timer_id); } else if ((chars_read < width) && !(has_delimiter && terminator)) { ret = FALSE; DBGSOCK((stdout, "socrfl: Out of time to be returned (2)\n")); } } /* If we terminated due to outofband, set up restart info. We may or may not restart (any outofband is capable of * restart) but set it up for at least the more common reasons (^C and job interrupt). * * Some restart info is kept in our iodesc block, but the buffer address information is kept in an mv_stent so if * the stack is garbage collected during the interrupt we don't lose track of where our stuff is saved away. */ if (outofband_terminate) { DBGSOCK((stdout, "socrfl: outofband interrupt received (%d) -- queueing mv_stent for read intr\n", outofband)); PUSH_MV_STENT(MVST_ZINTDEV); mv_chain->mv_st_cont.mvs_zintdev.io_ptr = iod; mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = TRUE; mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr = (char *)stringpool.free; mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.len = bytes_read; sockintr->who_saved = sockwhich_readfl; if ((0 < msec_timeout) && (NO_M_TIMEOUT != msec_timeout)) { sockintr->end_time = end_time; sockintr->end_time_valid = TRUE; cancel_timer(timer_id); /* Worry about timer if/when we come back */ } sockintr->max_bufflen = max_bufflen; sockintr->bytes_read = bytes_read; sockintr->chars_read = chars_read; dsocketptr->mupintr = TRUE; stringpool.free += bytes_read; /* Don't step on our parade in the interrupt */ socketus_interruptus++; DBGSOCK((stdout, "socrfl: .. mv_stent: bytes_read: %d chars_read: %d max_bufflen: %d " "interrupts: %d buffer_start: 0x"lvaddr"\n", bytes_read, chars_read, max_bufflen, socketus_interruptus, stringpool.free)); DBGSOCK_ONLY(if (sockintr->end_time_valid) DBGSOCK((stdout, "socrfl: .. endtime: %d/%d timeout: %d " "msec_timeout: %d\n", end_time.at_sec, end_time.at_usec, timeout, msec_timeout))); TRCTBL_ENTRY(SOCKRFL_OUTOFBAND, bytes_read, (INTPTR_T)chars_read, stringpool.free, NULL); /* BYPASSOK */ outofband_action(FALSE); GTMASSERT; /* Should *never* return from outofband_action */ return FALSE; /* For the compiler.. */ } if (0 < chars_read) { /* There's something to return. Note we do not assert anything using c_ptr as it is possible in a restarted * read with nearly immediate timeout to bypass setting c_ptr so its value is not dependable at this point. */ assert(0 <= bytes_read); v->str.len = bytes_read; v->str.addr = (char *)stringpool.free; UNICODE_ONLY(v->str.char_len = chars_read); DBGSOCK((stdout, "socrfl: String to return bytelen: %d charlen: %d iod-width: %d wrap: %d\n", v->str.len, chars_read, iod->width, iod->wrap)); DBGSOCK((stdout, "socrfl: x: %d y: %d\n", iod->dollar.x, iod->dollar.y)); if (((iod->dollar.x += chars_read) >= iod->width) && iod->wrap) /* Note increment/assignment */ { iod->dollar.y += (iod->dollar.x / iod->width); if (0 != iod->length) iod->dollar.y %= iod->length; iod->dollar.x %= iod->width; } if ((CHSET_M != ichset) && (CHSET_UTF8 != ichset)) { DBGSOCK((stdout, "socrfl: Converting UTF16xx data back to UTF8 for internal use\n")); v->str.len = gtm_conv(chset_desc[ichset], chset_desc[CHSET_UTF8], &v->str, NULL, NULL); v->str.addr = (char *)stringpool.free; stringpool.free += v->str.len; } } else { v->str.len = 0; v->str.addr = iod->dollar.key; } if (status >= 0) { /* No real problems */ iod->dollar.zeof = FALSE; iod->dollar.za = 0; memcpy(iod->dollar.device, "0", SIZEOF("0")); } else { /* There's a significant problem */ DBGSOCK((stdout, "socrfl: Error handling triggered - status: %d\n", status)); if (0 == chars_read) iod->dollar.x = 0; iod->dollar.za = 9; len = SIZEOF(ONE_COMMA) - 1; memcpy(iod->dollar.device, ONE_COMMA, len); errptr = (char *)STRERROR(real_errno); errlen = STRLEN(errptr); memcpy(&iod->dollar.device[len], errptr, errlen + 1); /* + 1 for null */ # ifdef UNIX if (io_curr_device.in == io_std_device.in) { if (!prin_in_dev_failure) prin_in_dev_failure = TRUE; else { send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOPRINCIO); stop_image_no_core(); } } # endif if (iod->dollar.zeof || -1 == status || 0 < iod->error_handler.len) { iod->dollar.zeof = TRUE; if (socketptr->ioerror) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_IOEOF, 0, ERR_TEXT, 2, errlen, errptr); } else iod->dollar.zeof = TRUE; } DBGSOCK_ONLY( if (!ret && out_of_time) { DBGSOCK((stdout, "socrfl: Returning from read due to timeout\n")); } else { DBGSOCK((stdout, "socrfl: Returning from read with success indicator set to %d\n", ret)); } ); return (ret); } fis-gtm-V6.0-003/sr_port/iosocket_snr.c0000644000032200000250000003516612201176157016715 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_snr.c * description: * -- takes care of the buffering of the recv for the socket device (and possible tcp device) * parameters: * -- socketptr pointer to a socket device, where we get socket descriptor, buffer and offset in buffer * -- buffer pointer to the buffer where to return stuff * -- maxlength maximum number of bytes to get * -- flags flags to be passed to recv() * -- time_for_read pointer to the timeout structure used by select() * -- extra_status reports either a timeout or a lost-of-connection * return: * -- got some stuff to return return number of bytes received * -- got nothing and timed out return 0 * -- loss-of-connection return -2 * -- error condition return -1, with errno set * side note: * -- use our own buffer if the requested size is smaller than our own buffer size * -- use the caller's buffer if the requested size is bigger than our own buffer * control flow: * -- if we already have some leftover, use it and figure out how much is still needed * -- if there is still need to read, figure out whether to use our buffer or the passed-in buffer * -- select so that this operation is timed * -- if select returns positive, recv, otherwise, return timeout * -- if recv gets nothing, return lost-of-connection * -- if the device buffer is used, move it over to the return buffer and update the device buffer pointer */ #include "mdef.h" #include #include #include "gtm_stdio.h" #include "gtm_time.h" #include "gtm_inet.h" #include "gtm_string.h" #ifdef UNIX #include "gtm_fcntl.h" #include "eintr_wrappers.h" static int fcntl_res; #ifdef DEBUG #include /* for gettimeofday */ #endif #ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT #include #endif #endif #include "gt_timer.h" #include "io.h" #include "iotimer.h" #include "iotcpdef.h" #include "iotcproutine.h" #include "stringpool.h" #include "iosocketdef.h" #include "min_max.h" #include "gtm_utf8.h" #include "outofband.h" /* MAX_SNR_IO is for read loop in iosocket_snr_utf_prebuffer(). It is possible for a series of interrupts (one * from each active region) to interfere with this read so be generous here. */ #define MAX_SNR_IO 50 #ifdef DEBUG /* Hold gettimeofday before and after select to debug AIX spin */ static struct timeval tvbefore, tvafter; #endif GBLREF io_pair io_curr_device; GBLREF bool out_of_time; GBLREF spdesc stringpool; GBLREF tcp_library_struct tcp_routines; GBLREF int4 outofband; /* Local routine we aren't making static due to increased debugging difficult static routines make */ ssize_t iosocket_snr_io(socket_struct *socketptr, void *buffer, size_t maxlength, int flags, ABS_TIME *time_for_read); /* Select aNd Receive */ ssize_t iosocket_snr(socket_struct *socketptr, void *buffer, size_t maxlength, int flags, ABS_TIME *time_for_read) { int status; ssize_t bytesread, recvsize; void *recvbuff; DBGSOCK((stdout, "socsnr: socketptr: 0x"lvaddr" buffer: 0x"lvaddr" maxlength: %d, flags: %d\n", socketptr, buffer, maxlength, flags)); /* Use leftover from the previous read, if there is any */ assert(0 < maxlength); if (0 < socketptr->buffered_length) { DBGSOCK2((stdout, "socsnr: read from buffer - buffered_length: %d\n", socketptr->buffered_length)); bytesread = MIN(socketptr->buffered_length, maxlength); memcpy(buffer, (void *)(socketptr->buffer + socketptr->buffered_offset), bytesread); socketptr->buffered_offset += bytesread; socketptr->buffered_length -= bytesread; DBGSOCK2((stdout, "socsnr: after buffer read - buffered_offset: %d buffered_length: %d\n", socketptr->buffered_offset, socketptr->buffered_length)); return bytesread; } /* Decide on which buffer to use and the size of the recv */ if (socketptr->buffer_size > maxlength) { recvbuff = socketptr->buffer; recvsize = socketptr->buffer_size; } else { recvbuff = buffer; recvsize = maxlength; } VMS_ONLY(recvsize = MIN(recvsize, VMS_MAX_TCP_IO_SIZE)); DBGSOCK2((stdout, "socsnr: recvsize set to %d\n", recvsize)); /* Select and recv */ assert(0 == socketptr->buffered_length); socketptr->buffered_length = 0; bytesread = (int)iosocket_snr_io(socketptr, recvbuff, recvsize, flags, time_for_read); DBGSOCK2((stdout, "socsnr: bytes read from recv: %d timeout: %d\n", bytesread, out_of_time)); if (0 < bytesread) { /* Got something this time */ if (recvbuff == socketptr->buffer) { if (bytesread <= maxlength) memcpy(buffer, socketptr->buffer, bytesread); else { /* Got some stuff for future recv */ memcpy(buffer, socketptr->buffer, maxlength); socketptr->buffered_length = bytesread - maxlength; bytesread = socketptr->buffered_offset = maxlength; DBGSOCK2((stdout, "socsnr: Buffer updated post read - buffered_offset: %d " "buffered_length: %d\n", socketptr->buffered_offset, socketptr->buffered_length)); } } } return bytesread; } /* Do the IO dirty work. Note the return value can be from either select() or recv(). * This would be a static routine but that just makes it harder to debug. */ ssize_t iosocket_snr_io(socket_struct *socketptr, void *buffer, size_t maxlength, int flags, ABS_TIME *time_for_read) { int status, bytesread, real_errno; fd_set tcp_fd; ABS_TIME lcl_time_for_read; # ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT long poll_timeout; unsigned long poll_nfds; struct pollfd poll_fdlist[1]; # endif DBGSOCK2((stdout, "socsnrio: Socket read request - socketptr: 0x"lvaddr" buffer: 0x"lvaddr" maxlength: %d flags: %d ", socketptr, buffer, maxlength, flags)); DBGSOCK2((stdout, "time_for_read->at_sec: %d usec: %d\n", time_for_read->at_sec, time_for_read->at_usec)); DEBUG_ONLY(gettimeofday(&tvbefore, NULL);) #ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT FD_ZERO(&tcp_fd); FD_SET(socketptr->sd, &tcp_fd); assert(0 != FD_ISSET(socketptr->sd, &tcp_fd)); lcl_time_for_read = *time_for_read; status = tcp_routines.aa_select(socketptr->sd + 1, (void *)(&tcp_fd), (void *)0, (void *)0, &lcl_time_for_read); #else poll_fdlist[0].fd = socketptr->sd; poll_fdlist[0].events = POLLIN; poll_nfds = 1; poll_timeout = time_for_read->at_usec / 1000; /* convert to millisecs */ status = poll(&poll_fdlist[0], poll_nfds, poll_timeout); #endif real_errno = errno; DEBUG_ONLY(gettimeofday(&tvafter, NULL);) DBGSOCK2((stdout, "socsnrio: Select return code: %d :: errno: %d\n", status, real_errno)); if (0 < status) { bytesread = tcp_routines.aa_recv(socketptr->sd, buffer, maxlength, flags); real_errno = errno; socketptr->last_recv_errno = (-1 != status) ? 0 : real_errno; /* Save status of last recv for dbging purposes */ DBGSOCK2((stdout, "socsnrio: aa_recv return code: %d :: errno: %d\n", bytesread, errno)); if ((0 == bytesread) || ((-1 == bytesread) && ((ECONNRESET == real_errno) || (EPIPE == real_errno) || (EINVAL == real_errno)))) { /* Lost connection */ if (0 == bytesread) errno = ECONNRESET; return (ssize_t)(-2); } DBGSOCK_ONLY2(errno = real_errno); return bytesread; } DBGSOCK_ONLY2(errno = real_errno); return (ssize_t)status; } /* When scanning for delimiters, we have to make sure that the next read can pull in at least one full utf char. * Failure to do this means that if a partial utf8 char is read, it will be rebuffered, reread, rebuffered, forever. * A return code of zero indicates a timeout error occured. A negative return code indicates an IO error of some sort. * A positive return code is the length in bytes of the next unicode char in the buffer. */ ssize_t iosocket_snr_utf_prebuffer(io_desc *iod, socket_struct *socketptr, int flags, ABS_TIME *time_for_read, boolean_t wait_for_input) { int mblen, bytesread, real_errno; ssize_t readlen; char *readptr; assert(CHSET_M != iod->ichset); DBGSOCK((stdout, "socsnrupb: Enter prebuffer: buffered_length: %d wait_for_input: %d\n", socketptr->buffered_length, wait_for_input)); /* See if there is *anything* in the buffer */ if (0 == socketptr->buffered_length) { /* Buffer is empty, read at least one char into it so we can check how many we need */ do { bytesread = (int)iosocket_snr_io(socketptr, socketptr->buffer, socketptr->buffer_size, flags, time_for_read); DBGSOCK_ONLY2(real_errno = errno); DBGSOCK2((stdout, "socsnrupb: Buffer empty - bytes read: %d errno: %d\n", bytesread, real_errno)); DBGSOCK_ONLY2(errno = real_errno); } while ((((-1 == bytesread) && (EINTR == errno)) || (0 == bytesread && wait_for_input)) && !out_of_time && (0 == outofband)); if (out_of_time || (0 != outofband)) { DBGSOCK_ONLY(if (out_of_time) { DBGSOCK((stdout, "socsnrupb: Returning due to timeout\n")); } else { DBGSOCK((stdout, "socsnrupb: Returning due to outofband\n")); } ); if (0 < bytesread) { /* If we read anything, be sure to consider it buffered */ socketptr->buffered_length = bytesread; socketptr->buffered_offset = 0; } return 0; } if (0 >= bytesread) { DBGSOCK_ONLY2(real_errno = errno); DBGSOCK2((stdout, "socsnrupb: Returning due to error code %d errno: %d\n", bytesread, real_errno)); DBGSOCK_ONLY2(errno = real_errno); return bytesread; } socketptr->buffered_length = bytesread; socketptr->buffered_offset = 0; } /* Compute number of bytes we need for the first char in the buffer */ readptr = socketptr->buffer + socketptr->buffered_offset; switch(iod->ichset) { case CHSET_UTF8: mblen = UTF8_MBFOLLOW(readptr); if (0 > mblen) mblen = 0; /* Invalid char, just assume one char needed */ break; case CHSET_UTF16BE: mblen = UTF16BE_MBFOLLOW(readptr, readptr + socketptr->buffered_length); if (0 > mblen) mblen = 1; /* If buffer is too small we will get -1 here. Assume need 2 chars */ break; case CHSET_UTF16LE: mblen = UTF16LE_MBFOLLOW(readptr, readptr + socketptr->buffered_length); if (0 > mblen) mblen = 1; /* If buffer is too small we will get -1 here. Assume need 2 chars */ break; case CHSET_UTF16: /* Special case as we don't know which mode we are in. This should only be used when * checking for BOMs. Check if first char is 0xFF or 0xFE. If it is, return 1 as our * (follow) length. If neither, assume UTF16BE (default UTF16 codeset) and return the * length it gives. */ if ((0xFF == (unsigned char)*readptr) || (0xFE == (unsigned char)*readptr)) mblen = 1; else { mblen = UTF16BE_MBFOLLOW(readptr, readptr + socketptr->buffered_length); if (0 > mblen) mblen = 1; /* If buffer is too small we will get -1 here. Assume need 2 chars */ } break; default: GTMASSERT; } mblen++; /* Include first char we were looking at in the required byte length */ DBGSOCK2((stdout, "socsnrupb: Length of char: %d\n", mblen)); if (socketptr->buffered_length < mblen) { /* Still insufficient chars in the buffer for our utf character. Read some more in. */ if ((socketptr->buffered_offset + mblen) > socketptr->buffer_size) { /* Our char won't fit in the buffer. This can only occur if the read point is * right at the end of the buffer since the minimum buffer size is 32K. Solution * is to slide the part of the char that we have down to the beginning of the * buffer so we have plenty of room. Since this is at most 3 bytes, this is not * a major performance concern. */ DBGSOCK2((stdout, "socsnrupb: Char won't fit in buffer, slide it down\n")); assert(SIZEOF(int) > socketptr->buffered_length); assert(socketptr->buffered_offset > socketptr->buffered_length); /* Assert no overlap */ memcpy(socketptr->buffer, (socketptr->buffer + socketptr->buffered_offset), socketptr->buffered_length); socketptr->buffered_offset = 0; } while (socketptr->buffered_length < mblen) { DBGSOCK2((stdout, "socsnrupb: Top of read loop for char - buffered_length: %d\n", socketptr->buffered_length)); readptr = socketptr->buffer + socketptr->buffered_offset + socketptr->buffered_length; readlen = socketptr->buffer_size - socketptr->buffered_offset - socketptr->buffered_length; assert(0 < readlen); bytesread = (int)iosocket_snr_io(socketptr, readptr, readlen, flags, time_for_read); DBGSOCK2((stdout, "socsnrupb: Read %d chars\n", bytesread)); if (0 > bytesread) { /* Some error occurred. Check for restartable condition. */ if (EINTR == errno) if (!out_of_time) continue; else return 0; /* timeout indicator */ return bytesread; } if (out_of_time) return 0; socketptr->buffered_length += bytesread; } } DBGSOCK((stdout, "socsnrupb: Returning char length %d -- buffered_length: %d\n", mblen, socketptr->buffered_length)); return mblen; } /* Place len bytes pointed by buffer back into socketptr's internal buffer * * Side effect: suppose the last snr was with a length > internal buffer size, we would not have used the internal buffer. For * that case, unsnr might move data not in the internal buffer into the internal buffer and also might result in buffer * expansion */ void iosocket_unsnr(socket_struct *socketptr, unsigned char *buffer, size_t len) { char *new_buff; DBGSOCK((stdout, "iosunsnr: ** Requeueing %d bytes\n", len)); if ((socketptr->buffered_length + len) <= socketptr->buffer_size) { if (0 < socketptr->buffered_length) { if (socketptr->buffered_offset < len) { memmove(socketptr->buffer + len, socketptr->buffer + socketptr->buffered_offset, socketptr->buffered_length); memmove(socketptr->buffer, buffer, len); } else { memmove(socketptr->buffer, buffer, len); memmove(socketptr->buffer + len, socketptr->buffer + socketptr->buffered_offset, socketptr->buffered_length); } } else memmove(socketptr->buffer, buffer, len); } else { new_buff = malloc(socketptr->buffered_length + len); memcpy(new_buff, buffer, len); if (0 < socketptr->buffered_length) memcpy(new_buff + len, socketptr->buffer + socketptr->buffered_offset, socketptr->buffered_length); free(socketptr->buffer); socketptr->buffer = new_buff; } socketptr->buffered_offset = 0; socketptr->buffered_length += len; return; } fis-gtm-V6.0-003/sr_port/iosocket_switch.c0000644000032200000250000000367112201176157017410 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_switch.c */ #include "mdef.h" #include "gtm_socket.h" #include "gtm_inet.h" #include "io.h" #include "iosp.h" #include "io_params.h" #include "iotcpdef.h" #include "gt_timer.h" #include "iosocketdef.h" GBLREF int4 gtm_max_sockets; boolean_t iosocket_switch(char *handle, int handle_len, d_socket_struct *from, d_socket_struct *to) { int4 index, ii; socket_struct *socketptr; error_def(ERR_SOCKNOTFND); error_def(ERR_SOCKETEXIST); error_def(ERR_SOCKMAX); if ((NULL == from) || (0 > (index = iosocket_handle(handle, &handle_len, FALSE, from)))) { rts_error(VARLSTCNT(4) ERR_SOCKNOTFND, 2, handle_len, handle); return FALSE; } else { /* attach the socket to "to" and set it to current */ assert(NULL != to); if (0 <= iosocket_handle(handle, &handle_len, FALSE, to)) { rts_error(VARLSTCNT(4) ERR_SOCKETEXIST, 2, handle_len, handle); return FALSE; } if (gtm_max_sockets <= to->n_socket) { rts_error(VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets); return FALSE; } socketptr = from->socket[index]; socketptr->dev = to; to->socket[to->n_socket++] = socketptr; to->current_socket = to->n_socket - 1; /* detach it from "from" */ if (from->current_socket >= index) from->current_socket--; for(ii = index; ii < from->n_socket - 1; ii++) { from->socket[ii] = from->socket[ii + 1]; } from->n_socket--; from->socket[from->n_socket] = NULL; } return TRUE; } fis-gtm-V6.0-003/sr_port/iosocket_use.c0000644000032200000250000005254412201176157016706 0ustar librarygtc/**************************************************************** * * * Copyright 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_use.c */ #include "mdef.h" #include "gtm_socket.h" #include "gtm_unistd.h" #include "gtm_iconv.h" #include "gtm_stdio.h" #include "gtm_string.h" #include #include "gtm_inet.h" #include "copy.h" #include "io.h" #include "io_params.h" #include "iotimer.h" #include "iotcpdef.h" #include "iotcproutine.h" #include "gt_timer.h" #include "iosocketdef.h" #include "nametabtyp.h" #include "namelook.h" #include "stringpool.h" #include "gtm_conv.h" GBLREF io_pair io_curr_device; GBLREF io_pair io_std_device; GBLREF io_desc *active_device; GBLREF tcp_library_struct tcp_routines; GBLREF d_socket_struct *socket_pool; GBLREF boolean_t gtm_utf8_mode; GBLREF spdesc stringpool; GBLREF UConverter *chset_desc[]; GBLREF int4 gtm_max_sockets; GBLREF d_socket_struct *newdsocket; GBLREF boolean_t dollar_zininterrupt; LITREF nametabent filter_names[]; LITREF unsigned char filter_index[27]; LITREF unsigned char io_params_size[]; error_def(ERR_ABNCOMPTINC); error_def(ERR_ACOMPTBINC); error_def(ERR_ADDRTOOLONG); error_def(ERR_ANCOMPTINC); error_def(ERR_CURRSOCKOFR); error_def(ERR_DELIMSIZNA); error_def(ERR_DELIMWIDTH); error_def(ERR_DEVPARMNEG); error_def(ERR_ILLESOCKBFSIZE); error_def(ERR_MRTMAXEXCEEDED); error_def(ERR_SETSOCKOPTERR); error_def(ERR_SOCKBFNOTEMPTY); error_def(ERR_SOCKNOTFND); error_def(ERR_SOCKMAX); error_def(ERR_TEXT); error_def(ERR_TTINVFILTER); error_def(ERR_ZFF2MANY); error_def(ERR_ZINTRECURSEIO); void iosocket_use(io_desc *iod, mval *pp) { unsigned char ch, len; int handled_len, handlea_len, handles_len; int4 length, width, new_len; d_socket_struct *dsocketptr; socket_struct *socketptr, newsocket; char handlea[MAX_HANDLE_LEN], handles[MAX_HANDLE_LEN], handled[MAX_HANDLE_LEN]; char addr[SA_MAXLITLEN], *errptr, sockaddr[SA_MAXLITLEN], temp_addr[SA_MAXLITLEN], ioerror; unsigned char delimiter_buffer[MAX_N_DELIMITER * (MAX_DELIM_LEN + 1)]; unsigned char zff_buffer[MAX_ZFF_LEN]; boolean_t attach_specified = FALSE, detach_specified = FALSE, connect_specified = FALSE, ioerror_specified = FALSE, listen_specified = FALSE, socket_specified = FALSE, delay_specified = FALSE, nodelay_specified = FALSE, bfsize_specified = FALSE, ibfsize_specified = FALSE, moreread_specified = FALSE, create_new_socket; int4 index, n_specified, zff_len, delimiter_len, moreread_timeout; int fil_type, nodelay, p_offset = 0; uint4 bfsize = DEFAULT_SOCKET_BUFFER_SIZE, ibfsize; char *tab; int save_errno; size_t d_socket_struct_len; mstr lcl_zff; assert(iod->state == dev_open); assert(iod->type == gtmsocket); dsocketptr = (d_socket_struct *)(iod->dev_sp); /* ---------------------------------- parse the command line ------------------------------------ */ n_specified = 0; zff_len = -1; /* indicates neither ZFF nor ZNOFF specified */ delimiter_len = -1; /* indicates neither DELIM nor NODELIM specified */ /* A read or wait was interrupted for this device. Allow only parmless use in $zinterrupt code for and interrupted device. */ if (iop_eol != *(pp->str.addr + p_offset)) { /* Parameters were specified */ if (dsocketptr->mupintr) { /* And if we are in $zinterrupt code this is not allowed */ if (dollar_zininterrupt) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); /* We are not in $zinterrupt code and this device was not resumed properly so clear its restartability. */ io_find_mvstent(iod, TRUE); dsocketptr->mupintr = FALSE; } } else if (dsocketptr->mupintr && !dollar_zininterrupt) { /* The interrupted read was not properly resumed so clear it now */ dsocketptr->mupintr = FALSE; dsocketptr->sock_save_state.who_saved = sockwhich_invalid; io_find_mvstent(iod, TRUE); } while (iop_eol != (ch = *(pp->str.addr + p_offset++))) { assert((params)ch < (params)n_iops); switch (ch) { case iop_exception: iod->error_handler.len = *(pp->str.addr + p_offset); iod->error_handler.addr = (char *)(pp->str.addr + p_offset + 1); s2pool(&iod->error_handler); break; case iop_filter: len = *(pp->str.addr + p_offset); tab = pp->str.addr + p_offset + 1; if ((fil_type = namelook(filter_index, filter_names, tab, len)) < 0) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TTINVFILTER); return; } switch (fil_type) { case 0: iod->write_filter |= CHAR_FILTER; break; case 1: iod->write_filter |= ESC1; break; case 2: iod->write_filter &= ~CHAR_FILTER; break; case 3: iod->write_filter &= ~ESC1; break; } break; case iop_nofilter: iod->write_filter = 0; break; case iop_attach: n_specified++; attach_specified = TRUE; handlea_len = (int)(*(pp->str.addr + p_offset)); memcpy(handlea, (char *)(pp->str.addr + p_offset + 1), handlea_len); break; case iop_detach: n_specified++; detach_specified = TRUE; handled_len = (int)(*(pp->str.addr + p_offset)); memcpy(handled, (char *)(pp->str.addr + p_offset + 1), handled_len); break; case iop_connect: n_specified++; connect_specified = TRUE; len = *(pp->str.addr + p_offset); if (len < USR_SA_MAXLITLEN) { memcpy(sockaddr, (char *)(pp->str.addr + p_offset + 1), len); sockaddr[len] = '\0'; } else rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ADDRTOOLONG, 4, len, pp->str.addr + p_offset + 1, len, USR_SA_MAXLITLEN); break; case iop_delimiter: n_specified++; delimiter_len = (int4)(unsigned char)*(pp->str.addr + p_offset); if (((MAX_DELIM_LEN + 1) * MAX_N_DELIMITER) >= delimiter_len) memcpy(delimiter_buffer, (pp->str.addr + p_offset + 1), delimiter_len); else rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DELIMSIZNA); break; case iop_nodelimiter: delimiter_len = 0; break; case iop_zdelay: delay_specified = TRUE; break; case iop_znodelay: nodelay_specified = TRUE; break; case iop_zbfsize: bfsize_specified = TRUE; GET_ULONG(bfsize, pp->str.addr + p_offset); if ((0 == bfsize) || (MAX_SOCKET_BUFFER_SIZE < bfsize)) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, bfsize); break; case iop_zibfsize: ibfsize_specified = TRUE; GET_ULONG(ibfsize, pp->str.addr + p_offset); if ((0 == ibfsize) || (MAX_INTERNAL_SOCBUF_SIZE < ibfsize)) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, ibfsize); break; case iop_ioerror: n_specified++; ioerror_specified = TRUE; ioerror = *(char *)(pp->str.addr + p_offset + 1); break; case iop_zlisten: n_specified++; listen_specified = TRUE; len = *(pp->str.addr + p_offset); if (len < USR_SA_MAXLITLEN) { memcpy(sockaddr, (char *)(pp->str.addr + p_offset + 1), len); sockaddr[len] = '\0'; } else rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ADDRTOOLONG, 4, len, pp->str.addr + p_offset + 1, len, USR_SA_MAXLITLEN); break; case iop_socket: n_specified++; socket_specified = TRUE; handles_len = (int)(*(pp->str.addr + p_offset)); memcpy(handles, (char *)(pp->str.addr + p_offset + 1), handles_len); break; case iop_ipchset: #if defined(KEEP_zOS_EBCDIC) || defined(VMS) if ((iconv_t)0 != iod->input_conv_cd) ICONV_CLOSE_CD(iod->input_conv_cd); SET_CODE_SET(iod->in_code_set, (char *)(pp->str.addr + p_offset + 1)); if (DEFAULT_CODE_SET != iod->in_code_set) ICONV_OPEN_CD(iod->input_conv_cd, INSIDE_CH_SET, (char *)(pp->str.addr + p_offset + 1)); #endif break; case iop_opchset: #if defined(KEEP_zOS_EBCDIC) || defined(VMS) if ((iconv_t)0 != iod->output_conv_cd) ICONV_CLOSE_CD(iod->output_conv_cd); SET_CODE_SET(iod->out_code_set, (char *)(pp->str.addr + p_offset + 1)); if (DEFAULT_CODE_SET != iod->out_code_set) ICONV_OPEN_CD(iod->output_conv_cd, (char *)(pp->str.addr + p_offset + 1), INSIDE_CH_SET); #endif break; case iop_zff: if (MAX_ZFF_LEN >= (zff_len = (int4)(unsigned char)*(pp->str.addr + p_offset))) memcpy(zff_buffer, (char *)(pp->str.addr + p_offset + 1), zff_len); else rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZFF2MANY, 2, zff_len, MAX_ZFF_LEN); break; case iop_znoff: zff_len = 0; break; case iop_length: GET_LONG(length, pp->str.addr + p_offset); if (length < 0) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG); iod->length = length; break; case iop_width: /* SOCKET WIDTH is handled the same way as TERMINAL WIDTH */ GET_LONG(width, pp->str.addr + p_offset); if (width < 0) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG); if (0 == width) { iod->width = TCPDEF_WIDTH; iod->wrap = FALSE; } else { iod->width = width; iod->wrap = TRUE; } break; case iop_wrap: iod->wrap = TRUE; break; case iop_nowrap: iod->wrap = FALSE; break; case iop_morereadtime: /* Time in milliseconds socket read will wait for more data before returning */ GET_LONG(moreread_timeout, pp->str.addr + p_offset); if (-1 == moreread_timeout) moreread_timeout = DEFAULT_MOREREAD_TIMEOUT; else if (-1 > moreread_timeout) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG); else if (MAX_MOREREAD_TIMEOUT < moreread_timeout) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MRTMAXEXCEEDED, 1, MAX_MOREREAD_TIMEOUT); moreread_specified = TRUE; break; default: /* ignore deviceparm */ break; } p_offset += ((io_params_size[ch] == IOP_VAR_SIZE) ? (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]); } /* ------ return immediately if no flag, worth a check because it is mostly true ------------ */ if (1 == p_offset) return; /* ------------------------------ compatibility verification -------------------------------- */ if ((socket_specified) && ((n_specified > 2) || ((2 == n_specified) && (0 >= delimiter_len)))) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ACOMPTBINC, 6, LEN_AND_LIT("SOCKET"), LEN_AND_LIT("DELIMITER"), LEN_AND_LIT("USE")); return; } if (connect_specified && listen_specified) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("CONNECT"), LEN_AND_LIT("ZLISTEN"), LEN_AND_LIT("USE")); return; } if (delay_specified && nodelay_specified) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("DELAY"), LEN_AND_LIT("NODELAY"), LEN_AND_LIT("OPEN")); return; } /* ------------------ make a local copy of device structure to play with -------------------- */ d_socket_struct_len = SIZEOF(d_socket_struct) + (SIZEOF(socket_struct) * (gtm_max_sockets - 1)); memcpy(newdsocket, dsocketptr, d_socket_struct_len); /* --------------- handle the two special cases attach/detach first ------------------------- */ if (detach_specified) { if (1 < n_specified) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ANCOMPTINC, 4, LEN_AND_LIT("DETACH"), LEN_AND_LIT("USE")); return; } if (NULL == socket_pool) iosocket_poolinit(); iosocket_switch(handled, handled_len, newdsocket, socket_pool); memcpy(dsocketptr, newdsocket, d_socket_struct_len); if (0 > dsocketptr->current_socket) { io_curr_device.in = io_std_device.in; io_curr_device.out = io_std_device.out; } return; /* detach can only be specified by itself */ } if (attach_specified) { /* NOTE: A socket could be moved from one device to another using DETACH/ATTACH. A socket does not carry I[O]CHSET with * it while being moved. Such a socket will use the I[O]CHSET of the device it is ATTACHed to. If there is input still * buffered, this may cause unintentional consequences in the application if I[O]CHSET changes. GT.M does not detect * (or report) a change in I[O]CHSET due to DETACH/ATTACH. */ if (1 < n_specified) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ANCOMPTINC, 4, LEN_AND_LIT("ATTACH"), LEN_AND_LIT("USE")); return; } if (NULL == socket_pool) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKNOTFND, 2, handlea_len, handlea); return; } iosocket_switch(handlea, handlea_len, socket_pool, newdsocket); memcpy(dsocketptr, newdsocket, d_socket_struct_len); return; /* attach can only be specified by itself */ } /* ------------ create/identify the socket to work on and make a local copy ----------------- */ if (create_new_socket = (listen_specified || connect_specified)) /* real "=" */ { /* allocate the structure for a new socket */ if (NULL == (socketptr = iosocket_create(sockaddr, bfsize, -1))) return; /* give the new socket a handle */ iosocket_handle(handles, &handles_len, TRUE, dsocketptr); socketptr->handle_len = handles_len; memcpy(socketptr->handle, handles, handles_len); socketptr->dev = newdsocket; /* use newdsocket temporarily for the sake of bind/connect */ } else { if (socket_specified) { /* use the socket flag to identify which socket to apply changes */ if (0 > (index = iosocket_handle(handles, &handles_len, FALSE, newdsocket))) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKNOTFND, 2, handles_len, handles); return; } newdsocket->current_socket = index; socketptr = newdsocket->socket[index]; } else { socketptr = newdsocket->socket[newdsocket->current_socket]; if (newdsocket->n_socket <= newdsocket->current_socket) { assert(FALSE); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, newdsocket->current_socket, newdsocket->n_socket); return; } } socketptr->temp_sd = FD_INVALID; } newsocket = *socketptr; /* ---------------------- apply changes to the local copy of the socket --------------------- */ if (0 <= delimiter_len) { iosocket_delimiter(delimiter_buffer, delimiter_len, &newsocket, (0 == delimiter_len)); /* The delimiter has changed. The iosocket_readfl/write routine won't notice so we have to do the UTF16xx conversion since we changed it. */ DBGSOCK2((stdout, "socuse: Delimiter(s) replaced - num delims: %d delimiter_len: %d ichset: %d ochset: %d\n", newsocket.n_delimiter, delimiter_len, iod->ichset, iod->ochset)); if (0 < delimiter_len) { if (!newsocket.first_read && (CHSET_UTF16BE == iod->ichset || CHSET_UTF16LE == iod->ichset)) { /* We have been reading with this socket so convert this new delimiter set */ DBGSOCK2((stdout, "socuse: Converting new delimiters for input\n")); iosocket_delim_conv(&newsocket, iod->ichset); } if (!newsocket.first_write && (CHSET_UTF16BE == iod->ochset || CHSET_UTF16LE == iod->ochset)) { /* We have been writing with this socket so convert the new default output delimiter */ DBGSOCK2((stdout, "socuse: Converting new delimiters for output\n")); if (newsocket.first_read || (CHSET_UTF16BE != iod->ichset && CHSET_UTF16LE != iod->ichset)) { /* Need to do conversion as iosocket_delim_conv above didn't do it for us */ DBGSOCK2((stdout, "socuse: running convert for write since input didn't do it\n")); new_len = gtm_conv(chset_desc[CHSET_UTF8], chset_desc[iod->ochset], &newsocket.delimiter[0], NULL, NULL); if (MAX_DELIM_LEN < new_len) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DELIMSIZNA); return; } } else { DBGSOCK2((stdout, "socuse: using previous length from read conversion\n")); new_len = newsocket.idelimiter[0].len; } newsocket.odelimiter0.len = new_len; UNICODE_ONLY(newsocket.odelimiter0.char_len = newsocket.delimiter[0].char_len); newsocket.odelimiter0.addr = malloc(new_len); memcpy(newsocket.odelimiter0.addr, (newsocket.first_read ? (char *)stringpool.free : newsocket.idelimiter[0].addr), new_len); } } } if (iod->wrap && 0 != newsocket.n_delimiter && iod->width < newsocket.delimiter[0].len) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DELIMWIDTH, 2, iod->width, newsocket.delimiter[0].len); if (0 <= zff_len && /* ZFF or ZNOFF specified */ 0 < (newsocket.zff.len = zff_len)) /* assign the new ZFF len, might be 0 from ZNOFF, or ZFF="" */ { /* ZFF="non-zero-len-string" specified */ if (CHSET_UTF16BE == iod->ochset || CHSET_UTF16LE == iod->ochset) /* need conversion of ZFF */ { DBGSOCK2((stdout, "socuse: Converting zff\n")); lcl_zff.addr = (char *)zff_buffer; lcl_zff.len = zff_len; new_len = gtm_conv(chset_desc[CHSET_UTF8], chset_desc[iod->ochset], &lcl_zff, NULL, NULL); if (MAX_ZFF_LEN < new_len) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZFF2MANY, 2, new_len, MAX_ZFF_LEN); if (NULL == newsocket.zff.addr) /* we rely on newsocket.zff.addr being set to 0 in iosocket_create() */ newsocket.zff.addr = (char *)malloc(MAX_ZFF_LEN); newsocket.zff.len = new_len; UNICODE_ONLY(newsocket.zff.char_len = 0); /* don't care */ memcpy(newsocket.zff.addr, stringpool.free, new_len); } else { /* Store parm without conversion */ if (gtm_utf8_mode) /* Check if ZFF has any invalid UTF-8 character */ { /* Note: the ZFF string originates from the source program, so is in UTF-8 mode or M mode regardless of OCHSET of this device. ZFF is output on WRITE # command, and MUST contain valid UTF-8 sequence. This validation is handled by gtm_conv in the path above. */ utf8_len_strict(zff_buffer, zff_len); } if (NULL == newsocket.zff.addr) /* we rely on newsocket.zff.addr being set to 0 in iosocket_create() */ newsocket.zff.addr = (char *)malloc(MAX_ZFF_LEN); memcpy(newsocket.zff.addr, zff_buffer, zff_len); } } if (ioerror_specified) newsocket.ioerror = ('T' == ioerror || 't' == ioerror); if (nodelay_specified || delay_specified) newsocket.nodelay = nodelay_specified; /* defaults to DELAY */ if (ibfsize_specified) newsocket.bufsiz = ibfsize; if (moreread_specified) { newsocket.moreread_timeout = moreread_timeout; newsocket.def_moreread_timeout = TRUE; /* need to know this was user-defined in iosocket_readfl.c */ } if (!create_new_socket) { /* these changes apply to only pre-existing sockets */ if (bfsize_specified) newsocket.buffer_size = bfsize; #ifdef TCP_NODELAY nodelay = newsocket.nodelay ? 1 : 0; if ((socketptr->nodelay != newsocket.nodelay) && (-1 == tcp_routines.aa_setsockopt(newsocket.sd, IPPROTO_TCP, TCP_NODELAY, &nodelay, SIZEOF(nodelay)))) { save_errno = errno; errptr = (char *)STRERROR(save_errno); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("TCP_NODELAY"), save_errno, LEN_AND_STR(errptr)); return; } #endif if ((socketptr->bufsiz != newsocket.bufsiz) && (-1 == tcp_routines.aa_setsockopt(newsocket.sd, SOL_SOCKET, SO_RCVBUF, &newsocket.bufsiz, SIZEOF(newsocket.bufsiz)))) { save_errno = errno; errptr = (char *)STRERROR(save_errno); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("SO_RCVBUF"), save_errno, LEN_AND_STR(errptr)); return; } if (socketptr->buffer_size != newsocket.buffer_size) { if (socketptr->buffered_length > bfsize) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKBFNOTEMPTY, 2, bfsize, socketptr->buffered_length); newsocket.buffer = (char *)malloc(bfsize); if (0 < socketptr->buffered_length) { memcpy(newsocket.buffer, socketptr->buffer + socketptr->buffered_offset, socketptr->buffered_length); newsocket.buffered_offset = 0; } } } /* -------------------------------------- action -------------------------------------------- */ if ((listen_specified && (!iosocket_bind(&newsocket, NO_M_TIMEOUT, ibfsize_specified))) || (connect_specified && (!iosocket_connect(&newsocket, 0, ibfsize_specified)))) { /* error message should be printed from bind/connect */ if (socketptr->sd > 0) (void)tcp_routines.aa_close(socketptr->sd); SOCKET_FREE(socketptr); return; } /* ------------------------------------ commit changes -------------------------------------- */ if (create_new_socket) { if (gtm_max_sockets <= newdsocket->n_socket) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets); return; } /* a new socket is created. so add to the list */ newsocket.dev = dsocketptr; newdsocket->socket[newdsocket->n_socket++] = socketptr; newdsocket->current_socket = newdsocket->n_socket - 1; } else if (socketptr->buffer_size != newsocket.buffer_size) free(socketptr->buffer); *socketptr = newsocket; memcpy(dsocketptr, newdsocket, d_socket_struct_len); return; } fis-gtm-V6.0-003/sr_port/iosocket_wait.c0000644000032200000250000002331412201176177017051 0ustar librarygtc/**************************************************************** * * * Copyright 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_wait.c * * return a listening socket -- create a new socket for the connection and set it to current * set it to current * set $KEY to "CONNECT" * return a connected socket -- set it to current * set $KEY to "READ" * timeout -- set $Test to 1 */ #include "mdef.h" #include #include "gtm_socket.h" #include "gtm_inet.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "io_params.h" #include "gt_timer.h" #include "io.h" #include "iotimer.h" #include "iotcp_select.h" #include "iotcproutine.h" #include "iotcpdef.h" #include "iosocketdef.h" #include "min_max.h" #include "outofband.h" #include #include "stack_frame.h" #include "mv_stent.h" #include "gtm_netdb.h" #include "gtm_stdlib.h" #define CONNECTED "CONNECT" #define READ "READ" GBLREF tcp_library_struct tcp_routines; GBLREF volatile int4 outofband; GBLREF int4 gtm_max_sockets; GBLREF int socketus_interruptus; GBLREF boolean_t dollar_zininterrupt; GBLREF stack_frame *frame_pointer; GBLREF unsigned char *stackbase, *stacktop, *msp, *stackwarn; GBLREF mv_stent *mv_chain; error_def(ERR_GETNAMEINFO); error_def(ERR_SOCKACPT); error_def(ERR_SOCKWAIT); error_def(ERR_TEXT); error_def(ERR_SOCKMAX); error_def(ERR_ZINTRECURSEIO); error_def(ERR_STACKCRIT); error_def(ERR_STACKOFLOW); boolean_t iosocket_wait(io_desc *iod, int4 timepar) { struct timeval utimeout; ABS_TIME cur_time, end_time; struct sockaddr_storage peer; /* socket address + port */ fd_set tcp_fd; d_socket_struct *dsocketptr; socket_struct *socketptr, *newsocketptr; socket_interrupt *sockintr; char *errptr; int4 errlen, ii, msec_timeout; int rv, max_fd, len; GTM_SOCKLEN_TYPE size; boolean_t zint_restart; mv_stent *mv_zintdev; int retry_num; struct sockaddr *peer_sa_ptr; char port_buffer[NI_MAXSERV], ipaddr[SA_MAXLEN + 1]; int errcode; /* check for validity */ assert(iod->type == gtmsocket); dsocketptr = (d_socket_struct *)iod->dev_sp; sockintr = &dsocketptr->sock_save_state; peer_sa_ptr = ((struct sockaddr *)(&peer)); /* Check for restart */ if (!dsocketptr->mupintr) /* Simple path, no worries*/ zint_restart = FALSE; else { /* We have a pending wait restart of some sort - check we aren't recursing on this device */ if (sockwhich_invalid == sockintr->who_saved) GTMASSERT; /* Interrupt should never have an invalid save state */ if (dollar_zininterrupt) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); if (sockwhich_wait != sockintr->who_saved) GTMASSERT; /* ZINTRECURSEIO should have caught */ DBGSOCK((stdout, "socwait: *#*#*#*#*#*#*# Restarted interrupted wait\n")); mv_zintdev = io_find_mvstent(iod, FALSE); if (mv_zintdev) { if (sockintr->end_time_valid) /* Restore end_time for timeout */ end_time = sockintr->end_time; /* Done with this mv_stent. Pop it off if we can, else mark it inactive. */ if (mv_chain == mv_zintdev) POP_MV_STENT(); /* pop if top of stack */ else { /* else mark it unused */ mv_zintdev->mv_st_cont.mvs_zintdev.buffer_valid = FALSE; mv_zintdev->mv_st_cont.mvs_zintdev.io_ptr = NULL; } zint_restart = TRUE; DBGSOCK((stdout, "socwait: mv_stent found - endtime: %d/%d\n", end_time.at_sec, end_time.at_usec)); } else DBGSOCK((stdout, "socwait: no mv_stent found !!\n")); dsocketptr->mupintr = FALSE; sockintr->who_saved = sockwhich_invalid; } /* check for events */ FD_ZERO(&tcp_fd); while (TRUE) { max_fd = 0; for (ii = 0; ii < dsocketptr->n_socket; ii++) { socketptr = dsocketptr->socket[ii]; if ((socket_listening == socketptr->state) || (socket_connected == socketptr->state)) { FD_SET(socketptr->sd, &tcp_fd); max_fd = MAX(max_fd, socketptr->sd); } } utimeout.tv_sec = timepar; utimeout.tv_usec = 0; msec_timeout = timeout2msec(timepar); sys_get_curr_time(&cur_time); if (!zint_restart || !sockintr->end_time_valid) add_int_to_abs_time(&cur_time, msec_timeout, &end_time); else { /* end_time taken from restart data. Compute what msec_timeout should be so timeout timer gets set correctly below. */ DBGSOCK((stdout, "socwait: Taking timeout end time from wait restart data\n")); cur_time = sub_abs_time(&end_time, &cur_time); if (0 > cur_time.at_sec) { msec_timeout = -1; utimeout.tv_sec = 0; utimeout.tv_usec = 0; } else { msec_timeout = (int4)(cur_time.at_sec * 1000 + cur_time.at_usec / 1000); utimeout.tv_sec = cur_time.at_sec; utimeout.tv_usec = (gtm_tv_usec_t)cur_time.at_usec; } } sockintr->end_time_valid = FALSE; for ( ; ; ) { rv = select(max_fd + 1, (void *)&tcp_fd, (void *)0, (void *)0, (timepar == NO_M_TIMEOUT ? (struct timeval *)0 : &utimeout)); if (0 > rv && EINTR == errno) { if (0 != outofband) { DBGSOCK((stdout, "socwait: outofband interrupt received (%d) -- " "queueing mv_stent for wait intr\n", outofband)); PUSH_MV_STENT(MVST_ZINTDEV); mv_chain->mv_st_cont.mvs_zintdev.io_ptr = iod; mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = FALSE; sockintr->who_saved = sockwhich_wait; sockintr->end_time = end_time; sockintr->end_time_valid = TRUE; dsocketptr->mupintr = TRUE; socketus_interruptus++; DBGSOCK((stdout, "socwait: mv_stent queued - endtime: %d/%d interrupts: %d\n", end_time.at_sec, end_time.at_usec, socketus_interruptus)); outofband_action(FALSE); GTMASSERT; /* Should *never* return from outofband_action */ return FALSE; /* For the compiler.. */ } sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (0 > cur_time.at_sec) { rv = 0; /* time out */ break; } utimeout.tv_sec = cur_time.at_sec; utimeout.tv_usec = (gtm_tv_usec_t)cur_time.at_usec; } else break; /* either other error or done */ } if (rv == 0) { iod->dollar.key[0] = '\0'; return FALSE; } else if (rv < 0) { errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr); return FALSE; } /* find out which socket is ready */ for (ii = 0; ii < dsocketptr->n_socket; ii++) { socketptr = dsocketptr->socket[ii]; if (0 != FD_ISSET(socketptr->sd, &tcp_fd)) break; } assert(ii < dsocketptr->n_socket); if (socket_listening == socketptr->state) { if (gtm_max_sockets <= dsocketptr->n_socket) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets); return FALSE; } size = SIZEOF(struct sockaddr_storage); rv = tcp_routines.aa_accept(socketptr->sd, peer_sa_ptr, &size); if (-1 == rv) { # ifdef __hpux if (ENOBUFS == errno) continue; /* On HP-UX, ENOBUFS may indicate a transient condition; retry */ # endif errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr); return FALSE; } SOCKET_DUP(socketptr, newsocketptr); newsocketptr->sd = rv; SOCKET_ADDR_COPY(newsocketptr->remote, peer_sa_ptr, size); /* translate internal address to numeric ip address */ GETNAMEINFO(peer_sa_ptr, size, ipaddr, SA_MAXLEN, NULL, 0, NI_NUMERICHOST, errcode); if (0 != errcode) { SOCKET_FREE(newsocketptr); RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); return FALSE; } if (NULL != newsocketptr->remote.saddr_ip) free(newsocketptr->remote.saddr_ip); STRNDUP(ipaddr, SA_MAXLEN, newsocketptr->remote.saddr_ip); /* translate internal address to port number*/ GETNAMEINFO(peer_sa_ptr, size, NULL, 0, port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode); if (0 != errcode) { SOCKET_FREE(newsocketptr); RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode); return FALSE; } newsocketptr->remote.port = ATOI(port_buffer); newsocketptr->state = socket_connected; newsocketptr->passive = FALSE; newsocketptr->first_read = newsocketptr->first_write = TRUE; /* put the new-born socket to the list and create a handle for it */ iosocket_handle(newsocketptr->handle, &newsocketptr->handle_len, TRUE, dsocketptr); dsocketptr->socket[dsocketptr->n_socket++] = newsocketptr; dsocketptr->current_socket = dsocketptr->n_socket - 1; len = SIZEOF(CONNECTED) - 1; memcpy(&iod->dollar.key[0], CONNECTED, len); iod->dollar.key[len++] = '|'; memcpy(&iod->dollar.key[len], newsocketptr->handle, newsocketptr->handle_len); len += newsocketptr->handle_len; iod->dollar.key[len++] = '|'; strncpy(&iod->dollar.key[len], newsocketptr->remote.saddr_ip, DD_BUFLEN - 1 - len); iod->dollar.key[DD_BUFLEN-1] = '\0'; /* In case we fill the buffer */ } else { assert(socket_connected == socketptr->state); dsocketptr->current_socket = ii; len = SIZEOF(READ) - 1; memcpy(&iod->dollar.key[0], READ, len); iod->dollar.key[len++] = '|'; memcpy(&iod->dollar.key[len], socketptr->handle, socketptr->handle_len); len += socketptr->handle_len; iod->dollar.key[len++] = '|'; if (NULL != socketptr->remote.saddr_ip) { strncpy(&iod->dollar.key[len], socketptr->remote.saddr_ip, DD_BUFLEN - 1 - len); iod->dollar.key[DD_BUFLEN-1] = '\0'; } else iod->dollar.key[len] = '\0'; } break; } return TRUE; } fis-gtm-V6.0-003/sr_port/iosocket_write.c0000644000032200000250000002110312201176157017227 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_write.c */ #include "mdef.h" #include #include "gtm_socket.h" #include "gtm_inet.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "io.h" #include "iotcpdef.h" #include "iotcproutine.h" #include "gt_timer.h" #include "iosocketdef.h" #include "dollarx.h" #include "gtm_conv.h" #include "gtm_utf8.h" #include "stringpool.h" #include "send_msg.h" #include "error.h" GBLREF io_pair io_curr_device; #ifdef UNIX GBLREF io_pair io_std_device; GBLREF bool prin_out_dev_failure; #endif GBLREF tcp_library_struct tcp_routines; GBLREF mstr chset_names[]; GBLREF UConverter *chset_desc[]; GBLREF spdesc stringpool; error_def(ERR_SOCKWRITE); error_def(ERR_TEXT); error_def(ERR_CURRSOCKOFR); error_def(ERR_ZFF2MANY); error_def(ERR_DELIMSIZNA); error_def(ERR_ZINTRECURSEIO); UNIX_ONLY(error_def(ERR_NOPRINCIO);) void iosocket_write(mstr *v) { iosocket_write_real(v, TRUE); } void iosocket_write_real(mstr *v, boolean_t convert_output) { io_desc *iod; mstr tempv; char *out, *c_ptr, *c_top; int in_b_len, b_len, status, new_len, c_len, mb_len; int flags; d_socket_struct *dsocketptr; socket_struct *socketptr; DBGSOCK2((stdout, "socwrite: ************************** Top of iosocket_write\n")); iod = io_curr_device.out; assert(gtmsocket == iod->type); dsocketptr = (d_socket_struct *)iod->dev_sp; socketptr = dsocketptr->socket[dsocketptr->current_socket]; if (dsocketptr->n_socket <= dsocketptr->current_socket) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket); return; } if (dsocketptr->mupintr) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO); #ifdef MSG_NOSIGNAL flags = MSG_NOSIGNAL; /* return EPIPE instead of SIGPIPE */ #else flags = 0; #endif socketptr->lastop = TCP_WRITE; if (socketptr->first_write) { /* First WRITE, do following 1. Transition to UTF16BE if ochset is UTF16 and WRITE a BOM 2. Convert ZFF into ochset format so we don't need to convert every time ZFF is output 3. Convert DELIMITER 0 to OCHSET format to avoid repeated conversions of DELIM0 on output */ if (CHSET_UTF16 == iod->ochset) { DBGSOCK2((stdout, "socwrite: First write UTF16 -- writing BOM\n")); iod->ochset = CHSET_UTF16BE; /* per Unicode standard, assume big endian when endian format is unspecified */ get_chset_desc(&chset_names[iod->ochset]); DOTCPSEND(socketptr->sd, UTF16BE_BOM, UTF16BE_BOM_LEN, flags, status); DBGSOCK2((stdout, "socwrite: TCP send of BOM-BE with rc %d\n", status)); if (0 != status) { SOCKERROR(iod, socketptr, ERR_SOCKWRITE, status); return; } #ifdef UNIX else if (iod == io_std_device.out) prin_out_dev_failure = FALSE; #endif } if (CHSET_UTF16BE == iod->ochset || CHSET_UTF16LE == iod->ochset) /* need conversion of ZFF and DELIM0 */ { if (0 < socketptr->zff.len) { new_len = gtm_conv(chset_desc[CHSET_UTF8], chset_desc[iod->ochset], &socketptr->zff, NULL, NULL); if (MAX_ZFF_LEN < new_len) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZFF2MANY, 2, new_len, MAX_ZFF_LEN); if (NULL != socketptr->zff.addr) /* we rely on newsocket.zff.addr being set to NULL in iosocket_create() */ socketptr->zff.addr = (char *)malloc(MAX_ZFF_LEN); socketptr->zff.len = new_len; UNICODE_ONLY(socketptr->zff.char_len = 0); /* don't care */ memcpy(socketptr->zff.addr, stringpool.free, new_len); } if (0 < socketptr->n_delimiter) { new_len = gtm_conv(chset_desc[CHSET_UTF8], chset_desc[iod->ochset], &socketptr->delimiter[0], NULL, NULL); if (MAX_DELIM_LEN < new_len) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DELIMSIZNA); return; } socketptr->odelimiter0.len = new_len; UNICODE_ONLY(socketptr->odelimiter0.char_len = socketptr->delimiter[0].char_len); socketptr->odelimiter0.addr = malloc(new_len); memcpy(socketptr->odelimiter0.addr, stringpool.free, new_len); } } socketptr->first_write = FALSE; } memcpy(iod->dollar.device, "0", SIZEOF("0")); if (CHSET_M != iod->ochset) { /* For ochset == UTF-8, validate the output, * For ochset == UTF-16[B|L]E, convert the output (and validate during conversion) */ if (CHSET_UTF8 == iod->ochset) { UTF8_LEN_STRICT(v->addr, v->len); /* triggers badchar error for invalid sequence */ tempv = *v; } else { assert(CHSET_UTF16BE == iod->ochset || CHSET_UTF16LE == iod->ochset); /* Certain types of writes (calls from iosocket_wteol or _wtff) already have their output converted. Converting again just wrecks it so avoid that when necessary. */ if (convert_output) { new_len = gtm_conv(chset_desc[CHSET_UTF8], chset_desc[iod->ochset], v, NULL, NULL); tempv.addr = (char *)stringpool.free; tempv.len = new_len; /* Since there is no dependence on string pool between now and when we send the data, we won't bother "protecting" the stringpool value. This space can be used again by whomever needs it without us forcing a garbage collection due to IO reformat. */ /* stringpool.free += new_len; */ } else tempv = *v; } } else tempv = *v; if (0 != (in_b_len = tempv.len)) { DBGSOCK2((stdout, "socwrite: starting output loop (%d bytes) - iodwidth: %d wrap: %d\n", in_b_len, iod->width, iod->wrap)); for (out = tempv.addr; ; out += b_len) { DBGSOCK2((stdout, "socwrite: ---------> Top of write loop $x: %d $y: %d in_b_len: %d\n", iod->dollar.x, iod->dollar.y, in_b_len)); if (!iod->wrap) b_len = in_b_len; else { if ((iod->dollar.x >= iod->width) && (START == iod->esc_state)) { /* Should this really be iosocket_Wteol() (for FILTER)? IF we call iosocket_wteol(), * there will be recursion iosocket_Write -> iosocket_Wteol ->iosocket_Write */ if (0 < socketptr->n_delimiter) { DOTCPSEND(socketptr->sd, socketptr->odelimiter0.addr, socketptr->odelimiter0.len, (socketptr->urgent ? MSG_OOB : 0) | flags, status); DBGSOCK2((stdout, "socwrite: TCP send of %d byte delimiter with rc %d\n", socketptr->odelimiter0.len, status)); if (0 != status) { SOCKERROR(iod, socketptr, ERR_SOCKWRITE, status); return; } #ifdef UNIX else if (iod == io_std_device.out) prin_out_dev_failure = FALSE; #endif } iod->dollar.y++; iod->dollar.x = 0; DBGSOCK2((stdout, "socwrite: $x > width - wrote delimiter: %d $x: %d $y: %d\n", (0 < socketptr->n_delimiter), iod->dollar.x, iod->dollar.y)); } if ((START != iod->esc_state) || ((int)(iod->dollar.x + in_b_len) <= (int)iod->width)) { /* enough room even in the worst case, i.e., if width - dollar.x can accommodate in_b_len chars, * it certainly can accommodate in_b_len bytes */ b_len = in_b_len; } else { c_len = iod->width - iod->dollar.x; for (c_ptr = out, c_top = out + in_b_len, b_len = 0; (c_ptr < c_top) && c_len--; b_len += mb_len, c_ptr += mb_len) { mb_len = (CHSET_M == iod->ochset) ? 0 : (CHSET_UTF8 == iod->ochset) ? UTF8_MBFOLLOW(c_ptr) : (CHSET_UTF16BE == iod->ochset) ? UTF16BE_MBFOLLOW(c_ptr, c_top) : UTF16LE_MBFOLLOW(c_ptr, c_top); assert(-1 != mb_len); mb_len++; } DBGSOCK2((stdout, "socwrite: computing string length in chars: in_b_len: %d mb_len: %d\n", in_b_len, mb_len)); } } assert(0 != b_len); DOTCPSEND(socketptr->sd, out, b_len, (socketptr->urgent ? MSG_OOB : 0) | flags, status); DBGSOCK2((stdout, "socwrite: TCP data send of %d bytes with rc %d\n", b_len, status)); if (0 != status) { SOCKERROR(iod, socketptr, ERR_SOCKWRITE, status); return; } #ifdef UNIX else if (iod == io_std_device.out) prin_out_dev_failure = FALSE; #endif dollarx(iod, (uchar_ptr_t)out, (uchar_ptr_t)out + b_len); DBGSOCK2((stdout, "socwrite: $x/$y updated by dollarx(): $x: %d $y: %d filter: %d escape: %d\n", iod->dollar.x, iod->dollar.y, iod->write_filter, iod->esc_state)); in_b_len -= b_len; if (0 >= in_b_len) break; } iod->dollar.za = 0; } DBGSOCK2((stdout, "socwrite: <--------- Leaving iosocket_write\n")); return; } fis-gtm-V6.0-003/sr_port/iosocket_wteol.c0000644000032200000250000000372412201176157017240 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_wteol.c */ /* write the 0th delimiter and flush */ #include "mdef.h" #include "gtm_socket.h" #include "gtm_inet.h" #include "gt_timer.h" #include "io.h" #include "iotcpdef.h" #include "iotcproutine.h" #include "iottdef.h" #include "iosocketdef.h" GBLREF tcp_library_struct tcp_routines; void iosocket_wteol(int4 val, io_desc *io_ptr) { d_socket_struct *dsocketptr; socket_struct *socketptr; char *ch, *top; int eol_cnt; assert(gtmsocket == io_ptr->type); dsocketptr = (d_socket_struct *)io_ptr->dev_sp; socketptr = dsocketptr->socket[dsocketptr->current_socket]; assert(val); io_ptr->esc_state = START; if (socketptr->n_delimiter > 0) { for (eol_cnt = val; eol_cnt--; ) { io_ptr->dollar.x = 0; /* so that iosocket_write doesn't try to wrap (based on escape state and width) */ iosocket_write_real(&socketptr->odelimiter0, FALSE); } } /* $X is maintained in VMS without the below assignment (resetting to 0) because the NATIVE_TTEOL is \015\012 * and the (\015) triggers appropriate maintenance of $X. In UNIX, NATIVE_TTEOL is \012, so * FILTER=CHARACTER effectively turns off all $X maintenance (except for WRAP logic). * In VMS the below assignment is not necessary, but harmless; it is always logically correct. */ io_ptr->dollar.x = 0; if (!(io_ptr->write_filter & CHAR_FILTER) || !socketptr->delim0containsLF) { /* If FILTER won't do it, also maintain $Y */ io_ptr->dollar.y += val; if (io_ptr->length) io_ptr->dollar.y %= io_ptr->length; } iosocket_flush(io_ptr); return; } fis-gtm-V6.0-003/sr_port/iosocket_wtff.c0000644000032200000250000000211112201176157017041 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_wtff.c */ #include "mdef.h" #include "gtm_socket.h" #include "gtm_inet.h" #include "io.h" #include "gt_timer.h" #include "iotcpdef.h" #include "iosocketdef.h" GBLREF io_pair io_curr_device; void iosocket_wtff(void) { io_desc *iod; socket_struct *socketptr; d_socket_struct *dsocketptr; iod = io_curr_device.out; assert(gtmsocket == iod->type); iod->esc_state = START; dsocketptr = (d_socket_struct *)iod->dev_sp; socketptr = dsocketptr->socket[dsocketptr->current_socket]; if (socketptr->zff.len) iosocket_write_real(&socketptr->zff, FALSE); iosocket_flush(iod); iod->dollar.x = 0; iod->dollar.y = 0; return; } fis-gtm-V6.0-003/sr_port/iosocket_wtone.c0000644000032200000250000000270112201176157017234 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iosocket_wtone.c */ #include "mdef.h" #include "gtm_socket.h" #include "gtm_inet.h" #include "io.h" #include "gt_timer.h" #include "iotcpdef.h" #include "iosocketdef.h" #include "gtm_utf8.h" GBLREF io_pair io_curr_device; void iosocket_wtone(int ch) { mstr temp; char c, uni_c[4], *endptr; io_desc *iod; if (CHSET_M == io_curr_device.out->ochset) { c = (char)ch; temp.len = 1; temp.addr = (char *)&c; } else { switch(io_curr_device.out->ochset) { case CHSET_UTF8: endptr = (char *)UTF8_WCTOMB(ch, uni_c); break; case CHSET_UTF16: /* unspecified endian format implies Big Endian */ case CHSET_UTF16BE: endptr = UTF16BE_WCTOMB(ch, uni_c); break; case CHSET_UTF16LE: endptr = UTF16LE_WCTOMB(ch, uni_c); break; default: GTMASSERT; } temp.addr = uni_c; temp.len = INTCAST(endptr - uni_c); assert(0 < temp.len); /* we validated the code point already in op_wtone() */ } UNICODE_ONLY(temp.char_len = 1); iosocket_write_real(&temp, TRUE); return; } fis-gtm-V6.0-003/sr_port/iosocketdef.h0000644000032200000250000002702012201176157016505 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef IOSOCKETDEF_H #define IOSOCKETDEF_H /* iosocketdef.h */ /* one socket device may have more than one socket associate with it. * one socket may have more than one delimiter associate with it. */ #include #include "gtm_inet.h" #include "gtm_netdb.h" #include "gtm_socket.h" /* for using sockaddr_storage */ #include "iotcpdef.h" #ifndef GTM_MB_LEN_MAX #include "gtm_utf8.h" #endif /* Debugging notes: Some debuging calls as as below. Note that DBGSOCK2 is *always* disabled. * disabled. As parts of the code work, the DBGSOCK calls are changed to DBGSOCK2 to get * them out of the way without removing them (they may be useful in the future). * * Uncomment the define for DEBUG_SOCK below to enable DBGSOCK() debugging */ /* #define DEBUG_SOCK */ #ifdef DEBUG_SOCK # define DBGSOCK(X) DBGFPF(X) # define DBGSOCK_ONLY(X) X #else # define DBGSOCK(X) # define DBGSOCK_ONLY(X) #endif #define DBGSOCK2(X) #define DBGSOCK_ONLY2(X) /* About the length of the delimiter string. While we are allocating lots of space here for the maximum representation * of 64 delimiters each of 64 chars MB chars, the fact is that the iop option processing actually limits the string * containing all the delimiters to 255 bytes by its nature of having single byte length field imbedded in the buffer * stream. When the iop processing is modified to handle a larger string, these options will be useful. But for right * now, they are way overkill.. */ #define MAX_N_SOCKET 64 /* Initial default for gtm_max_sockets in gbldefs.c */ #define MAX_MAX_N_SOCKET (1024 * 1024) /* Values higher than this absurd value are most likely wrong */ #define MAX_N_DELIMITER 64 #define MAX_DELIM_LEN (MAX_N_DELIMITER * GTM_MB_LEN_MAX) /* worst case byte length for 64 UTF-8 characters */ #define MAX_HANDLE_LEN (64 * GTM_MB_LEN_MAX) /* worst case byte length for 64 UTF-8 characters */ #define MAX_ZFF_LEN (64 * GTM_MB_LEN_MAX) /* worst case byte length for 64 UTF-8 characters */ #define DEFAULT_LISTEN_DEPTH 1 #define DEFAULT_SOCKET_BUFFER_SIZE 0x400 #define MAX_SOCKET_BUFFER_SIZE 0x100000 #define MAX_INTERNAL_SOCBUF_SIZE 0x100000 /* Next three fields relate to the time that a variable length unterminated read will wait to see * if there is more input coming in before it gives up and returns what it has to the user. This * time is specified in milliseconds. This value used to be 200ms but that was deemed too long on * modern systems yet now the user can change it if they wish to. Tradeoffs are longer waits for * variable reads versus potential CPU burner if the value gets too low. The implementation now * waits INITIAL_MOREREAD_TIMEOUT time for the first read to occur and then switches to the * DEFAULT_MOREREAD_TIMEOUT. This keeps CPU usage low during the potentially long period prior to * reading some data, while being more responsive for subsequent reads. */ #define INITIAL_MOREREAD_TIMEOUT 200 #define DEFAULT_MOREREAD_TIMEOUT 10 #define MAX_MOREREAD_TIMEOUT 999 #define ONE_COMMA "1," #define SOCKERROR(iod, socketptr, gtmerror, syserror) \ { \ int errlen; \ char *errptr; \ iod->dollar.za = 9; \ memcpy(iod->dollar.device, ONE_COMMA, SIZEOF(ONE_COMMA)); \ errptr = (char *)STRERROR(syserror); \ errlen = STRLEN(errptr); \ memcpy(&iod->dollar.device[SIZEOF(ONE_COMMA) - 1], errptr, errlen + 1); /* + 1 for null */ \ assert(ERR_SOCKWRITE == gtmerror); \ UNIX_ONLY(if (iod == io_std_device.out) \ { \ if (!prin_out_dev_failure) \ prin_out_dev_failure = TRUE; \ else \ { \ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOPRINCIO); \ stop_image_no_core(); \ } \ }) \ if (socketptr->ioerror) \ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) gtmerror, 0, ERR_TEXT, 2, errlen, errptr); \ } #define SOCKET_ALLOC(SOCKPTR) \ { \ SOCKPTR = (socket_struct *)malloc(SIZEOF(socket_struct)); \ memset(SOCKPTR, 0, SIZEOF(socket_struct)); \ } #define SOCKET_ADDR(SOCKPTR, SOCKEND) \ ((sockaddr_ptr)(SOCKPTR->SOCKEND.sa \ ? SOCKPTR->SOCKEND.sa \ : (SOCKPTR->SOCKEND.sa = (struct sockaddr *)malloc(SIZEOF(struct sockaddr_storage))))) #define SOCKET_LOCAL_ADDR(SOCKPTR) SOCKET_ADDR(SOCKPTR, local) #define SOCKET_REMOTE_ADDR(SOCKPTR) SOCKET_ADDR(SOCKPTR, remote) #define SOCKET_ADDR_COPY(SOCKADDRESS, SOCKADDRPTR, SOCKADDRLEN) \ { \ if (SOCKADDRESS.sa) \ free(SOCKADDRESS.sa); \ SOCKADDRESS.sa = (struct sockaddr *)malloc(SOCKADDRLEN); \ memcpy(SOCKADDRESS.sa, SOCKADDRPTR, SOCKADDRLEN); \ } #define SOCKET_AI_TO_ADDR(SOCKPTR, AIPTR, SOCKEND) SOCKET_ADDR_COPY((SOCKPTR)->SOCKEND, (AIPTR)->ai_addr, (AIPTR)->ai_addrlen) #define SOCKET_AI_TO_LOCAL_ADDR(SOCKPTR, AIPTR) SOCKET_AI_TO_ADDR(SOCKPTR, AIPTR, local) #define SOCKET_AI_TO_REMOTE_ADDR(SOCKPTR, AIPTR) SOCKET_AI_TO_ADDR(SOCKPTR, AIPTR, remote) #define SOCKET_ADDRLEN(SOCKPTR, AIPTR, SOCKEND) \ (((SOCKPTR)->SOCKEND.sa) ? ((AIPTR)->ai_addrlen) : (SIZEOF(struct sockaddr_storage))) #define SOCKET_BUFFER_INIT(SOCKPTR, SIZE) \ { \ SOCKPTR->buffer = (char *)malloc(SIZE); \ SOCKPTR->buffer_size = SIZE; \ SOCKPTR->buffered_length = SOCKPTR->buffered_offset = 0; \ } #define SOCKET_FREE(SOCKPTR) \ { \ if (NULL != SOCKPTR->buffer) \ free(SOCKPTR->buffer); \ if (NULL != SOCKPTR->zff.addr) \ free(SOCKPTR->zff.addr); \ if (NULL != SOCKPTR->local.sa) \ free(SOCKPTR->local.sa); \ if (NULL != SOCKPTR->remote.sa) \ free(SOCKPTR->remote.sa); \ if (NULL != SOCKPTR->local.saddr_ip) \ free(SOCKPTR->local.saddr_ip); \ if (NULL != SOCKPTR->remote.saddr_ip) \ free(SOCKPTR->remote.saddr_ip); \ iosocket_delimiter((unsigned char *)NULL, 0, SOCKPTR, TRUE); \ free(SOCKPTR); \ } #define SOCKET_DUP(SOCKPTR, NEWSOCKPTR) \ { \ NEWSOCKPTR = (socket_struct *)malloc(SIZEOF(socket_struct)); \ *NEWSOCKPTR = *SOCKPTR; \ if (NULL != SOCKPTR->buffer) \ NEWSOCKPTR->buffer = (char *)malloc(SOCKPTR->buffer_size); \ if (NULL != SOCKPTR->zff.addr) \ { \ NEWSOCKPTR->zff.addr = (char *)malloc(MAX_ZFF_LEN); \ memcpy(NEWSOCKPTR->zff.addr, SOCKPTR->zff.addr, SOCKPTR->zff.len); \ } \ if (NULL != SOCKPTR->local.sa) \ { \ NEWSOCKPTR->local.sa = (struct sockaddr *)malloc(SOCKPTR->local.ai.ai_addrlen); \ memcpy(NEWSOCKPTR->local.sa, SOCKPTR->local.sa, SOCKPTR->local.ai.ai_addrlen); \ } \ if (NULL != SOCKPTR->remote.sa) \ { \ NEWSOCKPTR->remote.sa = (struct sockaddr *)malloc(SOCKPTR->remote.ai.ai_addrlen); \ memcpy(NEWSOCKPTR->remote.sa, SOCKPTR->remote.sa, SOCKPTR->remote.ai.ai_addrlen); \ } \ if (NULL != SOCKPTR->local.saddr_ip) \ STRNDUP(SOCKPTR->local.saddr_ip, SA_MAXLEN, NEWSOCKPTR->local.saddr_ip); \ if (NULL != SOCKPTR->remote.saddr_ip) \ STRNDUP(SOCKPTR->remote.saddr_ip, SA_MAXLEN, NEWSOCKPTR->remote.saddr_ip); \ iosocket_delimiter_copy(SOCKPTR, NEWSOCKPTR); \ } enum socket_state { socket_connected, socket_listening, socket_bound, socket_created, socket_connect_inprogress }; enum socket_protocol { socket_tcpip, socket_spx, n_socket_protocol }; enum socket_which /* which module saved the interrupted info */ { sockwhich_invalid, sockwhich_readfl, sockwhich_wait, sockwhich_connect }; typedef struct socket_address_type { struct sockaddr *sa; struct addrinfo ai; struct addrinfo *ai_head; /* store the head of addrinfo linked list */ unsigned short port; char *saddr_ip; } socket_address; typedef struct socket_struct_type { int sd; /* socket descriptor */ int temp_sd; /* a temp socket descriptor only to test whether IPv6 can be created */ struct d_socket_struct_type *dev; /* point back to the driver */ boolean_t passive, ioerror, urgent, delim0containsLF; enum socket_state state; enum socket_protocol protocol; socket_address local, remote; uint4 lastop; uint4 moreread_timeout; /* timeout to see if more data available (ms) */ char handle[MAX_HANDLE_LEN]; int handle_len; int bufsiz; /* OS internal buffer size */ int n_delimiter; int last_recv_errno; mstr delimiter[MAX_N_DELIMITER]; mstr idelimiter[MAX_N_DELIMITER]; mstr odelimiter0; size_t buffer_size; /* size of the buffer for this socket */ size_t buffered_length; /* length of stuff buffered for this socket */ size_t buffered_offset; /* offset of the buffered stuff to buffer head */ char *buffer; /* pointer to the the buffer of this socket */ boolean_t nodelay; boolean_t first_read; boolean_t first_write; boolean_t def_moreread_timeout; /* true if deviceparameter morereadtime defined in open or use */ mstr zff; } socket_struct; typedef struct socket_interrupt_type { ABS_TIME end_time; enum socket_which who_saved; int max_bufflen; int bytes_read; int chars_read; boolean_t end_time_valid; boolean_t ibfsize_specified; struct d_socket_struct_type *newdsocket; } socket_interrupt; typedef struct d_socket_struct_type { socket_interrupt sock_save_state; /* Saved state of interrupted IO */ boolean_t mupintr; /* We were mupip interrupted */ int4 current_socket; /* current socket index */ int4 n_socket; /* number of sockets */ struct io_desc_struct *iod; /* Point back to main IO descriptor block */ struct socket_struct_type *socket[1]; /* Array size determined by gtm_max_sockets */ } d_socket_struct; boolean_t iosocket_bind(socket_struct *socketptr, int4 timepar, boolean_t update_bufsiz); boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t update_bufsiz); boolean_t iosocket_delimiter(unsigned char *delimiter_buffer, int4 delimiter_len, socket_struct *socketptr, boolean_t rm); void iosocket_delim_conv(socket_struct *socketptr, gtm_chset_t to_chset); void iosocket_delimiter_copy(socket_struct *from, socket_struct *to); boolean_t iosocket_switch(char *handle, int handle_len, d_socket_struct *from, d_socket_struct *to); int4 iosocket_handle(char *handle, int *len, boolean_t newhandle, d_socket_struct *dsocketptr); socket_struct *iosocket_create(char *sockaddr, uint4 bfsize, int file_des); ssize_t iosocket_snr(socket_struct *socketptr, void *buffer, size_t maxlength, int flags, ABS_TIME *time_for_read); void iosocket_unsnr(socket_struct *socketptr, unsigned char *buffer, size_t len); ssize_t iosocket_snr_utf_prebuffer(io_desc *iod, socket_struct *socketptr, int flags, ABS_TIME *time_for_read, boolean_t wait_for_input); void iosocket_write_real(mstr *v, boolean_t convert_output); void iosocket_readfl_badchar(mval *vmvalptr, int datalen, int delimlen, unsigned char *delimptr, unsigned char *strend); #endif fis-gtm-V6.0-003/sr_port/iotcp_close.c0000644000032200000250000000416512201176157016511 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iotcp_close.c - close a TCP/IP connection * Parameters- * iod - I/O descriptor for the currently open TCP/IP connection. * * pp->str.addr - device parameters * */ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_inet.h" #include "copy.h" #include "io_params.h" #include "io.h" #include "iotcpdef.h" #include "iotcproutine.h" #include "stringpool.h" GBLREF tcp_library_struct tcp_routines; LITREF unsigned char io_params_size[]; void iotcp_close(io_desc *iod, mval *pp) { bool close_listen_socket = FALSE; unsigned char c; d_tcp_struct *tcpptr; int p_offset; #ifdef DEBUG_TCP PRINTF("%s >>>\n", __FILE__); #endif assert(iod->type == tcp); tcpptr = (d_tcp_struct *)iod->dev_sp; p_offset = 0; while (*(pp->str.addr + p_offset) != iop_eol) { switch (c = *(pp->str.addr + p_offset++)) { case iop_listen: /* close the listening socket associated with this connection, * rather than the actual connection socket. */ close_listen_socket = TRUE; break; case iop_exception: iod->error_handler.len = *(pp->str.addr + p_offset); iod->error_handler.addr = (char *)(pp->str.addr + p_offset + 1); s2pool(&iod->error_handler); break; default: break; } p_offset += ((IOP_VAR_SIZE == io_params_size[c]) ? (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[c]); } if (close_listen_socket) { iotcp_rmlsock(iod); #ifdef DEBUG_TCP PRINTF("%s (listening socket for %d) <<<\n", __FILE__, tcpptr->socket); #endif } else { if (iod->state != dev_open) return; tcp_routines.aa_close(tcpptr->socket); iod->state = dev_closed; #ifdef DEBUG_TCP PRINTF("%s (%d) <<<\n", __FILE__, tcpptr->socket); #endif } } fis-gtm-V6.0-003/sr_port/iotcp_dummy.c0000644000032200000250000000110712201176157016530 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" short iotcp_dummy(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout) { return 0; } fis-gtm-V6.0-003/sr_port/iotcp_fillroutine.c0000644000032200000250000000673612201176157017746 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* get socket routines address */ #include "mdef.h" #include "gtm_netdb.h" #include "gtm_unistd.h" #include #include "gtm_socket.h" #include "gtm_inet.h" #include "gtm_string.h" /* for FD_ZERO */ #include "io.h" #include "iotcp_select.h" #include "iotcproutine.h" GBLDEF tcp_library_struct tcp_routines; int gtm_accept(int socket, struct sockaddr *address, sssize_t *address_len); int gtm_recv(int socket, void *buffer, size_t length, int flags); int gtm_send(int socket, void *buffer, size_t length, int flags); /* * Note - the checks for EINTR in these functions are valid and need to stay in, * because the functions are being assigned to members of the tcp_routines table, * and thus cannot be replaced by EINTR wrapper macros. */ int gtm_accept(int socket, struct sockaddr *address, sssize_t *address_len) { int res; do { res = accept(socket, address, (GTM_SOCKLEN_TYPE *)address_len); } while (-1 == res && EINTR == errno); return(res); } int gtm_connect(int socket, struct sockaddr *address, size_t address_len) { int res, sockerror; GTM_SOCKLEN_TYPE sockerrorlen; fd_set writefds; res = connect(socket, address, (GTM_SOCKLEN_TYPE)address_len); if ((-1 == res) && ((EINTR == errno) || (EINPROGRESS == errno) #if (defined(__osf__) && defined(__alpha)) || defined(__sun) || defined(__vms) || (EWOULDBLOCK == errno) #endif )) {/* connection attempt will continue so wait for completion */ do { /* a plain connect will usually timeout after 75 seconds with ETIMEDOUT */ FD_ZERO(&writefds); FD_SET(socket, &writefds); res = select(socket + 1, NULL, &writefds, NULL, NULL); if (-1 == res && EINTR == errno) continue; if (0 < res) { /* check for socket error */ sockerrorlen = SIZEOF(sockerror); res = getsockopt(socket, SOL_SOCKET, SO_ERROR, &sockerror, &sockerrorlen); if (0 == res && 0 != sockerror) { /* return socket error */ res = -1; errno = sockerror; } } break; } while (TRUE); } else if (-1 == res && EISCONN == errno) res = 0; /* socket is already connected */ return(res); } int gtm_recv(int socket, void *buffer, size_t length, int flags) { int res; do { res = (int)(recv(socket, buffer, (int)(length), flags)); } while (-1 == res && EINTR == errno); return(res); } int gtm_send(int socket, void *buffer, size_t length, int flags) { int res; do { res = (int)(send(socket, buffer, (int)(length), flags)); } while (-1 == res && EINTR == errno); return(res); } int iotcp_fillroutine(void) { if (gtm_accept == tcp_routines.aa_accept) return 0; /* already done */ tcp_routines.aa_accept = gtm_accept; tcp_routines.aa_bind = bind; tcp_routines.aa_close = close; tcp_routines.aa_connect = gtm_connect; tcp_routines.aa_getsockname = getsockname; tcp_routines.aa_getsockopt = getsockopt; tcp_routines.aa_listen = listen; tcp_routines.aa_recv = (int (*)())gtm_recv; tcp_routines.aa_select = select; tcp_routines.aa_send = (int (*)())gtm_send; tcp_routines.aa_setsockopt = setsockopt; tcp_routines.aa_socket = socket; return 0; } fis-gtm-V6.0-003/sr_port/iotcp_flush.c0000644000032200000250000000165412201176157016525 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_inet.h" #include "io.h" #include "iotcpdef.h" void iotcp_flush(io_desc *iod) { #ifdef C9A06001531 /* pending change request C9A06001531 */ d_tcp_struct *tcpptr; #ifdef DEBUG_TCP PRINTF("%s >>>\n", __FILE__); #endif tcpptr = (d_tcp_struct *)iod->dev_sp; if ((TCP_WRITE == iod->dollar.x && tcpptr->lastop) && !iod->dollar.za) iotcp_wteol(1, iod); #ifdef DEBUG_TCP PRINTF("%s <<<\n", __FILE__); #endif #endif return; } fis-gtm-V6.0-003/sr_port/iotcp_iocontrol.c0000644000032200000250000000232512201176157017410 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "gtm_inet.h" #include "gtm_string.h" #include "io.h" #include "iotcpdef.h" GBLREF io_pair io_curr_device; void iotcp_iocontrol(mstr *d) { return; } void iotcp_dlr_device(mstr *d) { io_desc *iod; int len; iod = io_curr_device.out; len = STRLEN(iod->dollar.device); /* verify internal buffer has enough space for $DEVICE string value */ assert((int)d->len > len); memcpy(d->addr, iod->dollar.device, len); d->len = len; return; } void iotcp_dlr_key(mstr *d) { io_desc *iod; int len; iod = io_curr_device.out; len = STRLEN(iod->dollar.key); /* verify internal buffer has enough space for $KEY string value */ assert((int)d->len > len); memcpy(d->addr, iod->dollar.key, len); d->len = len; return; } fis-gtm-V6.0-003/sr_port/iotcp_list.c0000644000032200000250000001227612201176157016361 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iotcp_list.c - routines to maintain a list of TCP/IP listening sockets */ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "gtm_socket.h" #include "gtm_inet.h" #include #include "io_params.h" #include "io.h" #include "iotcproutine.h" #include "iotcpdef.h" error_def(ERR_SOCKINIT); error_def(ERR_TEXT); /* list of listening sockets */ typedef struct lsock_rec_s { int socket; struct sockaddr_storage sas; struct addrinfo ai; struct lsock_rec_s *next; io_log_name *ldev; /* listening device record */ } lsock_rec; static lsock_rec *lsock_list = NULL; GBLREF tcp_library_struct tcp_routines; int iotcp_newlsock(io_log_name *dev, d_tcp_struct *tcpptr); /* find the listening socket associated with the address of this * new socket, creating a listening socket if there is none. */ int iotcp_getlsock(io_log_name *dev) { d_tcp_struct *tcpptr; lsock_rec *ls; #ifdef DEBUG_TCP PRINTF("iotcp_getlsock ---\n"); #endif tcpptr = (d_tcp_struct *)dev->iod->dev_sp; for (ls = lsock_list; ls != NULL; ls = ls->next) if (0 == memcmp(&(tcpptr->sas), &(ls->sas), SIZEOF(tcpptr->sas))) return ls->socket; return iotcp_newlsock(dev, tcpptr); } int iotcp_newlsock(io_log_name *dev, d_tcp_struct *tcpptr) { lsock_rec *new_lsock; io_log_name *ldev; /* listening device */ d_tcp_struct *lsock_tcp; int lsock; char buf[MAX_TRANS_NAME_LEN]; static char ones[] = {1, 1, 1}; mstr ldev_name; int on = 1; char *errptr; int4 errlen; #ifdef DEBUG_TCP PRINTF("iotcp_newlsock ---\n"); #endif lsock = tcp_routines.aa_socket(tcpptr->ai.ai_family, tcpptr->ai.ai_socktype, tcpptr->ai.ai_protocol); if (lsock == -1) { errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return 0; } /* allow multiple connections to the same IP address */ if (tcp_routines.aa_setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, SIZEOF(on)) == -1) { errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); (void)tcp_routines.aa_close(lsock); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return 0; } if (-1 == tcp_routines.aa_bind(lsock, tcpptr->ai.ai_addr, tcpptr->ai.ai_addrlen)) { errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); (void)tcp_routines.aa_close(lsock); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return 0; } /* establish a queue of length 5 for incoming connections */ if (tcp_routines.aa_listen(lsock, 5) == -1) { errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); (void)tcp_routines.aa_close(lsock); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return 0; } /* create an extra device for the listening socket (device * name is the user-specified device name with three ^A's * appended). We need this device to be on the io_log_name * list so that it gets closed automatically when the user's * program exits. */ ldev_name.addr=buf; memcpy(ldev_name.addr, dev->dollar_io, dev->len); memcpy(ldev_name.addr+dev->len, ones, 3); ldev_name.len = dev->len + 2; ldev = get_log_name(&ldev_name, INSERT); /* copy all state information from the current device */ /* io descriptor */ ldev->iod = (io_desc *)malloc(SIZEOF(io_desc)); memcpy(ldev->iod, dev->iod, SIZEOF(io_desc)); ldev->iod->state = dev_open; ldev->iod->pair.in = ldev->iod; ldev->iod->pair.out = ldev->iod; /* tcp-specific information */ ldev->iod->dev_sp = (void *)malloc(SIZEOF(d_tcp_struct)); lsock_tcp=(d_tcp_struct *)ldev->iod->dev_sp; memcpy(lsock_tcp, tcpptr, SIZEOF(d_tcp_struct)); lsock_tcp->socket = lsock; ldev->iod->state = dev_open; /* add to our list of tcp listening sockets */ new_lsock = (lsock_rec *)malloc(SIZEOF(lsock_rec)); new_lsock->socket = lsock; new_lsock->ai = tcpptr->ai; new_lsock->sas = tcpptr->sas; new_lsock->ai.ai_addr = (struct sockaddr *)(&new_lsock->sas); new_lsock->next = lsock_list; new_lsock->ldev = ldev; lsock_list = new_lsock; return lsock; } void iotcp_rmlsock(io_desc *iod) { lsock_rec *ls, *prev, *next; d_tcp_struct *tcpptr = (d_tcp_struct *)iod->dev_sp; for (prev = NULL, ls = lsock_list; ls != NULL;) { next = ls->next; /* Actually it's enough to just compare the port number, however extracting port from * sas needs to call getnameinfo(). Same sas can guarantee the same port, so * it's enough to use sas to detect whether the device is what we want to delete */ if (0 == memcmp(&(tcpptr->sas), &(ls->sas), SIZEOF(tcpptr->sas))) { if (prev) prev->next = ls->next; else lsock_list = ls->next; tcp_routines.aa_close(ls->socket); ls->ldev->iod->state = dev_closed; free(ls); } else prev = ls; ls = next; } } fis-gtm-V6.0-003/sr_port/iotcp_open.c0000644000032200000250000003046712201176157016351 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* iotcp_open.c - open a TCP/IP connection * Parameters- * dev - the logical name associated with this socket (ignored by this routine). * pp->str.addr - device parameters. The "stream" parameter is required. * file_des - unused. (UNIX only) * mspace - unused. * t - maximum time to wait for a connection (in ms). * * Returns- * non-zero - socket successfully opened and ready for I/O * zero - open operation failed or timed out. */ #include "mdef.h" #include #include "gtm_fcntl.h" #include "gtm_time.h" #include "gtm_socket.h" #include "gtm_netdb.h" /* gtm_netdb must be in front so that AI_V4MAPPED will be defined */ #include "gtm_ipv6.h" #include "gtm_inet.h" #include "gtm_ctype.h" #include "gtm_string.h" #include "gtm_stdio.h" #include "copy.h" #include "gt_timer.h" #include "io.h" #include "iotimer.h" #include "iotcp_select.h" #include "iotcpdef.h" #include "iotcpdefsp.h" #include "iotcproutine.h" #include "io_params.h" #include "stringpool.h" #include "outofband.h" #include "wake_alarm.h" #include "util.h" GBLREF tcp_library_struct tcp_routines; GBLREF bool out_of_time; GBLREF volatile int4 outofband; LITREF unsigned char io_params_size[]; error_def(ERR_DEVPARMNEG); error_def(ERR_GETADDRINFO); error_def(ERR_GETNAMEINFO); error_def(ERR_INVADDRSPEC); error_def(ERR_INVPORTSPEC); error_def(ERR_IPADDRREQ); error_def(ERR_OPENCONN); error_def(ERR_SOCKACPT); error_def(ERR_SOCKINIT); error_def(ERR_SOCKPARMREQ); error_def(ERR_SOCKWAIT); error_def(ERR_TEXT); short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 timeout) { boolean_t no_time_left = FALSE, timed; char addr[SA_MAXLEN + 1], *errptr, sockaddr[SA_MAXLEN + 1], temp_addr[SA_MAXLEN + 1], temp_ch; char ipname[SA_MAXLEN]; unsigned char ch, len; int4 length, width; unsigned short port; int4 errlen, msec_timeout; GTM_SOCKLEN_TYPE size; int ii, status, on = 1, p_offset = 0, temp_1 = -2; TID timer_id; ABS_TIME cur_time, end_time, time_for_read, lcl_time_for_read; d_tcp_struct *tcpptr, newtcp; io_desc *ioptr; struct sockaddr_storage peer_sas; /* socket address + port */ fd_set tcp_fd; int lsock; short retry_num; const char *terrptr; int errcode; char port_buffer[NI_MAXSERV]; int port_len; struct addrinfo *ai_ptr = NULL, *remote_ai_ptr = NULL, *tmp_ai_ptr, hints; int host_len; /* addr_len + port_len + delimeters */ int af; int test_ipv6_sd; #ifdef DEBUG_TCP PRINTF("iotcp_open.c >>> tt = %d\n", t); #endif ioptr = dev->iod; assert((params) *(pp->str.addr + p_offset) < (unsigned char)n_iops); assert(0 != ioptr); assert(ioptr->state >= 0 && ioptr->state < n_io_dev_states); assert(tcp == ioptr->type); if (dev_never_opened == ioptr->state) { ioptr->dev_sp = (void *)malloc(SIZEOF(d_tcp_struct)); memset(ioptr->dev_sp, 0, SIZEOF(d_tcp_struct)); } tcpptr = (d_tcp_struct *)ioptr->dev_sp; if (dev_never_opened == ioptr->state) { ioptr->state = dev_closed; ioptr->width = TCPDEF_WIDTH; ioptr->length = TCPDEF_LENGTH; ioptr->wrap = TRUE; if (-1 == iotcp_fillroutine()) assert(FALSE); } ioptr->dollar.zeof = FALSE; newtcp = *tcpptr; memcpy(ioptr->dollar.device, LITZERO, SIZEOF(LITZERO)); newtcp.passive = FALSE; while (iop_eol != *(pp->str.addr + p_offset)) { switch (ch = *(pp->str.addr + p_offset++)) { case iop_width: GET_LONG(width, pp->str.addr + p_offset); if (0 == width) newtcp.width = TCPDEF_WIDTH; else if (width > 0) newtcp.width = width; else rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG); break; case iop_length: GET_LONG(length, pp->str.addr + p_offset); if (0 == length) newtcp.length = TCPDEF_LENGTH; else if (length > 0) newtcp.length = length; else rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG); break; case iop_listen: newtcp.passive = TRUE; break; case iop_socket: /* test whether ipv6 socket is supported on local system */ af = ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET); if (AF_INET6 == af) { test_ipv6_sd = tcp_routines.aa_socket(af, SOCK_STREAM, IPPROTO_TCP); if (-1 == test_ipv6_sd) af = AF_INET; else tcp_routines.aa_close(test_ipv6_sd); } len = *(pp->str.addr + p_offset); memset(sockaddr, 0, SA_MAXLEN + 1); memcpy(sockaddr, pp->str.addr + p_offset + 1, (len <= USR_SA_MAXLITLEN) ? len : USR_SA_MAXLITLEN); *temp_addr = '\0'; *addr = '\0'; port = 0; if (SSCANF(sockaddr, "%[^,], %hu", temp_addr, &port) < 2) { if (SSCANF(sockaddr, ",%hu", &port) < 1) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC); return FALSE; } SERVER_HINTS(hints, af); port_len = 0; I2A(port_buffer, port_len, port); port_buffer[port_len]='\0'; if (0 != (errcode = getaddrinfo(NULL, port_buffer, &hints, &ai_ptr))) { RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode); return FALSE; } memcpy(&(newtcp.ai), ai_ptr, SIZEOF(*ai_ptr)); memcpy(&(newtcp.sas), ai_ptr->ai_addr, ai_ptr->ai_addrlen); freeaddrinfo(ai_ptr); newtcp.ai.ai_addr = (struct sockaddr*)(&newtcp.sas); } else { /* client side (connection side) */ SPRINTF(addr, "%s", temp_addr); SPRINTF(port_buffer, "%hu", port); CLIENT_HINTS_AF(hints, af); if (0 != (errcode = getaddrinfo(addr, port_buffer, &hints, &remote_ai_ptr))) { if(AF_INET6 == af) { af = AF_INET; CLIENT_HINTS_AF(hints, af); errcode = getaddrinfo(addr, port_buffer, &hints, &remote_ai_ptr); } if(errcode) { RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode); return FALSE; } } memcpy(&(newtcp.ai), remote_ai_ptr, SIZEOF(struct addrinfo)); memcpy(&(newtcp.sas), remote_ai_ptr->ai_addr, remote_ai_ptr->ai_addrlen); newtcp.ai.ai_addr = (struct sockaddr*)(&newtcp.sas); freeaddrinfo(remote_ai_ptr); } break; case iop_exception: ioptr->error_handler.len = *(pp->str.addr + p_offset); ioptr->error_handler.addr = (char *)(pp->str.addr + p_offset + 1); s2pool(&ioptr->error_handler); break; default: break; } p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ? (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]); } /* the previous check if ((0 == newtcp.sin.sin_port) && (0 == newtcp.sin.sin_addr.s_addr)) is no longer needed as * getaddrinfo() will return error for the above case */ /* active connection must have a complete address specification */ if (dev_closed == ioptr->state) { if (newtcp.passive) /* server side */ { /* no listening socket for this addr? make one. */ memcpy(ioptr->dev_sp, &newtcp, SIZEOF(d_tcp_struct)); if (!(lsock = iotcp_getlsock(dev))) return FALSE; /* could not create listening socket */ timer_id = (TID)iotcp_open; time_for_read.at_sec = ((0 == timeout) ? 0 : 1); time_for_read.at_usec = 0; while (TRUE) { out_of_time = FALSE; if (NO_M_TIMEOUT == timeout) { timed = FALSE; msec_timeout = NO_M_TIMEOUT; } else { timed = TRUE; msec_timeout = timeout2msec(timeout); if (msec_timeout > 0) { /* there is time to wait */ sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, msec_timeout, &end_time); start_timer(timer_id, msec_timeout, wake_alarm, 0, NULL); } else out_of_time = TRUE; } for (status = 0; 0 == status; ) { FD_ZERO(&tcp_fd); FD_SET(lsock, &tcp_fd); /* * Note: the check for EINTR from the select below should remain, as aa_select is a * function, and not all callers of aa_select behave the same when EINTR is returned. */ lcl_time_for_read = time_for_read; status = tcp_routines.aa_select(lsock + 1, (void *)&tcp_fd, (void *)0, (void *)0, &lcl_time_for_read); if (0 > status) { if (EINTR == errno && FALSE == out_of_time) /* interrupted by a signal which is not OUR timer */ status = 0; else break; } if (outofband) break; if (timed) { if (msec_timeout > 0) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (cur_time.at_sec <= 0) { out_of_time = TRUE; cancel_timer(timer_id); break; } } else break; } } if (timed) { if (0 != msec_timeout) { cancel_timer(timer_id); if (out_of_time || outofband) return FALSE; /*if (outofband) outofband_action(FALSE);*/ } } if (0 > status) { errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); iotcp_rmlsock((io_desc *)dev->iod); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr); return FALSE; } size = SIZEOF(struct sockaddr_storage); status = tcp_routines.aa_accept(lsock, (struct sockaddr*)&peer_sas, &size); if (-1 == status) { # ifdef __hpux if (ENOBUFS == errno) continue; # endif errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); iotcp_rmlsock((io_desc *)dev->iod); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr); return FALSE; } newtcp.socket = status; break; } } else /* client side */ { if (NO_M_TIMEOUT != timeout) { msec_timeout = timeout2msec(timeout); sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, msec_timeout, &end_time); } no_time_left = FALSE; temp_1 = 1; do { if (1 != temp_1) tcp_routines.aa_close(newtcp.socket); newtcp.socket = tcp_routines.aa_socket(newtcp.ai.ai_family, newtcp.ai.ai_socktype, newtcp.ai.ai_protocol); if (-1 == newtcp.socket) { errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return FALSE; } /* allow multiple connections to the same IP address */ if (-1 == tcp_routines.aa_setsockopt(newtcp.socket, SOL_SOCKET, SO_REUSEADDR, &on, SIZEOF(on))) { (void)tcp_routines.aa_close(newtcp.socket); errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return FALSE; } size=SIZEOF(newtcp.bufsiz); if (-1 == tcp_routines.aa_getsockopt(newtcp.socket, SOL_SOCKET, SO_RCVBUF, &newtcp.bufsiz, &size)) { (void)tcp_routines.aa_close(newtcp.socket); errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr); return FALSE; } /* * Note: the check for EINTR from the connect need not be converted to an EINTR wrapper macro, * since the connect is not retried on EINTR. */ temp_1 = tcp_routines.aa_connect(newtcp.socket, (struct sockaddr *)&newtcp.sas, newtcp.ai.ai_addrlen); if ((temp_1 < 0) && (ECONNREFUSED != errno) && (EINTR != errno)) { (void)tcp_routines.aa_close(newtcp.socket); errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_OPENCONN, 0, ERR_TEXT, 2, errlen, errptr); return FALSE; } if ((temp_1 < 0) && (EINTR == errno)) { (void)tcp_routines.aa_close(newtcp.socket); return FALSE; } if ((temp_1 < 0) && (NO_M_TIMEOUT != timeout)) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (cur_time.at_sec <= 0) no_time_left = TRUE; } SHORT_SLEEP(100); /* Sleep for 100 ms */ } while ((TRUE != no_time_left) && (temp_1 < 0)); if (temp_1 < 0) /* out of time */ { tcp_routines.aa_close(newtcp.socket); return FALSE; } } memcpy(ioptr->dev_sp, &newtcp, SIZEOF(d_tcp_struct)); ioptr->state = dev_open; } #ifdef DEBUG_TCP PRINTF("%s (%d) <<<\n", __FILE__, tcpptr->socket); #endif return TRUE; } fis-gtm-V6.0-003/sr_port/iotcp_rdone.c0000644000032200000250000000130112201176157016500 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" int iotcp_rdone (mint *v, int4 timeout) /* timeout in seconds */ { mval tmp; int ret; ret = iotcp_readfl(&tmp, 1, timeout); if (ret) *v = (int4)*(unsigned char *)(tmp.str.addr); else *v = -1; return ret; } fis-gtm-V6.0-003/sr_port/iotcp_read.c0000644000032200000250000000113612201176157016312 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" int iotcp_read (mval *v, int4 timeout) { return iotcp_readfl(v, 0, timeout); /* 0 means not fixed length */ } fis-gtm-V6.0-003/sr_port/iotcp_readfl.c0000644000032200000250000001721212201176157016636 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "gtm_stdio.h" #include "gtm_time.h" #include "gtm_inet.h" #include "gtm_string.h" #ifdef UNIX #include "gtm_fcntl.h" #include "eintr_wrappers.h" static int fcntl_res; #endif #include "gt_timer.h" #include "io.h" #include "iotimer.h" #include "iotcpdef.h" #include "iotcp_select.h" #include "iotcproutine.h" #include "stringpool.h" #include "wake_alarm.h" /* Maximum we will read in one read for this device */ #define MAX_READLEN 32767 GBLREF io_pair io_curr_device; GBLREF bool out_of_time; GBLREF spdesc stringpool; GBLREF tcp_library_struct tcp_routines; GBLREF int4 outofband; error_def(ERR_IOEOF); error_def(ERR_TEXT); error_def(ERR_GETSOCKOPTERR); error_def(ERR_SETSOCKOPTERR); int iotcp_readfl(mval *v, int4 width, int4 timeout) /* 0 == width is a flag that the caller is read and the length is not actually fixed */ /* timeout in seconds */ { /* VMS uses the UCX interface; should support others that emulate it */ boolean_t ret, timed, vari; int flags, len, real_errno, save_errno; int i; io_desc *io_ptr; d_tcp_struct *tcpptr; int4 status; int4 msec_timeout; /* timeout in milliseconds */ TID timer_id; ABS_TIME cur_time, end_time, time_for_read, lcl_time_for_read, zero; fd_set tcp_fd; char *errptr; int4 errlen; #ifdef DEBUG_TCP PRINTF("%s >>>\n", __FILE__); #endif assert(stringpool.free >= stringpool.base); assert(stringpool.free <= stringpool.top); if (0 == width) { /* op_readfl won't do this; must be a call from iotcp_read */ vari = TRUE; width = MAX_READLEN; } else { vari = FALSE; width = (width < MAX_READLEN) ? width : MAX_READLEN; } ENSURE_STP_FREE_SPACE(width); io_ptr = io_curr_device.in; assert(dev_open == io_ptr->state); tcpptr = (d_tcp_struct *)(io_ptr->dev_sp); if (io_ptr->dollar.x && (TCP_WRITE == tcpptr->lastop)) { /* switching from write to read */ #ifdef C9A06001531 /* pending change request C9A06-001531 */ if (!io_ptr->dollar.za) iotcp_wteol(1, io_ptr); #endif io_ptr->dollar.x = 0; } tcpptr->lastop = TCP_READ; ret = TRUE; timer_id = (TID)iotcp_readfl; out_of_time = FALSE; time_for_read.at_sec = ((0 == timeout) ? 0 : 1); time_for_read.at_usec = 0; if (NO_M_TIMEOUT == timeout) { timed = FALSE; msec_timeout = NO_M_TIMEOUT; } else { timed = TRUE; msec_timeout = timeout2msec(timeout); if (msec_timeout > 0) { /* there is time to wait */ #ifdef UNIX /* set blocking I/O */ FCNTL2(tcpptr->socket, F_GETFL, flags); if (flags < 0) { save_errno = errno; errptr = (char *)STRERROR(errno); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, LEN_AND_LIT("F_GETFL FOR NON BLOCKING I/O"), save_errno, LEN_AND_STR(errptr)); } FCNTL3(tcpptr->socket, F_SETFL, flags & (~(O_NDELAY | O_NONBLOCK)), fcntl_res); if (fcntl_res < 0) { save_errno = errno; errptr = (char *)STRERROR(errno); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("F_SETFL FOR NON BLOCKING I/O"), save_errno, LEN_AND_STR(errptr)); } #endif sys_get_curr_time(&cur_time); add_int_to_abs_time(&cur_time, msec_timeout, &end_time); start_timer(timer_id, msec_timeout, wake_alarm, 0, NULL); } else out_of_time = TRUE; } for (i = 0, status = 0; status >= 0; ) { FD_ZERO(&tcp_fd); FD_SET(tcpptr->socket, &tcp_fd); assert(0 != FD_ISSET(tcpptr->socket, &tcp_fd)); assert(((1 == time_for_read.at_sec) || (0 == time_for_read.at_sec)) && (0 == time_for_read.at_usec)); /* * the check for EINTR below is valid and should not be converted to an EINTR * wrapper macro, since it might be a timeout. */ lcl_time_for_read = time_for_read; status = tcp_routines.aa_select(tcpptr->socket + 1, (void *)(&tcp_fd), (void *)0, (void *)0, &lcl_time_for_read); if (status > 0) { status = tcp_routines.aa_recv(tcpptr->socket, (char *)(stringpool.free + i), width - i, 0); if ((0 == status) || ((-1 == status) && (ECONNRESET == errno || EPIPE == errno || EINVAL == errno))) { /* lost connection. */ if (0 == status) errno = ECONNRESET; real_errno = errno; status = -2; break; } } if (status < 0) { if (EINTR == errno && FALSE == out_of_time) { /* interrupted by a signal which is not OUR timer, continue looping */ status = 0; } else real_errno = errno; } else real_errno = 0; if (outofband) break; if (timed) { if (msec_timeout > 0) { sys_get_curr_time(&cur_time); cur_time = sub_abs_time(&end_time, &cur_time); if (cur_time.at_sec <= 0) { out_of_time = TRUE; cancel_timer(timer_id); if (status > 0) i += status; break; } } else { if (status > 0) i += status; break; } } if (0 > status) break; i += status; if ((vari && (0 != i)) || (i >= width)) break; } if (EINTR == real_errno) status = 0; /* don't treat a or timeout as an error */ if (timed) { if (0 == msec_timeout) { if (0 == status) ret = FALSE; } else { #ifdef UNIX real_errno = errno; FCNTL3(tcpptr->socket, F_SETFL, flags, fcntl_res); if (fcntl_res < 0) { save_errno = errno; errptr = (char *)STRERROR(errno); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("F_SETFL FOR RESTORING SOCKET OPTIONS"), save_errno, LEN_AND_STR(errptr)); } errno = real_errno; #endif if (out_of_time && (i < width)) ret = FALSE; else cancel_timer(timer_id); } } if (i > 0) { /* there's somthing to return */ v->str.len = i; v->str.addr = (char *)stringpool.free; if (((io_ptr->dollar.x += i) >= io_ptr->width) && (TRUE == io_ptr->wrap)) { io_ptr->dollar.y += (io_ptr->dollar.x / io_ptr->width); if (0 != io_ptr->length) io_ptr->dollar.y %= io_ptr->length; io_ptr->dollar.x %= io_ptr->width; } } else v->str.len = 0; #ifdef DEBUG_TCP PRINTF("%s <<<\n", __FILE__); #endif len = SIZEOF("1,") - 1; if (status >= 0) { /* no real problems */ io_ptr->dollar.za = 0; /* the handling of urgent data doesn't work and never has, the design should be changed to use a /URGENT controlnmemonic * because there is really only one character available at a time zero.at_sec = zero.at_usec = 0; FD_ZERO(&tcp_fd); FD_SET(tcpptr->socket, &tcp_fd); if (tcp_routines.aa_select(tcpptr->socket + 1, (void *)(tcpptr->urgent ? &tcp_fd : 0), (void *)0, (void *)(tcpptr->urgent ? 0 : &tcp_fd), &zero) > 0) { memcpy(io_ptr->dollar.device, "1,", len); if (tcpptr->urgent) { memcpy(&io_ptr->dollar.device[len], "No ",SIZEOF("No ")); len += SIZEOF("No ") - 1; } memcpy(&io_ptr->dollar.device[len], "Urgent Data", SIZEOF("Urgent Data")); } else */ memcpy(io_ptr->dollar.device, "0", SIZEOF("0")); } else { /* there's a significant problem */ if (0 == i) io_ptr->dollar.x = 0; io_ptr->dollar.za = 9; memcpy(io_ptr->dollar.device, "1,", len); errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); memcpy(&io_ptr->dollar.device[len], errptr, errlen); if (io_ptr->dollar.zeof || -1 == status || 0 < io_ptr->error_handler.len) { io_ptr->dollar.zeof = TRUE; rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_IOEOF, 0, ERR_TEXT, 2, errlen, errptr); } else io_ptr->dollar.zeof = TRUE; } return (ret); } fis-gtm-V6.0-003/sr_port/iotcp_use.c0000644000032200000250000000620712201176157016177 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_unistd.h" #include "gtm_inet.h" #include "gtm_iconv.h" #include "gtm_stdio.h" #include "copy.h" #include "io.h" #include "iosp.h" #include "io_params.h" #include "iotcpdef.h" #include "stringpool.h" typedef struct { unsigned short mem; unsigned short grp; } uic_struct; LITREF unsigned char io_params_size[]; void iotcp_use(io_desc *iod, mval *pp) { unsigned char c; int4 length, width; d_tcp_struct *tcpptr, newtcp; int p_offset; error_def(ERR_DEVPARMNEG); error_def(ERR_RMWIDTHPOS); #ifdef DEBUG_TCP PRINTF("%s >>>\n", __FILE__); #endif p_offset = 0; tcpptr = (d_tcp_struct *)iod->dev_sp; /* copy existing parameters */ memcpy(&newtcp, tcpptr, SIZEOF(d_tcp_struct)); while (*(pp->str.addr + p_offset) != iop_eol) { assert((params) *(pp->str.addr + p_offset) < (params) n_iops); switch (c = *(pp->str.addr + p_offset++)) { case iop_width: GET_LONG(width, pp->str.addr + p_offset); if (width == 0) newtcp.width = TCPDEF_WIDTH; else if (width > 0) newtcp.width = width; else rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); break; case iop_length: GET_LONG(length, pp->str.addr + p_offset); if (length == 0) newtcp.length = TCPDEF_LENGTH; else if (length > 0) newtcp.length = length; else rts_error(VARLSTCNT(1) ERR_DEVPARMNEG); break; case iop_urgent: newtcp.urgent = TRUE; break; case iop_nourgent: newtcp.urgent = FALSE; break; case iop_exception: iod->error_handler.len = *(pp->str.addr + p_offset); iod->error_handler.addr = (char *)(pp->str.addr + p_offset + 1); s2pool(&iod->error_handler); break; case iop_ipchset: #if defined(KEEP_zOS_EBCDIC) || defined(VMS) if ( (iconv_t)0 != iod->input_conv_cd ) { ICONV_CLOSE_CD(iod->input_conv_cd); } SET_CODE_SET(iod->in_code_set, (char *)(pp->str.addr + p_offset + 1)); if (DEFAULT_CODE_SET != iod->in_code_set) ICONV_OPEN_CD(iod->input_conv_cd, INSIDE_CH_SET, (char *)(pp->str.addr + p_offset + 1)); #endif break; case iop_opchset: #if defined(KEEP_zOS_EBCDIC) || defined(VMS) if ( (iconv_t)0 != iod->output_conv_cd ) { ICONV_CLOSE_CD(iod->output_conv_cd); } SET_CODE_SET(iod->out_code_set, (char *)(pp->str.addr + p_offset + 1)); if (DEFAULT_CODE_SET != iod->out_code_set) ICONV_OPEN_CD(iod->output_conv_cd, (char *)(pp->str.addr + p_offset + 1), INSIDE_CH_SET); #endif break; default: break; } p_offset += ((IOP_VAR_SIZE == io_params_size[c]) ? (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[c]); } /* commit changes */ memcpy(tcpptr, &newtcp, SIZEOF(d_tcp_struct)); #ifdef DEBUG_TCP PRINTF("%s <<<\n", __FILE__); #endif return; } fis-gtm-V6.0-003/sr_port/iotcp_write.c0000644000032200000250000000434512201176157016536 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_socket.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "gtm_inet.h" #include #include "io.h" #include "iotcpdef.h" #include "iotcpdefsp.h" #include "iotcproutine.h" GBLREF io_pair io_curr_device; GBLREF tcp_library_struct tcp_routines; error_def(ERR_SOCKWRITE); error_def(ERR_TEXT); void iotcp_write(mstr *v) { io_desc *iod; char *out; int inlen, outlen, size; d_tcp_struct *tcpptr; char *errptr; int4 errlen; #ifdef DEBUG_TCP PRINTF("%s >>>\n", __FILE__); #endif iod = io_curr_device.out; tcpptr = (d_tcp_struct *)iod->dev_sp; tcpptr->lastop = TCP_WRITE; memcpy(iod->dollar.device, LITZERO, SIZEOF(LITZERO)); inlen = v->len; outlen = iod->width - iod->dollar.x; if (!iod->wrap && inlen > outlen) inlen = outlen; if (!inlen) return; for (out = v->addr; ; out += size) { if (outlen > inlen) outlen = inlen; if ((size = tcp_routines.aa_send(tcpptr->socket, out, outlen, (tcpptr->urgent ? MSG_OOB : 0))) == -1) { iod->dollar.za = 9; memcpy(iod->dollar.device, LITONE_COMMA, SIZEOF(LITONE_COMMA)); errptr = (char *)STRERROR(errno); errlen = STRLEN(errptr); memcpy(&iod->dollar.device[SIZEOF(LITONE_COMMA) - 1], errptr, errlen); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKWRITE, 0, ERR_TEXT, 2, errlen, errptr); } assert(size == outlen); iod->dollar.x += size; if ((inlen -= size) <= 0) break; iod->dollar.x = 0; /* don't use wteol to terminate wrapped records for fixed. */ iod->dollar.y++; /* \n is reserved as an end-of-rec delimiter for variable format */ if (iod->length) /* and fixed format requires no padding for wrapped records */ iod->dollar.y %= iod->length; outlen = iod->width; } iod->dollar.za = 0; #ifdef DEBUG_TCP PRINTF("%s <<<\n", __FILE__); #endif return; } fis-gtm-V6.0-003/sr_port/iotcp_wteol.c0000644000032200000250000000146412201176157016535 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include #include #include "gtm_stdio.h" #include "gtm_string.h" #include "gtm_socket.h" #include "gtm_inet.h" #include "io.h" #include "iotcpdef.h" #include "iotcpdefsp.h" #include "iotcproutine.h" void iotcp_wteol(int4 x, io_desc *iod) { /* pending a change request C9A06-001531 */ return; } fis-gtm-V6.0-003/sr_port/iotcp_wtff.c0000644000032200000250000000172412201176157016350 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "io.h" #define FORM_FEED "\014" GBLREF io_pair io_curr_device; void iotcp_wtff(void) { mstr temp; io_desc *iod; #ifdef DEBUG_TCP PRINTF("%s >>>\n",__FILE__); #endif iod = io_curr_device.out; #ifdef C9A06001531 iotcp_wteol(1,iod); #endif temp.len = SIZEOF(FORM_FEED) - 1; temp.addr = FORM_FEED; iotcp_write(&temp); #ifdef C9A06001531 iotcp_wteol(1,iod); #endif iod->dollar.x = 0; iod->dollar.y = 0; #ifdef DEBUG_TCP PRINTF("%s <<<\n",__FILE__); #endif } fis-gtm-V6.0-003/sr_port/iotcp_wtone.c0000644000032200000250000000136212201176157016534 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "io.h" void iotcp_wtone(int ch) { mstr temp; char c; #ifdef DEBUG_TCP PRINTF("%s >>>\n",__FILE__); #endif c = (char)ch; temp.len = 1; temp.addr = &c; iotcp_write(&temp); #ifdef DEBUG_TCP PRINTF("%s <<<\n",__FILE__); #endif return; } fis-gtm-V6.0-003/sr_port/iotcpdef.h0000644000032200000250000000631112201176157016003 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __IOTCPDEF_H__ #define __IOTCPDEF_H__ #include "gtm_inet.h" #include "gtm_socket.h" /* for NI_MAXHOST */ #include "gtm_netdb.h" /* iotcpdef.h UNIX - TCP header file */ #define TCPDEF_WIDTH 255 #define TCPDEF_LENGTH 66 #define TCP_NOOP 0 #define TCP_WRITE 1 #define TCP_READ 2 #define SA_MAXLEN NI_MAXHOST /* NI_MAXHOST is 1025, large enough to hold any IPV6 address format * e.g.(123:567:901:345:215:0:0:0) */ #define SA_MAXLITLEN NI_MAXHOST /* large enough to hold any host name, e.g. * host name google: dfw06s16-in-x12.1e100.net */ #define USR_SA_MAXLITLEN 128 /* maximum size of host GTM user can specify * the reason why the number is so small is because the host name size * is stored as one byte in socket parameter list (refer to iosocket_use) */ #ifdef VMS #define VMS_MAX_TCP_IO_SIZE (64 * 1024 - 512) /* Hard limit for TCP send or recv size. On some implementations, the limit is * 64K - 1, on others it is 64K - 512. We take the conservative approach and * choose the lower limit */ #endif #define DOTCPSEND(SDESC, SBUFF, SBUFF_LEN, SFLAGS, RC) \ { \ ssize_t gtmioStatus; \ size_t gtmioBuffLen; \ size_t gtmioChunk; \ sm_uc_ptr_t gtmioBuff; \ \ gtmioBuffLen = SBUFF_LEN; \ gtmioBuff = (sm_uc_ptr_t)(SBUFF); \ for (;;) \ { \ gtmioChunk = gtmioBuffLen VMS_ONLY(> VMS_MAX_TCP_IO_SIZE ? VMS_MAX_TCP_IO_SIZE : gtmioBuffLen); \ if ((ssize_t)-1 != (gtmioStatus = tcp_routines.aa_send(SDESC, gtmioBuff, gtmioChunk, SFLAGS))) \ { \ gtmioBuffLen -= gtmioStatus; \ if (0 == gtmioBuffLen) \ break; \ gtmioBuff += gtmioStatus; \ } \ else if (EINTR != errno) \ break; \ } \ if ((ssize_t)-1 == gtmioStatus) /* Had legitimate error - return it */ \ RC = errno; \ else if (0 == gtmioBuffLen) \ RC = 0; \ else \ RC = -1; /* Something kept us from sending what we wanted */ \ } /* ***************************************************** */ /* *********** structures for TCP driver *************** */ /* ***************************************************** */ typedef struct { char saddr[SA_MAXLEN]; /* socket address */ struct sockaddr_storage sas; /* socket address + port */ struct addrinfo ai; unsigned char lastop; int bufsiz; /* OS internal buffer size */ int socket; /* socket descriptor */ int4 width; int4 length; bool passive; /* passive connection */ bool urgent; /* urgent data mode */ } d_tcp_struct; /* tcp */ #endif fis-gtm-V6.0-003/sr_port/iotcpdefsp.h0000644000032200000250000000120512201176157016343 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #define ASCII_LITONE_COMMA "1," #define EBCDIC_LITONE_COMMA "\361\153" #define ASCII_LITZERO "0" #define EBCDIC_LITZERO "\360" #define LITONE_COMMA ASCII_LITONE_COMMA #define LITZERO ASCII_LITZERO fis-gtm-V6.0-003/sr_port/iotcproutine.h0000644000032200000250000000203512201176157016731 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* pointers for tcp/ip routines */ typedef struct { int (*aa_accept)(); int (*aa_bind)(); int (*aa_close)(); int (*aa_connect)(); int (*aa_getsockopt)(); int (*aa_getsockname)(); int (*aa_listen)(); int (*aa_recv)(); int (*aa_select)(); int (*aa_send)(); int (*aa_setsockopt)(); int (*aa_shutdown)(); int (*aa_socket)(); bool using_tcpware; /* use tcpware(1) or ucx(0) */ }tcp_library_struct; fis-gtm-V6.0-003/sr_port/iotimer.h0000644000032200000250000000073612201176157015663 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #define NO_M_TIMEOUT 0x0007FFFE fis-gtm-V6.0-003/sr_port/iott_dummy.c0000644000032200000250000000110612201176157016370 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" short iott_dummy(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout) { return 0; } fis-gtm-V6.0-003/sr_port/iott_escape.c0000644000032200000250000000460112201176157016500 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "iottdef.h" #ifdef KEEP_zOS_EBCDIC #include "gtm_unistd.h" #endif uchar_ptr_t iott_escape(uchar_ptr_t strin, uchar_ptr_t strtop, io_desc *io_ptr) { unsigned char *str; unsigned char esc_type; #ifdef KEEP_zOS_EBCDIC error_def(ERR_ASC2EBCDICCONV); if ((DEFAULT_CODE_SET != io_ptr->in_code_set) && ( -1 == __etoa_l((char *)strin, strtop - strin) )) rts_error(VARLSTCNT(4) ERR_ASC2EBCDICCONV, 2, LEN_AND_LIT("__etoa_l")); #endif str = strin; esc_type = io_ptr->esc_state; while (esc_type < FINI) { switch (esc_type) { case START: assert(*str == ESC); esc_type = AFTESC; break; case AFTESC: switch(*str) { case ';': case '?': esc_type = SEQ2; break; case 'O': esc_type = SEQ4; break; case '[': esc_type = SEQ1; break; default: if (*str >= 0x30 && *str < 0x7F) esc_type = FINI; else if (*str > 0x1F && *str < 0x30) esc_type = SEQ2; else esc_type = BADESC; break; } break; case SEQ1: if (*str < 0x30 && *str > 0x1F) esc_type = SEQ3; else if (*str > 0x3F && *str < 0x7F) esc_type = FINI; else if (*str > 0x3F || *str < 0x30) esc_type = BADESC; break; case SEQ2: if (*str >= 0x30 && *str < 0x7F) esc_type = FINI; else if (*str > 0x2F || *str < 0x20) esc_type = BADESC; break; case SEQ3: if (*str > 0x3F && *str < 0x7F) esc_type = FINI; else if (*str > 0x2F || *str < 0x20) esc_type = BADESC; case SEQ4: if (*str >= 0x40 && *str < 0x7F) esc_type = FINI; else if (*str > 0x2F || *str < 0x20) esc_type = BADESC; break; default: GTMASSERT; } if (esc_type == BADESC || ++str >= strtop) break; } io_ptr->esc_state = esc_type; #ifdef KEEP_zOS_EBCDIC if ((DEFAULT_CODE_SET != io_ptr->in_code_set) && ( -1 == __atoe_l((char *)strin, strtop - strin) )) rts_error(VARLSTCNT(4) ERR_ASC2EBCDICCONV, 2, LEN_AND_LIT("__atoe_l")); #endif return str; } fis-gtm-V6.0-003/sr_port/iott_wrterr.c0000644000032200000250000000126212201176157016565 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "iott_wrterr.h" GBLREF int iott_write_error; void iott_wrterr(void) { int status; error_def(ERR_TERMWRITE); status = iott_write_error; iott_write_error = 0; rts_error(VARLSTCNT(3) ERR_TERMWRITE, 0, status); } fis-gtm-V6.0-003/sr_port/iott_wrterr.h0000644000032200000250000000107212201176157016571 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef IOTT_WRTERR_H_INCLUDED #define IOTT_WRTERR_H_INCLUDED void iott_wrterr(void); #endif /* IOTT_WRTERR_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/iott_wteol.c0000644000032200000250000000351412201176157016374 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #ifdef UNIX #include "error.h" #endif #include "io.h" #include "iottdef.h" /* essentially the same as ionl_wteol */ void iott_wteol(int4 val, io_desc *io_ptr) { mstr eol; int eol_cnt; UNIX_ONLY(d_tt_struct *tt_ptr;) UNIX_ONLY(error_def(ERR_ZINTRECURSEIO);) assert(val); #ifdef UNIX tt_ptr = (d_tt_struct *)io_ptr->dev_sp; if (tt_ptr->mupintr) rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO); #endif io_ptr->esc_state = START; eol.len = STRLEN(NATIVE_TTEOL); eol.addr = (char *)NATIVE_TTEOL; for (eol_cnt = val; eol_cnt--; ) { io_ptr->dollar.x = 0; /* so that iott_write doesn't try to wrap (based on escape state and width) */ iott_write(&eol); } /* $X is maintained in VMS without the below assignment (resetting to 0) because the NATIVE_TTEOL is \015\012 * and the (\015) triggers appropriate maintenance of $X. In UNIX, NATIVE_TTEOL is \012, so * FILTER=CHARACTER effectively turns off all $X maintenance (except for WRAP logic). * In VMS the below assignment is not necessary, but harmless; it is always logically correct. */ io_ptr->dollar.x = 0; if (!(io_ptr->write_filter & CHAR_FILTER)) { /* If no FILTER and EOL, also maintain $Y; * If FILTER, dollarx() of the linefeed character \012 takes care of this maintenance. */ io_ptr->dollar.y += val; if (io_ptr->length) io_ptr->dollar.y %= io_ptr->length; } return; } fis-gtm-V6.0-003/sr_port/iott_wtff.c0000644000032200000250000000173612201176157016214 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "iottdef.h" #include "io_params.h" GBLREF io_pair io_curr_device; static readonly unsigned char home_param_list[] = { (unsigned char)iop_x, 0, 0, 0, 0, (unsigned char)iop_y, 0, 0, 0, 0, (unsigned char)iop_clearscreen, (unsigned char)iop_eol }; static readonly mval home_params = DEFINE_MVAL_LITERAL(MV_STR, 0, 0, SIZEOF(home_param_list) - 1, (char *)home_param_list, 0, 0); void iott_wtff(void) { io_curr_device.out->esc_state = START; iott_use(io_curr_device.out, &home_params); } fis-gtm-V6.0-003/sr_port/iott_wtone.c0000644000032200000250000000251112201176157016372 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #ifdef UNICODE_SUPPORTED #include "gtm_utf8.h" #endif GBLREF io_pair io_curr_device; GBLREF boolean_t gtm_utf8_mode; LITREF mstr chset_names[]; void iott_wtone(int v) { mstr temp; char p[1]; #ifdef UNICODE_SUPPORTED unsigned char utf_buf[GTM_MB_LEN_MAX], *up; #endif io_desc *iod; UNICODE_ONLY(error_def(ERR_BADCHSET);) if (!gtm_utf8_mode UNICODE_ONLY(|| CHSET_M == io_curr_device.out->ochset)) { p[0] = (char)v; temp.len = 1; temp.addr = p; UNICODE_ONLY(temp.char_len = 1;) } #ifdef UNICODE_SUPPORTED else if (CHSET_UTF8 == io_curr_device.out->ochset) { up = UTF8_WCTOMB(v, utf_buf); temp.len = INTCAST(up - utf_buf); temp.addr = (char *)&utf_buf[0]; } else rts_error(VARLSTCNT(4) ERR_BADCHSET, 2, chset_names[io_curr_device.out->ochset].len, chset_names[io_curr_device.out->ochset].addr); #endif iott_write(&temp); return; } fis-gtm-V6.0-003/sr_port/ious_close.c0000644000032200000250000000123312201176157016343 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "iousdef.h" void ious_close(io_desc *iod, mval *pp) { assert(iod->state == dev_open); ((void(*)())(((d_us_struct*)(iod->dev_sp))->disp->close))(); iod->state = dev_closed; } fis-gtm-V6.0-003/sr_port/ious_dummy.c0000644000032200000250000000110612201176157016370 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" short ious_dummy(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout) { return 0; } fis-gtm-V6.0-003/sr_port/ious_flush.c0000644000032200000250000000116712201176157016365 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "iousdef.h" void ious_flush(io_desc *iod) { assert(iod->state == dev_open); ((void(*)())(((d_us_struct*)(iod->dev_sp))->disp->flush))(); } fis-gtm-V6.0-003/sr_port/ious_use.c0000644000032200000250000000117512201176157016037 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "iousdef.h" void ious_use(io_desc *iod, mval *pp) { assert(iod->state == dev_open); ((void(*)())(((d_us_struct*)(iod->dev_sp))->disp->use))(); } fis-gtm-V6.0-003/sr_port/ious_wteol.c0000644000032200000250000000120612201176157016370 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2004 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "iousdef.h" void ious_wteol(int4 x, io_desc *iod) { assert(iod->state == dev_open); ((void(*)())(((d_us_struct*)(iod->dev_sp))->disp->wteol))(x); } fis-gtm-V6.0-003/sr_port/ious_wtff.c0000644000032200000250000000115312201176157016205 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "io.h" #include "iousdef.h" GBLREF io_pair io_curr_device; void ious_wtff() { (((d_us_struct*)(io_curr_device.out->dev_sp))->disp->wtff)(); } fis-gtm-V6.0-003/sr_port/iousdef.h0000644000032200000250000000130712201176157015644 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #define MAX_US_READ 128 /* ***************************************************** */ /* ********* structure for user device driver ********** */ /* ***************************************************** */ typedef struct { dev_dispatch_struct *disp; }d_us_struct; fis-gtm-V6.0-003/sr_port/is_canonic_name.c0000644000032200000250000002231712201176157017312 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_ctype.h" #include "is_canonic_name.h" #ifdef DEBUG #include "subscript.h" #endif #ifdef UNICODE_SUPPORTED #include "gtm_utf8.h" GBLREF boolean_t badchar_inhibit; error_def(ERR_BADCHAR); #endif /* * ----------------------------------------------- * is_canonic_name() * validate a variable name * * Arguments: * src - Pointer to Source Name string mval * subscripts - Pointer to sequence number of subscript to find & return of subscript count * start_off - Pointer offset of the component requested by op_fnqsubscript * stop_off - Pointer offset of the end of the component requested by op_fnqsubscript * Return: * boolean_t - TRUE indicates good name; FALSE indicates defective * ----------------------------------------------- */ boolean_t is_canonic_name(mval *src, int *subscripts, int *start_off, int *stop_off) { /* subscripts is overloaded - out to op_fnqlength, which doesn't use the last 2 arguments & in from op_fnqsubscript */ char term; int envpart; boolean_t instring; int isrc; boolean_t keep_quotes; char letter; int point; char previous; int seq; int start; int state; int stop; int subs_count; int utf8_len; /* state: * 0 before start of name * 1 found ^ allow environment * 2 dispatch for starting a component * 3 in string * 4 in number * 5 expect first letter of name * 6 expect next letter of name * 7 in $CHAR() * 8 at end of processing */ MV_FORCE_STR(src); seq = *subscripts; keep_quotes = FALSE; start = stop = 0; state = 0; subs_count = -1; for (isrc = 0; isrc < src->str.len; ) { letter = src->str.addr[isrc]; switch (state) { case 0: /* start of name */ if ('^' == letter) /* before start of name */ { state = 1; /* check for environment */ break; } if (('%' == letter) || ISALPHA_ASCII(letter)) { if (0 == seq) start = isrc; state = 6; /* rest of name */ break; } return FALSE; case 1: /* global name */ if (('%' == letter) ||ISALPHA_ASCII(letter)) /* found ^ allow environment */ { /* found ^ allow environment */ if (0 == seq) start = isrc; state = 6; /* rest of name */ break; } if (('|' == letter) || ('[' == letter)) { term = (letter == '[') ? ']' : letter; envpart = 0; if (subs_count == seq) start = isrc + 1; state = 2; /* process environment */ break; } return FALSE; case 2: /* dispatch for starting a component */ point = 0; instring = FALSE; if (envpart > 1) return FALSE; /* too many environment components */ if (')' == term) subs_count++; /* new subscript */ else envpart++; /* next environment component */ if ((subs_count == seq) && (0 == stop)) start = isrc; if ('"' == letter) { if ((subs_count == seq) && (1 == envpart)) start++; instring = TRUE; state = 3; /* string */ break; } if ('$' ==letter) { state = 7; /* $[z]char() */ break; } if ('0' == letter) /* Canonic number cannot start with 0 unless is single char */ { if (++isrc < src->str.len) letter = src->str.addr[isrc]; else return FALSE; /* Cannot end with "0" */ if (term == letter) state = (')' == term) ? 8 : 5; /* end or name */ else if (',' != letter) return FALSE; /* Not a single char number */ if ((subs_count == seq) && (0 == stop)) stop = isrc; break; } if (('-' == letter) || ('.' == letter) || ISDIGIT_ASCII(letter)) { if ('.' == letter) point++; previous = letter; state = 4; /* numeric */ break; } return FALSE; case 3: /* [quoted] string */ if ('"' == letter) /* in string */ { instring = !instring; if (instring) break; if (isrc + 1 >= src->str.len) return FALSE; if ('_' != src->str.addr[isrc + 1]) break; isrc++; if (++isrc < src->str.len) letter = src->str.addr[isrc]; else return FALSE; if ('$' != letter) return FALSE; state = 7; /* $[z]char() */ break; } if (!instring) { if (',' == letter) state = 2; /* on to next */ else if (term == letter) state = (')' == term) ? 8 : 5; /* end or name */ else return FALSE; if ((subs_count == seq) && (0 == stop)) /* Not returning 2nd env part - maybe problem */ stop = isrc - (keep_quotes ? 0 : 1); } break; case 4: /* numeric */ if (ISDIGIT_ASCII(letter)) /* in number */ { if (('-' == previous) && ('0' == letter)) return FALSE; previous = letter; break; } if ('.' == letter) { if ((++point > 1)) return FALSE; previous = letter; break; } if (point && ('0' == previous)) return FALSE; if (',' == letter) state = 2; /* next */ else if (term == letter) state = (')' == term) ? 8 : 5; /* end or name */ else return FALSE; if ((subs_count == seq) && (0 == stop)) stop = isrc; previous = letter; break; case 5: /* expect first letter of name */ if (('%' == letter) || ISALPHA_ASCII(letter)) { if (0 == seq) start = isrc; state = 6; /* rest of name */ break; } return FALSE; case 6: /* expect next letter of name */ if ('(' == letter) { term = ')'; envpart = 1; subs_count = 0; state = 2; /* done with name */ if (0 == seq) stop = isrc; } else if (!ISALNUM_ASCII(letter)) return FALSE; break; case 7: /* $[Z]CHAR() */ previous = letter; /* in $CHAR() - must be ASCII */ if (('Z' == letter) || ('z' == letter)) { if (++isrc < src->str.len) letter = src->str.addr[isrc]; else return FALSE; if ('z' == previous) previous = 'Z'; } if (!(('C' == letter) || ('c' == letter))) return FALSE; if (++isrc < src->str.len) letter = src->str.addr[isrc]; else return FALSE; if (('H' == letter) || ('h' == letter)) { if (++isrc < src->str.len) letter = src->str.addr[isrc]; else return FALSE; if (!(('A' == letter) || ('a' == letter) || (('(' == letter) && ('Z' == previous)))) return FALSE; } else if ('Z' == previous) return FALSE; if ('(' != letter) { if (++isrc < src->str.len) letter = src->str.addr[isrc]; else return FALSE; if (!('R' == letter) || ('r' == letter)) return FALSE; if (++isrc < src->str.len) letter = src->str.addr[isrc]; else return FALSE; } if ('(' != letter) return FALSE; if (subs_count == seq) keep_quotes = TRUE; for (++isrc ;isrc < src->str.len; isrc++) { letter = src->str.addr[isrc]; if (ISDIGIT_ASCII(letter)) continue; if (!((',' == letter) || (')' == letter))) return FALSE; previous = letter; if (++isrc < src->str.len) letter = src->str.addr[isrc]; else return FALSE; if (')' == previous) break; if (!ISDIGIT_ASCII(letter)) return FALSE; } if (isrc > src->str.len) return FALSE; if ('_' == letter) { if (++isrc < src->str.len) letter = src->str.addr[isrc]; else return FALSE; if ('$' == letter) break; if ('"' != letter) return FALSE; instring = TRUE; state = 3; /* back to string */ break; } if (',' == letter) state = 2; else if (term == letter) state = (')' == term) ? 8 : 5; /* end or name */ else return FALSE; if ((subs_count == seq) && (0 == stop)) stop = isrc - (keep_quotes ? 0 : 1); /* Not returning 2nd env part - maybe problem */ break; case 8: /* end of subscript but no closing paren - ")" */ return FALSE; break; } # ifdef UNICODE_SUPPORTED if (!gtm_utf8_mode || (0 == (letter & 0x80))) isrc++; else if (0 < (utf8_len = UTF8_MBFOLLOW(&src->str.addr[isrc++]))) { /* multi-byte increment */ assert(4 > utf8_len); if (0 > utf8_len) rts_error(VARLSTCNT(6) ERR_BADCHAR, 4, 1, &src->str.addr[isrc - 1], LEN_AND_LIT(UTF8_NAME)); isrc += utf8_len; } # endif NON_UNICODE_ONLY(isrc++); } if ((8 != state) && (6 != state)) return FALSE; if ((0 <= seq) && (0 == stop)) stop = src->str.len - (8 == state ? 1 : 0); if (keep_quotes && ('"' == src->str.addr[start - 1])) start--; assert((0 < subs_count) || ((6 == state) && (-1 == subs_count))); if (6 == state) subs_count = 0; assert((('^' == src->str.addr[0]) ? MAX_GVSUBSCRIPTS : MAX_LVSUBSCRIPTS) > subs_count); assert((0 < isrc) && (isrc == src->str.len)); assert(stop <= isrc); assert((0 <= start) && (start <= stop)); *subscripts = subs_count; *start_off = start; *stop_off = stop; return TRUE; } fis-gtm-V6.0-003/sr_port/is_canonic_name.h0000644000032200000250000000103312201176157017307 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ boolean_t is_canonic_name(mval *src, int *subscripts, int *start_off, int *stop_off); fis-gtm-V6.0-003/sr_port/is_equ.c0000644000032200000250000000273612201176157015475 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" int is_equ(mval *u,mval *v) { int land, lor, utyp, vtyp; utyp = u->mvtype; vtyp = v->mvtype; land = utyp & vtyp; lor = utyp | vtyp; if ((land & MV_NM) != 0 && (lor & MV_NUM_APPROX) == 0) { /* at this point, the mval's are both exact numbers, we can do a numeric comparison */ /* If they are both integers, compare only the relevant cells */ if (land & MV_INT) return (u->m[1] == v->m[1]); /* If one is an integer and the other is not, the two values cannot be equal */ if (lor & MV_INT) return 0; /* They are both decimal floating numbers, do a full comparison */ return ((((mval_b *)u)->sgne == ((mval_b *)v)->sgne) && (u->m[1] == v->m[1]) && (u->m[0]==v->m[0])); } /* At least one of the numbers is not in numeric form or is not a cannoical number, do a string compare */ MV_FORCE_STR(u); MV_FORCE_STR(v); if ((u->str.len != v->str.len) || (u->str.len && (u->str.addr != v->str.addr) && memcmp(u->str.addr, v->str.addr, u->str.len))) return 0; else return 1; } fis-gtm-V6.0-003/sr_port/is_file_identical.h0000644000032200000250000000214612201176157017636 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __IS_FILE_IDENTICAL_H__ #define __IS_FILE_IDENTICAL_H__ bool is_file_identical(char *filename1, char *filename2); bool is_gdid_file_identical(gd_id_ptr_t fid, char *filename, int4 filelen); #ifdef VMS void set_gdid_from_file(gd_id_ptr_t fileid, char *filename, int4 filelen); bool is_gdid_gdid_identical(gd_id_ptr_t fid_1, gd_id_ptr_t fid_2); #elif defined(UNIX) #include "gtm_stat.h" bool is_gdid_identical(gd_id_ptr_t fid1, gd_id_ptr_t fid2); bool is_gdid_stat_identical(gd_id_ptr_t fid, struct stat *stat_buf); void set_gdid_from_stat(gd_id_ptr_t fid, struct stat *stat_buf); boolean_t filename_to_id(gd_id_ptr_t fid, char *filename); #endif #endif fis-gtm-V6.0-003/sr_port/is_ident.c0000644000032200000250000000231612201176157016000 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "toktyp.h" LITREF char ctypetab[NUM_CHARS]; char is_ident(mstr *v) { int4 y; char *c, *c_top, ret; signed char ch; bool dig_start; ret = TRUE; c = v->addr; c_top = c + v->len; if (!v->len || (ch = *c++) < 0) ret = 0; else { switch (y = ctypetab[ch]) { case TK_LOWER: case TK_PERCENT: case TK_UPPER: case TK_DIGIT: dig_start = y == TK_DIGIT; for ( ; c < c_top; c++) { ch = *c; if (ch < 0) break; y = ctypetab[ch]; if (y != TK_DIGIT && dig_start) break; if (y != TK_DIGIT && y != TK_UPPER && y != TK_LOWER) break; } if (c == c_top) { /* we have an ident */ ret = 1 + dig_start; } else { ret = 0; } break; default: ret = 0; } } return ret; } fis-gtm-V6.0-003/sr_port/is_proc_alive.h0000644000032200000250000000124412201176157017024 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef IS_PROC_ALIVE_INCLUDED #define IS_PROC_ALIVE_INCLUDED #ifdef VMS bool is_proc_alive(uint4 pid, uint4 imagecnt); #elif defined(UNIX) bool is_proc_alive(int4 pid, int4 imagecnt); #endif #endif /* IS_PROC_ALIVE_INCLUDED */ fis-gtm-V6.0-003/sr_port/jfh_from_jnl_info.c0000644000032200000250000000750312201176157017655 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_time.h" #include "gdsroot.h" #include "gdsbt.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif GBLREF jnl_process_vector *prc_vec; GBLREF jnl_gbls_t jgbl; #ifdef UNIX GBLREF int4 strm_index; #endif void jfh_from_jnl_info(jnl_create_info *info, jnl_file_header *header) { int idx; trans_num db_tn; /**** We will write journal file header, epoch and eof in order ****/ /* Write the file header */ memset((char *)header, 0, JNL_HDR_LEN); /* note: In Unix, this means we 0-fill 2K REAL_JNL_HDR_LEN + 62K padding */ memcpy(header->label, JNL_LABEL_TEXT, STR_LIT_LEN(JNL_LABEL_TEXT)); header->is_little_endian = GTM_IS_LITTLE_ENDIAN; assert(NULL != prc_vec); JNL_WHOLE_FROM_SHORT_TIME(prc_vec->jpv_time, jgbl.gbl_jrec_time); memcpy(&header->who_created, (unsigned char*)prc_vec, SIZEOF(jnl_process_vector)); memcpy(&header->who_opened, (unsigned char*)prc_vec, SIZEOF(jnl_process_vector)); /* EPOCHs are written unconditionally in Unix while they are written only for BEFORE_IMAGE in VMS */ if (JNL_HAS_EPOCH(info)) header->end_of_data = JNL_HDR_LEN + PINI_RECLEN + EPOCH_RECLEN + PFIN_RECLEN; else header->end_of_data = JNL_HDR_LEN + PINI_RECLEN + PFIN_RECLEN; header->max_jrec_len = info->max_jrec_len; header->bov_timestamp = jgbl.gbl_jrec_time; header->eov_timestamp = jgbl.gbl_jrec_time; db_tn = info->csd->trans_hist.curr_tn; header->bov_tn = db_tn; header->eov_tn = db_tn; header->before_images = info->before_images; /* Note that in case of MUPIP JOURNAL -ROLLBACK, we need to set header->repl_state to repl_open although replication * is currently not ON in the database. This is so future ROLLBACKs know this journal is replication enabled. */ header->repl_state = jgbl.mur_rollback ? repl_open : info->repl_state; header->data_file_name_length = info->fn_len; memcpy(header->data_file_name, info->fn, info->fn_len); header->data_file_name[info->fn_len] = '\0'; header->alignsize = info->alignsize; header->autoswitchlimit = info->autoswitchlimit; header->epoch_interval = info->epoch_interval; header->start_seqno = info->reg_seqno; header->end_seqno = info->reg_seqno; header->prev_jnl_file_name_length = info->prev_jnl_len; ; memcpy(header->prev_jnl_file_name, info->prev_jnl, info->prev_jnl_len); header->prev_jnl_file_name[info->prev_jnl_len] = '\0'; assert(JNL_ALLOC_MIN <= info->alloc); header->jnl_alq = info->alloc; header->virtual_size = info->alloc; header->jnl_deq = info->extend; header->checksum = info->checksum; GTMCRYPT_ONLY( GTMCRYPT_COPY_HASH(info, header); ) # ifdef UNIX if (INVALID_SUPPL_STRM != strm_index) { assert(MAX_SUPPL_STRMS == ARRAYSIZE(header->strm_start_seqno)); for (idx = 0; idx < MAX_SUPPL_STRMS; idx++) header->strm_start_seqno[idx] = info->csd->strm_reg_seqno[idx]; if (jgbl.forw_phase_recovery) { /* If MUPIP JOURNAL -ROLLBACK, might need to do additional processing. See macro definition for comments */ MUR_ADJUST_STRM_REG_SEQNO_IF_NEEDED(info->csd, header->strm_start_seqno); } for (idx = 0; idx < MAX_SUPPL_STRMS; idx++) header->strm_end_seqno[idx] = header->strm_start_seqno[idx]; } else { memset(&header->strm_start_seqno[0], 0, SIZEOF(header->strm_start_seqno)); memset(&header->strm_end_seqno[0], 0, SIZEOF(header->strm_end_seqno)); } # endif } fis-gtm-V6.0-003/sr_port/jmp_opto.c0000644000032200000250000003006012201176157016026 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "compiler.h" #include "opcode.h" #include "mdq.h" #include "jmp_opto.h" #include "gtmdbglvl.h" #include "cdbg_dump.h" LITREF octabstruct oc_tab[]; /* op-code table */ GBLREF triple t_orig; /* head of triples */ GBLREF uint4 gtmDebugLevel; #define IND_NOT_DEFINED ((unsigned char)-2) #define JOPT_NO_OPT 1 #define JOPT_REP_JMP 2 #define JOPT_REF_NXT_TRP 3 #define NO_ENTRY ((unsigned char)-1) #define NUM_JO_TBL_ELE 11 #define PTR_NOT_DEFINED 0 typedef struct { unsigned int opcode; unsigned int index; unsigned int opto_flag[NUM_JO_TBL_ELE]; } jump_opto_struct; LITDEF readonly jump_opto_struct jump_opto_table[NUM_JO_TBL_ELE] = { { OC_JMP, /* opcode */ 0, /* index */ { JOPT_REP_JMP, /* OC_JMP */ JOPT_NO_OPT, /* OC_JMPTSET */ JOPT_NO_OPT, /* OC_JMPTCLR */ JOPT_NO_OPT, /* OC_JMPEQU */ JOPT_NO_OPT, /* OC_JMPNEQ */ JOPT_NO_OPT, /* OC_JMPGTR */ JOPT_NO_OPT, /* OC_JMPLEQ */ JOPT_NO_OPT, /* OC_JMPLSS */ JOPT_NO_OPT, /* OC_JMPGEQ */ JOPT_NO_OPT, /* HALT */ JOPT_NO_OPT /* RET */ } }, { OC_JMPTSET, /* opcode */ 1, /* index */ { JOPT_REP_JMP, /* OC_JMP */ JOPT_REP_JMP, /* OC_JMPTSET */ JOPT_REF_NXT_TRP, /* OC_JMPTCLR */ JOPT_NO_OPT, /* OC_JMPEQU */ JOPT_NO_OPT, /* OC_JMPNEQ */ JOPT_NO_OPT, /* OC_JMPGTR */ JOPT_NO_OPT, /* OC_JMPLEQ */ JOPT_NO_OPT, /* OC_JMPLSS */ JOPT_NO_OPT, /* OC_JMPGEQ */ JOPT_NO_OPT, /* HALT */ JOPT_NO_OPT /* RET */ } }, { OC_JMPTCLR, /* opcode */ 2, /* index */ { JOPT_REP_JMP, /* OC_JMP */ JOPT_REF_NXT_TRP, /* OC_JMPTSET */ JOPT_REP_JMP, /* OC_JMPTCLR */ JOPT_NO_OPT, /* OC_JMPEQU */ JOPT_NO_OPT, /* OC_JMPNEQ */ JOPT_NO_OPT, /* OC_JMPGTR */ JOPT_NO_OPT, /* OC_JMPLEQ */ JOPT_NO_OPT, /* OC_JMPLSS */ JOPT_NO_OPT, /* OC_JMPGEQ */ JOPT_NO_OPT, /* HALT */ JOPT_NO_OPT /* RET */ } }, { OC_JMPEQU, /* opcode */ 3, /* index */ { JOPT_REP_JMP, /* OC_JMP */ JOPT_NO_OPT, /* OC_JMPTSET */ JOPT_NO_OPT, /* OC_JMPTCLR */ JOPT_REP_JMP, /* OC_JMPEQU */ JOPT_REF_NXT_TRP, /* OC_JMPNEQ */ JOPT_REF_NXT_TRP, /* OC_JMPGTR */ JOPT_NO_OPT, /* OC_JMPLEQ */ JOPT_REF_NXT_TRP, /* OC_JMPLSS */ JOPT_NO_OPT, /* OC_JMPGEQ */ JOPT_NO_OPT, /* HALT */ JOPT_NO_OPT /* RET */ } }, { OC_JMPNEQ, /* opcode */ 4, /* index */ { JOPT_REP_JMP, /* OC_JMP */ JOPT_NO_OPT, /* OC_JMPTSET */ JOPT_NO_OPT, /* OC_JMPTCLR */ JOPT_REF_NXT_TRP, /* OC_JMPEQU */ JOPT_REP_JMP, /* OC_JMPNEQ */ JOPT_NO_OPT, /* OC_JMPGTR */ JOPT_NO_OPT, /* OC_JMPLEQ */ JOPT_NO_OPT, /* OC_JMPLSS */ JOPT_NO_OPT, /* OC_JMPGEQ */ JOPT_NO_OPT, /* HALT */ JOPT_NO_OPT /* RET */ } }, { OC_JMPGTR, /* opcode */ 5, /* index */ { JOPT_REP_JMP, /* OC_JMP */ JOPT_NO_OPT, /* OC_JMPTSET */ JOPT_NO_OPT, /* OC_JMPTCLR */ JOPT_REF_NXT_TRP, /* OC_JMPEQU */ JOPT_REP_JMP, /* OC_JMPNEQ */ JOPT_REP_JMP, /* OC_JMPGTR */ JOPT_REF_NXT_TRP, /* OC_JMPLEQ */ JOPT_REF_NXT_TRP, /* OC_JMPLSS */ JOPT_NO_OPT, /* OC_JMPGEQ */ JOPT_NO_OPT, /* HALT */ JOPT_NO_OPT /* RET */ } }, { OC_JMPLEQ, /* opcode */ 6, /* index */ { JOPT_REP_JMP, /* OC_JMP */ JOPT_NO_OPT, /* OC_JMPTSET */ JOPT_NO_OPT, /* OC_JMPTCLR */ JOPT_NO_OPT, /* OC_JMPEQU */ JOPT_NO_OPT, /* OC_JMPNEQ */ JOPT_REF_NXT_TRP, /* OC_JMPGTR */ JOPT_REP_JMP, /* OC_JMPLEQ */ JOPT_NO_OPT, /* OC_JMPLSS */ JOPT_NO_OPT, /* OC_JMPGEQ */ JOPT_NO_OPT, /* HALT */ JOPT_NO_OPT /* RET */ } }, { OC_JMPLSS, /* opcode */ 7, /* index */ { JOPT_REP_JMP, /* OC_JMP */ JOPT_NO_OPT, /* OC_JMPTSET */ JOPT_NO_OPT, /* OC_JMPTCLR */ JOPT_REF_NXT_TRP, /* OC_JMPEQU */ JOPT_REP_JMP, /* OC_JMPNEQ */ JOPT_REF_NXT_TRP, /* OC_JMPGTR */ JOPT_REP_JMP, /* OC_JMPLEQ */ JOPT_REP_JMP, /* OC_JMPLSS */ JOPT_REF_NXT_TRP, /* OC_JMPGEQ */ JOPT_NO_OPT, /* HALT */ JOPT_NO_OPT /* RET */ } }, { OC_JMPGEQ, /* opcode */ 8, /* index */ { JOPT_REP_JMP, /* OC_JMP */ JOPT_NO_OPT, /* OC_JMPTSET */ JOPT_NO_OPT, /* OC_JMPTCLR */ JOPT_NO_OPT, /* OC_JMPEQU */ JOPT_NO_OPT, /* OC_JMPNEQ */ JOPT_NO_OPT, /* OC_JMPGTR */ JOPT_NO_OPT, /* OC_JMPLEQ */ JOPT_REF_NXT_TRP, /* OC_JMPLSS */ JOPT_REP_JMP, /* OC_JMPGEQ */ JOPT_NO_OPT, /* HALT */ JOPT_NO_OPT /* RET */ } }, { OC_HALT, /* opcode */ 9, /* index */ { JOPT_NO_OPT, /* OC_JMP */ JOPT_NO_OPT, /* OC_JMPTSET */ JOPT_NO_OPT, /* OC_JMPTCLR */ JOPT_NO_OPT, /* OC_JMPEQU */ JOPT_NO_OPT, /* OC_JMPNEQ */ JOPT_NO_OPT, /* OC_JMPGTR */ JOPT_NO_OPT, /* OC_JMPLEQ */ JOPT_NO_OPT, /* OC_JMPLSS */ JOPT_NO_OPT, /* OC_JMPGEQ */ JOPT_NO_OPT, /* HALT */ JOPT_NO_OPT /* RET */ } }, { OC_RET, /* opcode */ 10, /* index */ { JOPT_NO_OPT, /* OC_JMP */ JOPT_NO_OPT, /* OC_JMPTSET */ JOPT_NO_OPT, /* OC_JMPTCLR */ JOPT_NO_OPT, /* OC_JMPEQU */ JOPT_NO_OPT, /* OC_JMPNEQ */ JOPT_NO_OPT, /* OC_JMPGTR */ JOPT_NO_OPT, /* OC_JMPLEQ */ JOPT_NO_OPT, /* OC_JMPLSS */ JOPT_NO_OPT, /* OC_JMPGEQ */ JOPT_NO_OPT, /* HALT */ JOPT_NO_OPT /* RET */ } } }; STATICDEF unsigned int *jo_ptr_ray[OPCODE_COUNT]; STATICDEF unsigned int jo_ind_ray[OPCODE_COUNT]; STATICFNDCL void jo_get_ptrs(unsigned int op); STATICFNDEF void jo_get_ptrs(unsigned int op) { const jump_opto_struct *j, *j_top; for (j = &jump_opto_table[0], j_top = j + NUM_JO_TBL_ELE; j < j_top; j++) { if (j->opcode == op) { jo_ind_ray[op] = j->index; jo_ptr_ray[op] = (unsigned int *)&j->opto_flag[0]; return; } } jo_ind_ray[op] = NO_ENTRY; jo_ptr_ray[op] = (unsigned int *)NO_ENTRY; } STATICDEF const readonly oprtype null_operand; /************************************************************************************************************ NOTE: We may which to modify the lookup method at some point in the future. B. Shear suggests nested switch statements. Another option is to do the lookup each time. ***********************************************************************************************************/ void jmp_opto(void) { unsigned int **clrp1, *clrp2, **clrtop1, *clrtop2, i, *p; tbp *b; triple *ct, *cur_trip, *jump_trip, *next_trip, *ref_trip, *terminal_trip; void get_jo_ptrs(); # ifdef DEBUG /* If debug and compiler debugging is enabled, run through the triples again to show where we are jus * before we modify them. */ if (gtmDebugLevel & GDL_DebugCompiler) { PRINTF(" \n\n\n\n************************************ Begin jmp_opto scan *****************************\n"); } # endif for (clrp1 = &jo_ptr_ray[0], clrtop1 = clrp1 + OPCODE_COUNT; clrp1 < clrtop1; clrp1++) *clrp1 = (unsigned int *)NO_ENTRY; for (clrp2 = &jo_ind_ray[0], clrtop2 = clrp2 + OPCODE_COUNT; clrp2 < clrtop2; clrp2++) *clrp2 = NO_ENTRY; dqloop(&t_orig, exorder, cur_trip) { if (OC_GVSAVTARG == cur_trip->opcode) { /* Look for an adjacent and therefore superfluous GVRECTARG */ for (next_trip = cur_trip->exorder.fl; oc_tab[next_trip->opcode].octype & OCT_CGSKIP; next_trip = next_trip->exorder.fl) ; if ((OC_GVRECTARG == next_trip->opcode) && (next_trip->operand[0].oprval.tref == cur_trip) && (next_trip->jmplist.que.fl == &(next_trip->jmplist))) { COMPDBG(PRINTF("jmp_opto: NOOPing OC_GVRECTARG opcode at triple addres 0x"lvaddr"\n", next_trip);); next_trip->opcode = OC_NOOP; next_trip->operand[0].oprclass = next_trip->operand[1].oprclass = NO_REF; cur_trip = cur_trip->exorder.bl; /* in case there are more than one in a row */ } continue; } if (OC_GVRECTARG == cur_trip->opcode) { /* Look for a second effectively adjacent GVRECTARG that duplicates this one */ for (next_trip = cur_trip->exorder.fl; oc_tab[next_trip->opcode].octype & OCT_CGSKIP; next_trip = next_trip->exorder.fl) ; if ((OC_GVRECTARG == next_trip->opcode) && (next_trip->operand[0].oprval.tref == cur_trip->operand[0].oprval.tref) && (next_trip->jmplist.que.fl == &(next_trip->jmplist))) { COMPDBG(PRINTF("jmp_opto: NOOPing OC_GVRECTARG opcode at triple addres 0x"lvaddr"\n", next_trip);); next_trip->opcode = OC_NOOP; next_trip->operand[0].oprclass = next_trip->operand[1].oprclass = NO_REF; cur_trip = cur_trip->exorder.bl; /* in case there are more than one in a row */ } continue; } if ((oc_tab[cur_trip->opcode].octype & OCT_JUMP) && (OC_CALL != cur_trip->opcode) && (OC_CALLSP != cur_trip->opcode)) { assert(OPCODE_COUNT > cur_trip->opcode); if (PTR_NOT_DEFINED == (p = jo_ptr_ray[cur_trip->opcode])) /* note assignment */ { jo_get_ptrs(cur_trip->opcode); p = jo_ptr_ray[cur_trip->opcode]; } assert(TJMP_REF == cur_trip->operand[0].oprclass); jump_trip = cur_trip->operand[0].oprval.tref; if (IND_NOT_DEFINED == (i = jo_ind_ray[jump_trip->opcode])) /* note assignment */ { jo_get_ptrs(jump_trip->opcode); i = jo_ind_ray[jump_trip->opcode]; } while ((IND_NOT_DEFINED != i) && (NO_ENTRY != i)) { switch(p[i]) { case JOPT_NO_OPT: i = NO_ENTRY; break; case JOPT_REF_NXT_TRP: if (cur_trip->src.line == jump_trip->src.line) { dqloop(&jump_trip->jmplist, que, b) { if (b->bpt = cur_trip) { dqdel(b, que); break; } } dqins(&jump_trip->exorder.fl->jmplist, que, b); cur_trip->operand[0].oprval.tref = jump_trip->exorder.fl; jump_trip = cur_trip->operand[0].oprval.tref; if (IND_NOT_DEFINED == (i = jo_ind_ray[jump_trip->opcode])) /* assignmnt */ { jo_get_ptrs(jump_trip->opcode); i = jo_ind_ray[jump_trip->opcode]; } COMPDBG(PRINTF("jmp_opto: JOPT_REF_NXT_TRP optimization on triple " "0x"lvaddr"\n", cur_trip);); } else i = NO_ENTRY; break; case JOPT_REP_JMP: if (cur_trip->src.line == jump_trip->src.line) { assert(TJMP_REF == jump_trip->operand[0].oprclass); dqloop(&jump_trip->jmplist, que, b) { if (b->bpt = cur_trip) { dqdel(b, que); break; } } dqins(&jump_trip->operand[0].oprval.tref->jmplist, que, b); cur_trip->operand[0] = jump_trip->operand[0]; jump_trip = cur_trip->operand[0].oprval.tref; if (IND_NOT_DEFINED == (i = jo_ind_ray[jump_trip->opcode])) /* assgnmnt */ { jo_get_ptrs(jump_trip->opcode); i = jo_ind_ray[jump_trip->opcode]; } COMPDBG(PRINTF("jmp_opto: JOPT_REP_JMP optimization on triple " "0x"lvaddr"\n", cur_trip);); } else i = NO_ENTRY; break; default: GTMASSERT; break; } /* switch */ } /* while */ terminal_trip = cur_trip->exorder.fl; while ((oc_tab[cur_trip->opcode].octype & OCT_JUMP) && (OC_CALL != cur_trip->opcode) && (OC_CALLSP != cur_trip->opcode) && (TJMP_REF == cur_trip->operand[0].oprclass)) { for ((ref_trip = cur_trip->operand[0].oprval.tref); (oc_tab[ref_trip->opcode].octype & OCT_CGSKIP); (ref_trip = ref_trip->exorder.fl)) ; if (ref_trip == terminal_trip) { cur_trip->opcode = OC_NOOP; cur_trip->operand[0] = null_operand; COMPDBG(PRINTF("jmp_opto: Triple removed at address 0x"lvaddr"\n", cur_trip);); cur_trip = cur_trip->exorder.bl; } else break; } cur_trip = terminal_trip->exorder.bl; } /* if */ } /* dqloop */ # ifdef DEBUG /* If debug and compiler debugging is enabled, run through the triples again to show what we * have done to them.. */ if (gtmDebugLevel & GDL_DebugCompiler) { dqloop(&t_orig, exorder, ct) { PRINTF("\n ************************ Triple Start **********************\n"); cdbg_dump_triple(ct, 0); } } # endif } fis-gtm-V6.0-003/sr_port/jmp_opto.h0000644000032200000250000000105012201176157016030 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef JMP_OPTO_INCLUDED #define JMP_OPTO_INCLUDED void jmp_opto(void); #endif /* JMP_OPTO_INCLUDED */ fis-gtm-V6.0-003/sr_port/jnl.h0000644000032200000250000020536112201176160014771 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #ifndef JNL_H_INCLUDED #define JNL_H_INCLUDED #ifdef DEBUG #include /* for offsetof macro (see OFFSETOF usage in assert below) */ #endif #ifndef JNLSP_H_INCLUDED #include "jnlsp.h" #endif #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif error_def(ERR_JNLBADLABEL); error_def(ERR_JNLENDIANBIG); error_def(ERR_JNLENDIANLITTLE); #define TID_STR_SIZE 8 #define JPV_LEN_NODE 16 #define JPV_LEN_USER 12 #define JPV_LEN_PRCNAM 16 #define JPV_LEN_TERMINAL 15 /* Whenever JNL_LABEL_TEXT changes, also change the following * 1) Update JNL_VER_THIS * 2) Add REPL_JNL_Vxx enum to repl_jnl_t typedef AND Vxx_JNL_VER #define in repl_filter.h * 3) Add an entry each to repl_filter_old2cur & repl_filter_cur2old arrays in repl_filter.c. * If the FILTER format is also changing, then do the following as well * 4) Add REPL_FILTER_Vxx enum to repl_filter_t typedef in repl_filter.h * 5) Add/Edit IF_xTOy macros in repl_filter.h to transform from/to the NEW jnl format version only. * Remove all entries that dont have the new jnl format in either the from or to part of the conversion. * 6) Add/Edit prototype and implement functions jnl_xTOy() and jnl_yTOx() in repl_filter.c * 7) Enhance repl_tr_endian_convert() to endian convert journal records from previous jnl formats to new format. * This is similar to the jnl_xTOy() filter conversion functions except that lot of byte-swaps are needed. * 8) Periodically determine if the size of the array repl_filter_old2cur is huge and if so trim support of * rolling upgrade (using replication internal filters) for older GT.M versions/jnl-formats. * This would mean bumping the macro JNL_VER_EARLIEST_REPL and examining all arrays that are defined * using this macro and changing the entries in all those arrays accordingly (e.g. repl_filter_old2cur * array currently assumes earliest supported version is V15 and hence has the function named IF_curTO15 * which needs to change to say IF_curTO17 if the earliest supported version changes to V17 or so). * */ #define JNL_LABEL_TEXT "GDSJNL23" /* see above comment paragraph for todos whenever this is changed */ #define JNL_VER_THIS 23 #define JNL_VER_EARLIEST_REPL 17 /* Replication filter support starts here GDSJNL17 = GT.M V5.1-000. * (even though it should be V5.0-000, since that is pre-multisite, * the replication connection with V55000 will error out at handshake * time so V5.1-000 is the minimum that will even reach internal filter code) */ #define JRT_MAX_V17 JRT_AIMG /* Maximum jnl record type in GDSJNL17 or GDSJNL18 that can be input to replication * filter. Actually JRT_TRIPLE is a higher record type than JRT_AIMG but it is only * sent through the replication pipe and never seen by filter routines. */ #define JRT_MAX_V19 JRT_UZTWORM /* Max jnlrec type in GDSJNL19/GDSJNL20 that can be input to replication filter */ #define JRT_MAX_V21 JRT_UZTRIG /* Max jnlrec type in GDSJNL21 that can be input to replication filter */ #define JRT_MAX_V23 JRT_UZTRIG /* Max jnlrec type in GDSJNL22/GDSJNL23 that can be input to replication filter. * Actually JRT_HISTREC is a higher record type than JRT_UZTRIG but it is only * sent through the replication pipe and never seen by filter routines. */ #define ALIGN_KEY 0xdeadbeef #ifdef UNIX # define JNL_ALLOC_DEF 2048 # define JNL_ALLOC_MIN 2048 #elif defined(VMS) # define JNL_ALLOC_DEF 100 # define JNL_ALLOC_MIN 10 #endif #ifdef UNIX /* The journal buffer size (specified in pages of size DISK_BLOCK_SIZE) should be large enough for one largest record, * which is equivalent to the largest possible value (of size MAX_STRLEN) and largest possible key (of size MAX_KEY_SZ), * plus the overhead of storing the journal records. */ # define JNL_BUFFER_MIN ((MAX_LOGI_JNL_REC_SIZE + ROUND_UP(2 * MAX_IO_BLOCK_SIZE, DISK_BLOCK_SIZE)) / DISK_BLOCK_SIZE + 1) #endif #define JNL_BUFFER_MAX 32768 /* # of 512-byte blocks = 16Mb journal buffer size */ /* JNL_EXTEND_DEF allocation size / 10 #define JNL_EXTEND_DEF_PERC 0.1 * Uncomment this section when code is ready to use extension = 10% of allocation */ #define JNL_EXTEND_MIN 0 #ifdef UNIX # define JNL_EXTEND_DEF 2048 # define JNL_EXTEND_MAX 1073741823 #else # define JNL_EXTEND_DEF 100 # define JNL_EXTEND_MAX 65535 #endif #define JNL_MIN_WRITE 32768 #define JNL_MAX_WRITE 65536 /* FE was changed to EB because, the bit pattern there seems to vary more than the one for "FE". * Also a research in ELWOOD journal file showed that "EB" was one of the few patterns that had the least occurrences */ #define JNL_REC_SUFFIX_CODE 0xEB /* In Unix, with sync_io, we do journal writes to disk at filesystem block size boundaries. * In VMS, the writes are at 512-byte boundaries only. */ #ifdef UNIX # define JNL_WRT_START_MODULUS(jb) jb->fs_block_size #elif defined(VMS) # define JNL_WRT_START_MODULUS(jb) 512 #endif #define JNL_WRT_START_MASK(jb) ~(JNL_WRT_START_MODULUS(jb) - 1) /* mask defining where the next physical write needs to * happen as follows from the size of JNL_WRT_START_MODULUS */ #define JNL_WRT_END_MODULUS 8 #define JNL_WRT_END_MASK ~(JNL_WRT_END_MODULUS - 1) #ifdef UNIX # define JNL_MIN_ALIGNSIZE (1 << 12) /* 4096 disk blocks effectively 2M alignsize */ # define JNL_DEF_ALIGNSIZE (1 << 12) /* 4096 disk blocks effectively 2M alignsize */ #else # define JNL_MIN_ALIGNSIZE (1 << 5) /* 32 disk blocks effectively 16K alignsize */ # define JNL_DEF_ALIGNSIZE (1 << 7) /* 128 disk blocks effectively 64K alignsize */ #endif #define JNL_MAX_ALIGNSIZE (1 << 22) /* 4194304 disk blocks effectively 2G alignsize */ #define JNL_REC_START_BNDRY 8 #ifdef UNIX /* maximum logical journal record size */ # define MAX_LOGI_JNL_REC_SIZE (ROUND_UP(MAX_STRLEN, DISK_BLOCK_SIZE) + ROUND_UP(MAX_KEY_SZ, DISK_BLOCK_SIZE)) #else # define MAX_LOGI_JNL_REC_SIZE (MAX_DB_BLK_SIZE) /* maximum logical journal record size */ #endif /* one more disk-block for PBLK record header/footer */ #define MAX_JNL_REC_SIZE (MAX_LOGI_JNL_REC_SIZE + DISK_BLOCK_SIZE) /* Very large records require spanning nodes, which only happen in TP. */ #define MAX_NONTP_JNL_REC_SIZE(BSIZE) ((BSIZE) + DISK_BLOCK_SIZE) #define MAX_MAX_NONTP_JNL_REC_SIZE MAX_NONTP_JNL_REC_SIZE(MAX_DB_BLK_SIZE) #ifdef GTM_TRIGGER /* Define maximum size that $ZTWORMHOLE can be. Since $ZTWORMHOLE should be able to fit in a journal record and the * minimum alignsize is 128K, we do not want it to go more than 128K (that way irrespective of whatever alignsize the user * specifies for the journal file, $ZTWORMHOLE will fit in the journal record). Leaving a max of 512 bytes for the * journal record prefix/suffix (32-byte overhead) and MIN_ALIGN_RECLEN (see comment in JNL_MAX_RECLEN macro for why * this is needed) we allow for a max of 128K-512 bytes in $ZTWORMHOLE. */ #define MAX_ZTWORMHOLE_LEN (128 * 1024) #define MAX_ZTWORMHOLE_SIZE (MAX_ZTWORMHOLE_LEN - 512) #define MAX_ZTWORM_JREC_LEN (MAX_ZTWORMHOLE_LEN - MIN_ALIGN_RECLEN) #endif #define MIN_YIELD_LIMIT 0 #define MAX_YIELD_LIMIT 2048 #define DEFAULT_YIELD_LIMIT 8 #ifdef UNIX /* Have a minimum jnl-file-auto-switch-limit of 4 align boundaries (currently each align boundary is 2M) */ #define JNL_AUTOSWITCHLIMIT_MIN (4 * JNL_MIN_ALIGNSIZE) #define JNL_AUTOSWITCHLIMIT_DEF 8386560 /* Instead of 8388607 it is adjusted for default allocation = extension = 2048 */ #else /* Have a minimum jnl-file-auto-switch-limit of 128 align boundaries (currently each align boundary is 16K) */ #define JNL_AUTOSWITCHLIMIT_MIN (128 * JNL_MIN_ALIGNSIZE) #define JNL_AUTOSWITCHLIMIT_DEF 8388600 /* Instead of 8388607 it is adjusted for default allocation = extension = 100 */ #endif /* options (4-bytes unsigned integer) to wcs_flu() (currently flush_hdr, write_epoch, sync_epoch) are bit-wise ored */ #define WCSFLU_NONE 0 #define WCSFLU_FLUSH_HDR 1 #define WCSFLU_WRITE_EPOCH 2 #define WCSFLU_SYNC_EPOCH 4 #define WCSFLU_FSYNC_DB 8 /* Currently used only in Unix wcs_flu() */ #define WCSFLU_IN_COMMIT 16 /* Set if caller is t_end or tp_tend. See wcs_flu for explanation of when this is set */ #define WCSFLU_MSYNC_DB 32 /* Force a full msync if NO_MSYNC is defined. Currently used only in Unix wcs_flu(). */ #define WCSFLU_SPEEDUP_NOBEFORE 64 /* Do not flush dirty db buffers. Just write an epoch record. * Used to speedup nobefore jnl for Unix. Flag ignored in VMS. */ #define WCSFLU_CLEAN_DBSYNC 128 /* wcs_flu invoked by wcs_clean_dbsync (as opposed to t_end/tp_tend invocation) */ /* options for error_on_jnl_file_lost */ #define JNL_FILE_LOST_TURN_OFF 0 /* Turn off journaling. */ #define JNL_FILE_LOST_ERRORS 1 /* Throw an rts_error. */ #define MAX_JNL_FILE_LOST_OPT JNL_FILE_LOST_ERRORS /* EPOCHs are written unconditionally in Unix (assuming jnl is ON) while they are written only for BEFORE_IMAGE in VMS */ #define JNL_HAS_EPOCH(jnlfile) UNIX_ONLY(TRUE) VMS_ONLY(jnlfile->before_images) #ifdef DEBUG #define DEFAULT_EPOCH_INTERVAL_IN_SECONDS 30 /* exercise epoch-syncing code relatively more often in DBG */ #else #define DEFAULT_EPOCH_INTERVAL_IN_SECONDS 300 #endif #define DEFAULT_EPOCH_INTERVAL SECOND2EPOCH_SECOND(DEFAULT_EPOCH_INTERVAL_IN_SECONDS) /* ***MUST*** include math.h for VMS */ #define MAX_EPOCH_INTERVAL 32767 /* in seconds. Amounts to nearly 10 hours. Don't want to keep db stale so long */ #define JNL_ENABLED(X) ((X)->jnl_state == jnl_open) /* If TRUE, journal records are to be written */ #define JNL_ALLOWED(X) ((X)->jnl_state != jnl_notallowed) /* If TRUE, journaling is allowed for the file */ #define REPL_ENABLED(X) ((X)->repl_state == repl_open) /* If TRUE, replication records are to be written */ #define REPL_WAS_ENABLED(X) ((X)->repl_state == repl_was_open) /* If TRUE, replication is now closed, but was open earlier */ /* In this state, replication records are not written */ #define REPL_ALLOWED(X) ((X)->repl_state != repl_closed) /* If TRUE, replication records are/were written */ /* Logical records should be written if journaling is enabled in the region OR if replication state is WAS_ON (repl_was_open). * In the former case, the journal records will be written to the journal pool, journal buffer and journal file. * In the latter case, the journal records will be written to the journal pool but not to the journal buffer and journal file. * All code that generates logical journal records should use the below macro instead of JNL_ENABLED macro. * Note that replication does not care about non-logical records (PBLK/AIMG/INCTN etc.) and hence code that generates them does * not need to (and should not) use this macro. */ #define JNL_WRITE_LOGICAL_RECS(X) (JNL_ENABLED(X) || REPL_WAS_ENABLED(X)) /* The following macro should be used to invoke the function "jnl_write" for any logical record. This macro * checks if journaling is enabled and if so invokes "jnl_write" else it invokes "jnl_write_poolonly" which * writes only to the journal pool. */ #define JNL_WRITE_APPROPRIATE(CSA, JPC, RECTYPE, JREC, BLKPTR, JFB) \ { \ assert(JNL_ENABLED(CSA) || REPL_WAS_ENABLED(CSA)); \ assert((NULL == JFB) || (RECTYPE == ((jnl_record *)(((jnl_format_buffer *)JFB)->buff))->prefix.jrec_type)); \ if (JNL_ENABLED(CSA)) \ jnl_write(JPC, RECTYPE, JREC, BLKPTR, JFB); /* write to jnlbuffer, jnlfile, jnlpool */ \ else \ jnl_write_poolonly(JPC, RECTYPE, JREC, JFB); /* write to jnlpool only */ \ } #define MUEXTRACT_TYPE(A) (((A)[0]-'0')*10 + ((A)[1]-'0')) /* A is a character pointer */ #define PADDED PADDING /* User must enter this string to ask standard input or output. */ #define JNL_STDO_EXTR "-stdout" #ifdef BIGENDIAN #define THREE_LOW_BYTES(x) ((uchar_ptr_t)((uchar_ptr_t)&x + 1)) #else #define THREE_LOW_BYTES(x) ((uchar_ptr_t)(&x)) #endif #define EXTTIME(S) extract_len = exttime(S, murgbl.extr_buff, extract_len) /* This macro should be used to initialize jgbl.gbl_jrec_time to the system time. The reason is that it does additional checks. */ #define SET_GBL_JREC_TIME \ { \ assert(!jgbl.dont_reset_gbl_jrec_time); \ JNL_SHORT_TIME(jgbl.gbl_jrec_time); \ } /* This macro ensures that journal records are written in non-decreasing time order in each journal file. * It is passed the time field to adjust and a pointer to the journal buffer of the region. * The journal buffer holds the timestamp of the most recently written journal record. */ #define ADJUST_GBL_JREC_TIME(jgbl, jbp) \ { \ if (jgbl.gbl_jrec_time < jbp->prev_jrec_time) \ { \ assert(!jgbl.dont_reset_gbl_jrec_time); \ jgbl.gbl_jrec_time = jbp->prev_jrec_time; \ } \ } /* This macro is similar to ADJUST_GBL_JREC_TIME except that this ensures ordering of timestamps across * ALL replicated regions in a replicated environment. In VMS, we dont maintain this prev_jnlseqno_time * field. */ # define ADJUST_GBL_JREC_TIME_JNLPOOL(jgbl, jpl) \ { \ if (jgbl.gbl_jrec_time < jpl->prev_jnlseqno_time) \ { \ assert(!jgbl.dont_reset_gbl_jrec_time); \ jgbl.gbl_jrec_time = jpl->prev_jnlseqno_time; \ } \ jpl->prev_jnlseqno_time = jgbl.gbl_jrec_time; \ } /* Check if journal file is usable from the fields in the file header. * Currently, the fields tested are LABEL and ENDIANNESS. */ #define JNL_HDR_ENDIAN_OFFSET 8 #define CHECK_JNL_FILE_IS_USABLE(JFH, STATUS, DO_GTMPUTMSG, JNL_FN_LEN, JNL_FN) \ { \ boolean_t check_failed = FALSE; \ uint4 lcl_status; \ \ assert(JNL_HDR_ENDIAN_OFFSET == OFFSETOF(jnl_file_header, is_little_endian)); \ if (0 != MEMCMP_LIT((JFH)->label, JNL_LABEL_TEXT)) \ { \ lcl_status = ERR_JNLBADLABEL; \ check_failed = TRUE; \ } \ BIGENDIAN_ONLY( \ else if ((JFH)->is_little_endian) \ { \ lcl_status = ERR_JNLENDIANLITTLE; \ check_failed = TRUE; \ } \ ) \ LITTLEENDIAN_ONLY( \ else if (!(JFH)->is_little_endian) \ { \ lcl_status = ERR_JNLENDIANBIG; \ check_failed = TRUE; \ } \ ) \ /* Currently, we can do one gtm_putmsg for any of the above 3 error messages \ * because all of them have a fao count of 2 and expect jnl_fn_len and jnl_fn \ * as arguments. If a new error gets added and has a different fao format, \ * then the below gtm_putmsg has to be done differently based on that error. \ */ \ if (check_failed) \ { \ STATUS = lcl_status; \ if (DO_GTMPUTMSG) \ gtm_putmsg(VARLSTCNT(4) lcl_status, 2, JNL_FN_LEN, JNL_FN); \ } \ } /* Token generation used in non-replicated journaled environment. Note the assumption here that SIZEOF(token_split_t) == SIZEOF(token_build) which will be asserted in gvcst_init(). The TOKEN_SET macro below depends on this assumption. */ typedef struct token_split_t_struct { # ifdef BIGENDIAN uint4 process_id; uint4 local_tn; # else uint4 local_tn; uint4 process_id; # endif } token_split_t; typedef union { token_split_t t_piece; token_num token; } token_build; /* To assist in setting token value, the following macro is supplied to handle the two token parts */ #define TOKEN_SET(BASE, TN, PID) (((token_build_ptr_t)(BASE))->t_piece.local_tn = (uint4)(TN), \ ((token_build_ptr_t)(BASE))->t_piece.process_id = (PID)) enum jpv_types { CURR_JPV = 0, ORIG_JPV, JPV_COUNT }; /* Note we have two process verctors now for a pini record */ typedef struct jnl_process_vector_struct /* name needed since this is used in cmmdef.h for "pvec" member */ { uint4 jpv_pid; /* Process id */ int4 jpv_image_count; /* Image activations [VMS only] */ jnl_proc_time jpv_time; /* Timestamp of the process genarating this. (This could be different than the journal record timestamp) */ jnl_proc_time jpv_login_time; /* Used for process initialization time */ char jpv_node[JPV_LEN_NODE], /* Node name */ jpv_user[JPV_LEN_USER], /* User name */ jpv_prcnam[JPV_LEN_PRCNAM], /* Process name [VMS only] */ jpv_terminal[JPV_LEN_TERMINAL]; /* Login terminal */ unsigned char jpv_mode; /* a la JPI$_MODE [VMS only] */ int4 filler; /* SIZEOF(jnl_process_vector) must be a multiple of SIZEOF(int4) */ } jnl_process_vector; enum pini_rec_stat { IGNORE_PROC = 0, ACTIVE_PROC = 1, FINISHED_PROC = 2, BROKEN_PROC = 4 }; typedef struct pini_list { uint4 pini_addr; uint4 new_pini_addr; /* used in forward phase of recovery */ jnl_process_vector jpv; /* CURR_JPV. Current process's JPV. For GTCM server we also use this. */ jnl_process_vector origjpv; /* ORIG_JPV. Used for GTCM client only */ enum pini_rec_stat state; /* used for show qualifier */ } pini_list_struct; enum jnl_record_type { #define JNL_TABLE_ENTRY(rectype, extract_rtn, label, update, fixed_size, is_replicated) rectype, #include "jnl_rec_table.h" #undef JNL_TABLE_ENTRY JRT_RECTYPES /* Total number of JOURNAL record types */ }; #include "jnl_typedef.h" enum jnl_state_codes { jnl_notallowed, jnl_closed, jnl_open }; enum repl_state_codes { repl_closed, /* region not replicated, no records are written */ repl_open, /* region is replicated, and records are written */ repl_was_open /* region is currently not replicated, but it was earlier; jnl_file_lost() changes open to was_open */ }; typedef struct { trans_num eov_tn; /* curr_tn is saved as eov_tn by jnl_write_epoch. Used by recover/rollback */ volatile trans_num epoch_tn; /* Transaction number for current epoch */ seq_num end_seqno; /* reg_seqno saved by jnl_write_epoch. Used by recover/rollback */ seq_num strm_end_seqno[MAX_SUPPL_STRMS]; /* used to keep jfh->strm_end_seqno uptodate with each epoch. * Unused in VMS but defined so shared memory layout is similar in Unix & VMS. */ int4 min_write_size, /* if unwritten data gets to this size, write it */ max_write_size, /* maximum size of any single write */ size; /* buffer size */ int4 epoch_interval; /* Time between successive epochs in epoch-seconds */ boolean_t before_images; /* If TRUE, before-image processing is enabled */ /* end not volatile QUAD */ uintszofptr_t buff_off; /* relative offset to filesystem-block-size aligned buffer start */ volatile int4 free; /* relative index of first byte to write in buffer */ volatile uint4 freeaddr, /* virtual on-disk address which will correspond to free, when it is written */ end_of_data, /* Synched offset updated by jnl_write_epoch. Used by recover/rollback */ filesize; /* highest virtual address available in the file (units in disk-blocks) * file size in bytes limited to 4GB by autoswitchlimit, so 'filesize' <= 8MB * so filesize cannot overflow the four bytes of a uint4 */ /* end mainline QUAD */ volatile int4 blocked; volatile uint4 fsync_dskaddr; /* dskaddr upto which fsync is done */ volatile int4 dsk; /* relative index of 1st byte to write to disk; * if free == dsk, buffer is empty */ volatile int4 wrtsize; /* size of write in progress */ volatile uint4 dskaddr, /* virtual on-disk address corresponding to dsk */ now_writer, /* current owner of io_in_prog (VMS-only) */ image_count; /* for VMS is_proc_alive */ volatile struct /* must be at least word aligned for memory coherency */ { short cond; unsigned short length; int4 dev_specific; } iosb; /* alignsize is removed and log2_of_alignsize introduced */ uint4 log2_of_alignsize; /* Ceiling of log2(alignsize) */ jnl_tm_t eov_timestamp; /* jgbl.gbl_jrec_time saved by jnl_write_epoch. Used by recover/rollback */ uint4 cycle; /* shared copy of the number of the current journal file generation */ volatile int4 qiocnt, /* Number of qio's issued */ bytcnt, /* Number of bytes written */ errcnt, /* Number of errors during writing */ reccnt[JRT_RECTYPES]; /* Number of records written per opcode */ int filler_align[35 - JRT_RECTYPES]; /* So buff below starts on even (QW) keel */ /* Note the above filler will fail if JRT_RECTYPES grows beyond 31 elements and give compiler warning in VMS * if JRT_RECTYPES equals 31. In that case, change the start num to the next odd number above MAX(31,JRT_RECTYPES). */ volatile jnl_tm_t prev_jrec_time; /* to ensure that time never decreases across successive jnl records */ volatile int4 free_update_pid; /* pid that is updating jb->free and jb->freeaddr */ volatile uint4 next_epoch_time; /* Time when next epoch is to be written (in epoch-seconds) */ volatile boolean_t need_db_fsync; /* need an fsync of the db file */ volatile int4 io_in_prog; /* VMS only: write in progress indicator (NOTE: must manipulate only with interlocked instructions */ uint4 enospc_errcnt; /* number of times jb->errcnt was last incremented due to ENOSPC error * when writing to this journal file */ uint4 max_jrec_len; /* copy of max_jrec_len from journal file header */ uint4 fs_block_size; /* underlying journal file system block size; * primarily used in Unix, 512 in VMS */ /* CACHELINE_PAD macros provide spacing between the following latches so that they do not interfere with each other which can happen if they fall in the same data cacheline of a processor. */ CACHELINE_PAD(SIZEOF(global_latch_t), 0) /* start next latch at a different cacheline than previous fields */ global_latch_t io_in_prog_latch; /* UNIX only: write in progress indicator */ CACHELINE_PAD(SIZEOF(global_latch_t), 1) /* pad enough space so next latch falls in different cacheline */ global_latch_t fsync_in_prog_latch; /* fsync in progress indicator */ CACHELINE_PAD(SIZEOF(global_latch_t), 2) /* pad enough space so next non-filler byte falls in different cacheline */ /**********************************************************************************************/ /* Important: must keep header structure quadword (8 byte) aligned for buffers used in QIO's */ /**********************************************************************************************/ unsigned char buff[1]; /* Actually buff[size] */ } jnl_buffer; #define FIX_NONZERO_FREE_UPDATE_PID(csa, jbp) \ { \ assert(csa->now_crit); /* hold crit before manipulating freeaddr/free */ \ assert(jbp->free_update_pid); \ UNIX_ONLY(assert(!is_proc_alive(jbp->free_update_pid, 0));) \ VMS_ONLY(assert(FALSE);) /* secshr_db_clnup should have cleaned up this field even in case of STOP/ID */ \ if ((jbp->freeaddr % jbp->size) != jbp->free) \ { /* Previous process in jnl_write got killed after incrementing freeaddr but before incrementing \ * free. Recalculate jbp->free based on current value of jbp->freeaddr. */ \ jbp->free = jbp->freeaddr % jbp->size; \ jbp->free_update_pid = 0; \ } \ DBG_CHECK_JNL_BUFF_FREEADDR(jbp); \ } #define DBG_CHECK_JNL_BUFF_FREEADDR(jbp) \ { \ assert((jbp->freeaddr % jbp->size) == jbp->free); \ assert((jbp->freeaddr >= jbp->dskaddr) \ || (gtm_white_box_test_case_enabled \ && (WBTEST_JNL_FILE_LOST_DSKADDR == gtm_white_box_test_case_number))); \ } #ifdef DB64 # ifdef __osf__ # pragma pointer_size(save) # pragma pointer_size(long) # else # error UNSUPPORTED PLATFORM # endif #endif typedef jnl_buffer *jnl_buffer_ptr_t; typedef token_build *token_build_ptr_t; #ifdef DB64 # ifdef __osf__ # pragma pointer_size(restore) # endif #endif typedef struct jnl_private_control_struct { jnl_buffer_ptr_t jnl_buff; /* pointer to shared memory */ gd_region *region; /* backpointer to region head */ fd_type channel, /* output channel, aka fd in UNIX */ old_channel; /* VMS only - for dealing with deferred deassign */ gd_id fileid; /* currently initialized and used only by source-server */ vms_lock_sb *jnllsb; /* VMS only */ uint4 pini_addr, /* virtual on-disk address for JRT_PINI record, if journaling */ new_freeaddr; int4 temp_free; /* M Temp copy of free relative index until full write done */ double filler_q0; /* reset QUAD end mainline */ int4 new_dsk; /* A VMS only */ uint4 new_dskaddr; /* A VMS only */ int4 status; /* A for error reporting */ volatile boolean_t dsk_update_inprog; /* A VMS only */ volatile boolean_t qio_active; /* jnl buffer write in progress in THIS process (recursion indicator) */ boolean_t fd_mismatch; /* TRUE when jpc->channel does not point to the active journal */ volatile boolean_t sync_io; /* TRUE if the process is using O_SYNC/O_DSYNC for this jnl (UNIX) */ /* TRUE if writers open NOCACHING to bypass XFC cache (VMS) */ boolean_t error_reported; /* TRUE if jnl_file_lost already reported the journaling error */ uint4 status2; /* for secondary error status, currently used only in VMS */ uint4 cycle; /* private copy of the number of this journal file generation */ } jnl_private_control; typedef enum { JNL_KILL, JNL_SET, JNL_ZKILL, # ifdef GTM_TRIGGER JNL_ZTWORM, JNL_ZTRIG, # endif JA_MAX_TYPES } jnl_action_code; typedef enum { #define MUEXT_TABLE_ENTRY(muext_rectype, code0, code1) muext_rectype, #include "muext_rec_table.h" #undef MUEXT_TABLE_ENTRY MUEXT_MAX_TYPES /* Total number of EXTRACT JOURNAL record types */ } muextract_type; typedef struct { jnl_action_code operation; uint4 nodeflags; } jnl_action; #define JNL_FENCE_LIST_END ((sgmnt_addrs *)-1L) typedef struct { sgmnt_addrs *fence_list; int level; token_num token; seq_num strm_seqno; /* valid only in case of replication. uninitialized in case of ZTP */ } jnl_fence_control; typedef struct { uint4 jrec_type : 8; /* Offset:0 :: Actually, enum jnl_record_type */ uint4 forwptr : 24; /* Offset:1 :: Offset to beginning of next record */ off_jnl_t pini_addr; /* Offset:4 :: Offset in the journal file which contains pini record */ jnl_tm_t time; /* Offset:8 :: 4-byte time stamp both for UNIX and VMS */ uint4 checksum; /* Offset:12 :: Generated from journal record */ trans_num tn; /* Offset:16 */ } jrec_prefix; /* 24-byte */ typedef struct { uint4 backptr : 24; /* Offset to beginning of current record */ uint4 suffix_code : 8; /* JNL_REC_SUFFIX_CODE */ } jrec_suffix; /* 4-byte */ typedef union { seq_num jnl_seqno; token_num token; } token_seq_t; typedef struct { char label[SIZEOF(JNL_LABEL_TEXT) - 1]; char is_little_endian; /* this field's offset (JNL_HDR_ENDIAN_OFFSET) should not change * across journal versions and is checked right after reading the header. */ char filler_align8[7]; jnl_process_vector who_created, /* Process who created */ who_opened; /* Process who last opened */ jnl_proc_time bov_timestamp, /* 8-byte time when journal was created */ eov_timestamp; /* 8-byte time when journal was last updated Updated by cre_jnl_file/jnl_file_extend/jnl_file_close */ trans_num bov_tn, /* Beginning journal record's transaction number */ eov_tn; /* End transaction number. Updated by cre_jnl_file/jnl_file_extend/jnl_file_close */ seq_num start_seqno; /* reg_seqno when this journal file was created */ seq_num end_seqno; /* reg_seqno when this journal file was closed or last extended. Updated by cre_jnl_file/jnl_file_extend/jnl_file_close */ off_jnl_t end_of_data; /* Offset of beginning of last record. Updated by cre_jnl_file/jnl_file_extend/jnl_file_close */ off_jnl_t prev_recov_end_of_data; /* Recovered/Rolled back journal's turn around point's offset. This offset was supposed to have EOF_RECORD before recover switched journal. A non-zero value means this journal was recovered and had the turn around point. */ off_jnl_t virtual_size; /* Allocation + n * Extension (in blocks). jnl_file_extend updates it */ boolean_t crash; /* crashed before jnl_file_close() completed */ boolean_t recover_interrupted; /* true when recover creates the journal file; false after success. */ off_jnl_t turn_around_offset; /* At turn around point journal record's (EPOCH) offset */ jnl_tm_t turn_around_time; /* At turn around point journal record's timestamp */ boolean_t before_images; /* before image enabled in this journal */ uint4 alignsize; /* align size of journal (where a valid record start) */ int4 epoch_interval; /* Time between successive epochs in epoch-seconds */ int4 repl_state; /* To state whether replication is turned on for this journal file */ uint4 autoswitchlimit;/* Limit in disk blocks (max 4GBytes) when jnl should be auto switched */ uint4 jnl_alq; /* initial allocation (in blocks) */ uint4 jnl_deq; /* extension (in blocks) */ #ifdef VMS boolean_t update_disabled;/* If the secondary side has database update disabled. For rollback. */ #else boolean_t filler_update_disabled; /* obsoleted as part of multi-site replication changes */ #endif int4 max_jrec_len; /* Maximum length in bytes of a journal record. * Although computed from the database block size, we need this * stored as well in case database is not available */ uint4 data_file_name_length; /* Length of data_file_name */ uint4 prev_jnl_file_name_length; /* Length of prev_jnl_file_name */ uint4 next_jnl_file_name_length; /* Length of next_jnl_file_name */ uint4 checksum; /* Calculate from journal file id */ uint4 prev_recov_blks_to_upgrd_adjust; /* amount to adjust filehdr "blks_to_upgrd" if ever * backward recovery goes back past this journal file */ unsigned char data_file_name[JNL_NAME_SIZE]; /* Database file name */ unsigned char prev_jnl_file_name[JNL_NAME_SIZE]; /* Previous generation journal file name */ unsigned char next_jnl_file_name[JNL_NAME_SIZE]; /* Next generation journal file name */ /* encryption related fields */ uint4 is_encrypted; char encryption_hash[GTMCRYPT_RESERVED_HASH_LEN]; /* The below two arrays are unused in VMS but defined there to keep the layout similar between Unix & VMS */ seq_num strm_start_seqno[MAX_SUPPL_STRMS]; seq_num strm_end_seqno[MAX_SUPPL_STRMS]; /* filler remaining */ char filler[440]; } jnl_file_header; typedef struct { int4 status, alloc, extend, buffer; sgmnt_data_ptr_t csd; seq_num reg_seqno; unsigned char jnl[JNL_NAME_SIZE], *fn; uint4 max_jrec_len; short fn_len, jnl_len, jnl_def_len; bool before_images; bool filler_bool[1]; uint4 alignsize; int4 autoswitchlimit; /* limit in disk blocks (8388607 blocks) * when jnl should be auto switched */ int4 epoch_interval; /* Time between successive epochs in epoch-seconds */ char *prev_jnl; int4 prev_jnl_len; int4 jnl_state; /* current csd->jnl_state */ int4 repl_state; uint4 status2; /* for secondary error status information in VMS */ boolean_t no_rename; boolean_t no_prev_link; int4 blks_to_upgrd; /* Blocks not at current block version level */ uint4 checksum; uint4 free_blocks; /* free blocks counter at time of epoch */ uint4 total_blks; /* total blocks counter at time of epoch */ uint4 is_encrypted; char encryption_hash[GTMCRYPT_HASH_LEN]; sgmnt_addrs *csa; } jnl_create_info; /* Journal record definitions */ #define jnl_str_len_t uint4 /* 4 byte length (which is in turn split into bit fields below) */ /* Bit masks for the "nodeflags" field. Note that there is no flag to indicate whether this update actually invoked any triggers. * That is because we have to format the journal record BEFORE invoking any triggers (that way the triggering update comes ahead * of its corresponding triggered updates in the journal file as this ordering is relied upon by the update process) and as part * of formatting, we also compute the checksum that includes the "nodeflags" field and so fixing this field AFTER trigger * invocation to reflect if any triggers were invoked would mean recomputing the checksum all over again. Currently there is no * need for the "triggers actually invoked" bit. If it is later desired, care should be taken to recompute the checksum. */ #define JS_NOT_REPLICATED_MASK (1 << 0) /* 1 if this update should NOT be replicated. * All updates done inside of a trigger and a SET redo (because of changes to $ztval) * fall in this category. */ #define JS_HAS_TRIGGER_MASK (1 << 1) /* 1 if the global being updated had at least one trigger defined (not necessarily * invoked for this particular update) */ #define JS_NULL_ZTWORM_MASK (1 << 2) /* 1 if $ZTWORMHOLE for this update should be "" string, 0 otherwise */ #define JS_SKIP_TRIGGERS_MASK (1 << 3) /* 1 if MUPIP LOAD update so triggers are not invoked on replay by update process */ #define JS_IS_DUPLICATE (1 << 4) /* 1 if this SET or KILL is a duplicate. In case of a SET, this is a duplicate set. * In case of a KILL, it is a kill of a non-existing node aka duplicate kill. * Note that the dupkill occurs only in case of the update process. In case of GT.M, * the KILL is entirely skipped. In both duplicate sets or kills, only a journal * record is written, the database is untouched. */ #define JS_MAX_MASK (1 << 8) /* max of 8 bits we have for mask */ /* Note that even though mumps_node, ztworm_str, ztrig_str and align_str are members defined as type "jnl_string" below, * the "nodeflags" field is initialized to non-zero values ONLY in the case of the mumps_node member. * For ztworm_str and align_str, nodeflags is guaranteed to be zero so the 24-bit "length" member * can even be used as a 32-bit length (if necessary) without issues. This is why nodeflags is * defined in a different order (BEFORE or AFTER the "length" member) based on big-endian or little-endian. */ typedef struct { # ifdef BIGENDIAN unsigned int nodeflags : 8; unsigned int length : 24; # else unsigned int length : 24; unsigned int nodeflags : 8; # endif char text[1]; /* Actually text[length] */ } jnl_string; typedef struct jnl_format_buff_struct { que_ent free_que; struct jnl_format_buff_struct *next; # ifdef GTM_TRIGGER struct jnl_format_buff_struct *prev; # endif enum jnl_record_type rectype; int4 record_size; int4 hi_water_bsize; char *buff; uint4 checksum; jnl_action ja; # ifdef GTM_CRYPT char *alt_buff; /* for storing the unencrypted jnl *SET and *KILL records to be pushed * into the jnl pool. */ # endif } jnl_format_buffer; /* All fixed size records are 8-byte-multiple size. * All variable size records are made 8-byte multiple size by run-time process */ /* struct_jrec_upd for non-TP, TP or ZTP. For replication we use 8-byte jnl_seqno. Otherwise we use 8-byte token. * Currently we dont support ZTP + replication. */ typedef struct /* variable length */ { jrec_prefix prefix; token_seq_t token_seq; /* must start at 8-byte boundary */ seq_num strm_seqno; /* non-zero only if this is a supplementary instance in which case this # * reflects the 60-bit sequence number corresponding to this update on the * originating primary + higher order 4-bits reflecting the stream #. */ uint4 update_num; /* 'n' where this is the nth journaled update (across all regions) in this TP * transaction. n=1 for the first update inside TP, 2 for the second update * inside TP and so on. Needed so journal recovery and update process can play * all the updates inside of one TP transaction in the exact same order as GT.M. */ unsigned short filler_short; unsigned short num_participants; /* # of regions that wrote a TCOM record in their jnl files. * Currently written only for TSET/TKILL/TZTWORM records. * Uninitialized for all other types of SET/KILL/ZTWORM records. */ jnl_string mumps_node; /* For set/kill/zkill : {jnl_str_len_t key_len, char key[key_len]} */ /* For set additionally : {mstr_len_t data_len, char data[data_len]} */ } struct_jrec_upd; /* $ztwormhole record */ typedef struct /* variable length */ { jrec_prefix prefix; token_seq_t token_seq; /* must start at 8-byte boundary */ seq_num strm_seqno; /* see "struct_jrec_upd" for comment on the purpose of this field */ uint4 update_num; /* 'n' where this is the nth journaled update (across all regions) in this TP * transaction. n=1 for the first update inside TP, 2 for the second update * inside TP and so on. Needed so journal recovery and update process can play * all the updates inside of one TP transaction in the exact same order as GT.M. */ unsigned short filler_short; unsigned short num_participants; /* # of regions that wrote a TCOM record in their jnl files. * Currently written only for TSET/TKILL/TZTWORM records. * Uninitialized for all other types of SET/KILL/ZTWORM records. */ jnl_string ztworm_str; /* jnl_str_len_t ztworm_str_len, char ztworm_str[ztworm_str_len]} */ } struct_jrec_ztworm; #define INVALID_UPDATE_NUM (uint4)-1 typedef struct /* variable length */ { jrec_prefix prefix; block_id blknum; uint4 bsiz; enum db_ver ondsk_blkver; /* Previous version of block from cache_rec */ int4 filler; char blk_contents[1]; /* Actually blk_contents[bsiz] */ } struct_jrec_blk; typedef struct /* variable length */ { jrec_prefix prefix; jnl_string align_str; /* Note: Actual string (potentially 0-length too) follows the align_string and then jrec_suffix */ } struct_jrec_align; /* Please change the "GBLDEF struct_jrec_tcom" initialization, if below is changed */ typedef struct /* fixed length */ { jrec_prefix prefix; token_seq_t token_seq; /* must start at 8-byte boundary */ seq_num strm_seqno; /* see "struct_jrec_upd" for comment on the purpose of this field */ unsigned short filler_short; unsigned short num_participants; /* # of regions that wrote a TCOM record in their jnl files */ char jnl_tid[TID_STR_SIZE]; jrec_suffix suffix; } struct_jrec_tcom; /* Please change the "static struct_jrec_ztcom" initialization in op_ztcommit.c, if below is changed */ typedef struct /* fixed length */ { jrec_prefix prefix; token_num token; /* must start at 8-byte boundary */ seq_num filler_8bytes; /* To mirror tcom layout. It is ok to waste space because ztcom is * obsoleted record. This keeps logic (e.g. MUR_TCOM_TOKEN_PROCESSING) faster * by avoiding if checks (of whether the rectype is TCOM or ZTCOM and accordingly * taking the appropriate offset). */ unsigned short filler_short; unsigned short participants; /* # of regions that wrote ZTCOM record in their jnl files for this fenced tn */ jrec_suffix suffix; } struct_jrec_ztcom; /* Below are different inctn_detail_*_t type definitions based on the inctn record opcode. * Each of them need to ensure the following. * a) SIZEOF(inctn_detail_*_t) is identical. * b) "opcode" member is at the same offset. * c) "suffix" is the last member. * Any new inctn_detail_*_t type definitions should have corresponding code changes in jnl_write_inctn_rec.c */ typedef struct { block_id blknum; /* block that got upgraded or downgraded (opcode = inctn_blk*grd) */ uint4 filler_uint4; unsigned short filler_short; unsigned short opcode; jrec_suffix suffix; } inctn_detail_blknum_t; typedef struct { int4 blks_to_upgrd_delta; /* Delta to adjust csd->blks_to_upgrade (opcode = inctn_gdsfilext_*) */ uint4 filler_uint4; unsigned short filler_short; unsigned short opcode; jrec_suffix suffix; } inctn_detail_blks2upgrd_t; typedef union { inctn_detail_blknum_t blknum_struct; inctn_detail_blks2upgrd_t blks2upgrd_struct; } inctn_detail_t; typedef struct /* fixed length */ { jrec_prefix prefix; inctn_detail_t detail; /* jrec_suffix is already part of inctn_detail_t */ } struct_jrec_inctn; typedef struct /* fixed length */ { jrec_prefix prefix; jnl_process_vector process_vector[JPV_COUNT]; int4 filler; jrec_suffix suffix; } struct_jrec_pini; typedef struct /* fixed length */ { jrec_prefix prefix; uint4 filler; jrec_suffix suffix; } struct_jrec_pfin; /* Following 3 are same structures. In case we change it in future, let's define them separately */ typedef struct /* fixed length */ { jrec_prefix prefix; seq_num jnl_seqno; /* must start at 8-byte boundary */ seq_num strm_seqno; /* see "struct_jrec_upd" for comment on the purpose of this field */ uint4 filler; jrec_suffix suffix; } struct_jrec_null; typedef struct /* fixed length */ { jrec_prefix prefix; seq_num jnl_seqno; /* must start at 8-byte boundary */ uint4 blks_to_upgrd; /* blocks-to-upgrade counter at time of epoch */ uint4 free_blocks; /* free blocks counter at time of epoch */ uint4 total_blks; /* total blocks counter at time of epoch */ boolean_t fully_upgraded; /* cs_data->fully_upgraded at the time of epoch */ seq_num strm_seqno[MAX_SUPPL_STRMS]; /* seqno of each possible supplementary stream at epoch time. * used by rollback to restore seqnos on the database. */ uint4 filler; /* so as to make the EPOCH record aligned to 8 byte boundary */ jrec_suffix suffix; } struct_jrec_epoch; typedef struct /* fixed length */ { jrec_prefix prefix; seq_num jnl_seqno; /* must start at 8-byte boundary */ uint4 filler; jrec_suffix suffix; } struct_jrec_eof; typedef struct /* fixed length */ { jrec_prefix prefix; /* 24 bytes */ uint4 orig_total_blks; uint4 orig_free_blocks; uint4 total_blks_after_trunc; jrec_suffix suffix; /* 4 bytes */ } struct_jrec_trunc; typedef union { jrec_prefix prefix; struct_jrec_upd jrec_set_kill; /* JRT_SET or JRT_KILL or JRT_ZTRIG record will use this format */ struct_jrec_ztworm jrec_ztworm; struct_jrec_blk jrec_pblk, jrec_aimg; struct_jrec_align jrec_align; /** All below are fixed size and above are variable size records */ struct_jrec_tcom jrec_tcom; struct_jrec_ztcom jrec_ztcom; struct_jrec_inctn jrec_inctn; struct_jrec_pini jrec_pini; struct_jrec_pfin jrec_pfin; struct_jrec_null jrec_null; struct_jrec_epoch jrec_epoch; struct_jrec_eof jrec_eof; struct_jrec_trunc jrec_trunc; } jnl_record; /* Macro to access fixed size record's size */ #define TCOM_RECLEN SIZEOF(struct_jrec_tcom) #define ZTCOM_RECLEN SIZEOF(struct_jrec_ztcom) #define INCTN_RECLEN SIZEOF(struct_jrec_inctn) #define PINI_RECLEN SIZEOF(struct_jrec_pini) #define PFIN_RECLEN SIZEOF(struct_jrec_pfin) #define NULL_RECLEN SIZEOF(struct_jrec_null) #define EPOCH_RECLEN SIZEOF(struct_jrec_epoch) #define EOF_RECLEN SIZEOF(struct_jrec_eof) #define TRUNC_RECLEN SIZEOF(struct_jrec_trunc) /* Macro to access variable size record's fixed part's size */ #define FIXED_ZTWORM_RECLEN OFFSETOF(struct_jrec_ztworm, ztworm_str) #define FIXED_UPD_RECLEN OFFSETOF(struct_jrec_upd, mumps_node) #define MIN_ALIGN_RECLEN (OFFSETOF(struct_jrec_align, align_str.text[0]) + JREC_SUFFIX_SIZE) #define FIXED_ALIGN_RECLEN OFFSETOF(struct_jrec_align, align_str.text[0]) #define FIXED_BLK_RECLEN OFFSETOF(struct_jrec_blk, blk_contents[0]) #define FIXED_PBLK_RECLEN OFFSETOF(struct_jrec_blk, blk_contents[0]) #define FIXED_AIMG_RECLEN OFFSETOF(struct_jrec_blk, blk_contents[0]) #define MIN_PBLK_RECLEN (OFFSETOF(struct_jrec_blk, blk_contents[0]) + JREC_SUFFIX_SIZE) #define MIN_AIMG_RECLEN (OFFSETOF(struct_jrec_blk, blk_contents[0]) + JREC_SUFFIX_SIZE) #define JREC_PREFIX_SIZE SIZEOF(jrec_prefix) #define JREC_SUFFIX_SIZE SIZEOF(jrec_suffix) #define MIN_JNLREC_SIZE (JREC_PREFIX_SIZE + JREC_SUFFIX_SIZE) #define JREC_PREFIX_UPTO_LEN_SIZE (offsetof(jrec_prefix, pini_addr)) /* JNL_FILE_TAIL_PRESERVE macro indicates maximum number of bytes to ensure allocated at the end of the journal file * to store the journal records that will be written whenever the journal file gets closed. * (i) Any process closing the journal file needs to write at most one PINI, one EPOCH, one PFIN and one EOF record * In case of wcs_recover extra INCTN will be written * (ii) We may need to give room for twice the above space to accommodate the EOF writing by a process that closes the journal * and the EOF writing by the first process that reopens it and finds no space left and switches to a new journal. * (iii) We may need to write one ALIGN record at the most since the total calculated from (i) and (ii) above is * less than the minimum alignsize that we support (asserted before using JNL_FILE_TAIL_PRESERVE in macros below) * The variable portion of this ALIGN record can get at the most equal to the maximum of the sizes of the * PINI/EPOCH/PFIN/EOF record. We know PINI_RECLEN is maximum of EPOCH_RECLEN, PFIN_RECLEN, EOF_RECLEN (this * is in fact asserted in gvcst_init.c). */ #define JNL_FILE_TAIL_PRESERVE (MIN_ALIGN_RECLEN + (PINI_RECLEN + EPOCH_RECLEN + INCTN_RECLEN + \ PFIN_RECLEN + EOF_RECLEN) * 2 + PINI_RECLEN) typedef struct set_jnl_options_struct { int cli_journal, cli_enable, cli_on, cli_replic_on; boolean_t alignsize_specified, allocation_specified, autoswitchlimit_specified, image_type_specified, /* beofre/nobefore option specified */ buffer_size_specified, epoch_interval_specified, extension_specified, filename_specified, sync_io_specified, yield_limit_specified; /* since jnl_create_info does not have following fields, we need them here */ boolean_t sync_io; int4 yield_limit; } set_jnl_options; /* rlist_state needed to be moved here to use with mu_set_reglist */ enum rlist_state { NONALLOCATED, ALLOCATED, DEALLOCATED }; /* mu_set_reglist needed to be moved here for the journal specific fields */ /* ATTN: the first four items in this structure need to be identical to those * in structure tp_region in tp.h. */ typedef struct mu_set_reglist { struct mu_set_reglist *fPtr; /* all fields after this are used for mupip_set_journal.c */ gd_region *reg; char unique_id[UNIQUE_ID_SIZE]; enum rlist_state state; sgmnt_data_ptr_t sd; bool exclusive; /* standalone access is required for this region */ int fd; enum jnl_state_codes jnl_new_state; enum repl_state_codes repl_new_state; boolean_t before_images; } mu_set_rlist; /* The enum codes below correspond to code-paths that can call set_jnl_file_close() in VMS */ typedef enum { SET_JNL_FILE_CLOSE_BACKUP = 1, /* just for safety a non-zero value to start with */ SET_JNL_FILE_CLOSE_SETJNL, SET_JNL_FILE_CLOSE_EXTEND, SET_JNL_FILE_CLOSE_RUNDOWN, SET_JNL_FILE_CLOSE_INVALID_OP } set_jnl_file_close_opcode_t; typedef void (*pini_addr_reset_fnptr)(sgmnt_addrs *csa); typedef struct { token_num mur_jrec_seqno; /* This is jnl_seqno of the current record that backward * recovery/rollback is playing in its forward phase. */ token_num mur_jrec_strm_seqno; /* This is the strm_seqno of the current record that backward * recovery/rollback is playing in its forward phase. */ VMS_ONLY(seq_num max_resync_seqno;) /* for update process and rollback fetchresync */ unsigned short filler_short; unsigned short mur_jrec_participants; jnl_tm_t gbl_jrec_time; jnl_tm_t mur_tp_resolve_time; /* tp resolve time as determined by journal recovery. * Time of the point upto which a region will be processed for * TP token resolution for backward or forward recover. * Note : This is what prevents user to change system time. */ boolean_t forw_phase_recovery; boolean_t mur_rollback; /* a copy of mur_options.rollback to be accessible to runtime code */ boolean_t mupip_journal; /* the current command is a MUPIP JOURNAL command */ boolean_t dont_reset_gbl_jrec_time; /* Do not reset gbl_jrec_time */ pini_addr_reset_fnptr mur_pini_addr_reset_fnptr; /* function pointer to invoke "mur_pini_addr_reset" */ uint4 cumul_jnl_rec_len; /* cumulative length of the replicated journal records * for the current TP or non-TP transaction */ boolean_t wait_for_jnl_hard; uint4 tp_ztp_jnl_upd_num; /* Incremented whenever a journaled update happens inside of * TP or ZTP. Copied over to the corresponding journal record * to record the sequence of all updates inside TP/ZTP transaction. */ uint4 mur_jrec_nodeflags; /* copy of "nodeflags" from jnl record currently being played */ # ifdef GTM_TRIGGER unsigned char *prev_ztworm_ptr; /* Non-NULL if at least one ztwormhole record was successfully * formatted in this transaction. Note that ZTWORMHOLE records are * formatted ONLY in case of journaled & replicated databases. * 1. If replicated database is unencrypted, this points to * jfb->buff + FIXED_UPD_RECLEN * 2. If replicated database is encrypted, this points to * jfb->alt_buff + FIXED_UPD_RECLEN * If no ztwormhole record is yet formatted, then points to NULL */ unsigned char *save_ztworm_ptr; /* copy of prev_ztworm_ptr saved until we know for sure whether * a ZTWORMHOLE journal record will be written or not. */ # endif # ifdef DEBUG boolean_t mur_fences_none; /* a copy of mur_options.fences to be accessible to runtime code */ uint4 cumul_index; uint4 cu_jnl_index; uint4 max_tp_ztp_jnl_upd_num; /* Max of all values processed in this * potentially multi-region transaction. Used only by jnl recovery. */ boolean_t mur_options_forward; /* a copy of mur_options.forward to be accessible to GT.M runtime */ # endif # ifdef UNIX boolean_t onlnrlbk; /* TRUE if ONLINE ROLLBACK */ # endif boolean_t mur_extract; /* a copy of mur_options.extr[0] to be accessible to GTM runtime*/ boolean_t save_dont_reset_gbl_jrec_time; /* save a copy of dont_reset_gbl_jrec_time */ } jnl_gbls_t; #define JNL_SHARE_SIZE(X) (JNL_ALLOWED(X) ? \ (ROUND_UP(JNL_NAME_EXP_SIZE + SIZEOF(jnl_buffer), OS_PAGE_SIZE) \ + ROUND_UP(((sgmnt_data_ptr_t)X)->jnl_buffer_size * DISK_BLOCK_SIZE, \ OS_PAGE_SIZE) + OS_PAGE_SIZE) : 0) /* pass address of jnl_buffer to get address of expanded jnl file name */ #define JNL_GDID_PVT(CSA) ((CSA)->jnl->fileid) #ifdef UNIX #define JNL_GDID_PTR(CSA) ((gd_id_ptr_t)(&((CSA)->nl->jnl_file.u))) #else #define JNL_GDID_PTR(CSA) ((gd_id_ptr_t)(&((CSA)->nl->jnl_file.jnl_file_id))) #endif /* Note that since "cycle" (in jpc and jb below) can rollover the 4G limit back to 0, it should * only be used to do "!=" checks and never to do ordered checks like "<", ">", "<=" or ">=". */ #define JNL_FILE_SWITCHED(JPC) ((JPC)->cycle != (JPC)->jnl_buff->cycle) #define REG_STR "region" #define FILE_STR "database file" /* Given a journal record, get_jnl_seqno returns the jnl_seqno field * Now all replication type records, EOF and EPOCH have the jnl_seqno at the same offset. * Modify the macro GET_JNL_SEQNO if offset of jnl_seqno is changed for any journal records */ #define GET_JNL_SEQNO(j) (((jnl_record *)(j))->jrec_null.jnl_seqno) #define GET_STRM_SEQNO(j) (((jnl_record *)(j))->jrec_null.strm_seqno) #define GET_REPL_JNL_SEQNO(j) (IS_REPLICATED(((jrec_prefix *)j)->jrec_type) ? GET_JNL_SEQNO(j) : 0) /* For MUPIP JOURNAL -ROLLBACK, getting the strm_reg_seqno from the file header is not as straightforward * as accessing csd->strm_reg_seqno[idx]. This is because it increments this field in mur_output_record even * before we reach t_end/tp_tend. That is done for convenience of the implementation. But this assumes that the * commit has actually completed. Therefore, in case we need to invoke jnl_file_extend() inside t_end/tp_tend even * before the commit, we would see an incorrect value of csd->strm_reg_seqno[idx]. In that case, we use the * global variable jgbl.mur_jrec_strm_seqno to identify if the strm_reg_seqno[idx] value is 1 more than that and * if so return 1 lesser than that as the real strm_reg_seqno[idx]. This is used by routines that write journal * records (EPOCH, jfh->strm_end_seqno etc.) to write the correct strm_seqno. Not doing so will cause the strm_seqno * to be higher than necessary and confuse everything else (including rollback) as far as replication is concerned. * Note: We check for process_exiting to differentiate between calls made from mur_close_files() to before. Once we * reach mur_close_files, we should no longer be in an active transaction and so we dont need to make any adjustments. * VMS does not support supplementary instances so the below macro does not apply there at all. */ #ifdef UNIX #define MUR_ADJUST_STRM_REG_SEQNO_IF_NEEDED(CSD, DST) \ { \ int strm_num; \ seq_num strm_seqno; \ \ GBLREF int process_exiting; \ \ if (jgbl.mur_jrec_strm_seqno && !process_exiting) \ { \ assert(jgbl.mur_rollback); \ VMS_ONLY(assert(FALSE);) \ strm_seqno = jgbl.mur_jrec_strm_seqno; \ strm_num = GET_STRM_INDEX(strm_seqno); \ strm_seqno = GET_STRM_SEQ60(strm_seqno); \ if (CSD->strm_reg_seqno[strm_num] == (strm_seqno + 1)) \ { \ assert(DST[strm_num] == (strm_seqno + 1)); \ DST[strm_num] = strm_seqno; \ } \ } \ } #else #define MUR_ADJUST_STRM_REG_SEQNO_IF_NEEDED(CSD, DST) #endif /* Given a journal record, GET_TN returns the tn field */ #define GET_TN(j) (((*jrec_prefix)(j))->prefix.tn) /* In t_end(), we need to write the after-image if DSE or mupip recover/rollback is playing it. * But to write it out, we should have it already built before bg_update(). * Hence, we pre-build the block here itself before invoking t_end(). */ #define BUILD_AIMG_IF_JNL_ENABLED(CSD, TN) \ { \ GBLREF cw_set_element cw_set[]; \ GBLREF unsigned char cw_set_depth; \ GBLREF jnl_format_buffer *non_tp_jfb_ptr; \ \ cw_set_element *cse; \ \ if (JNL_ENABLED(CSD)) \ { \ assert(1 == cw_set_depth); /* Only DSE uses this macro and it updates one block at a time */ \ cse = (cw_set_element *)(&cw_set[0]); \ cse->new_buff = (unsigned char *)non_tp_jfb_ptr->buff; \ gvcst_blk_build(cse, (uchar_ptr_t)cse->new_buff, TN); \ cse->done = TRUE; \ } \ } /* In Unix, the journal file header size is currently set to 64K so it is aligned with any possible filesystem block size * known at this point. This will help us do aligned writes to the journal file header as well as the journal file contents * without needing to mix both of them in the same aligned disk write. In VMS, we continue with 512-byte alignment so no change. * Note that the journal_file_header structure is only 2K currently and is captured using the REAL_JNL_HDR_LEN macro while * the padded 64K file header is captured using the JNL_HDR_LEN macro. Use either one as appropriate in the code. Both of them * are identical in VMS where it is currently 2K. */ #define REAL_JNL_HDR_LEN SIZEOF(jnl_file_header) #ifdef UNIX # define JNL_HDR_LEN 64 * 1024 #elif defined(VMS) # define JNL_HDR_LEN REAL_JNL_HDR_LEN #endif #define JNL_FILE_FIRST_RECORD JNL_HDR_LEN /* Minimum possible journal file size */ #define MIN_JNL_FILE_SIZE (JNL_HDR_LEN + PINI_RECLEN + EPOCH_RECLEN + PFIN_RECLEN + EOF_RECLEN) /* maximum required journal file size (in 512-byte blocks), if the current transaction was the only one in a fresh journal file */ #define MAX_REQD_JNL_FILE_SIZE(tot_jrec_size) DIVIDE_ROUND_UP((tot_jrec_size + MIN_JNL_FILE_SIZE), DISK_BLOCK_SIZE) /* this macro aligns the input size to account that journal file sizes can increase only in multiples of the extension size */ #define ALIGNED_ROUND_UP(tmp_tot_jrec_size, jnl_alq, jnl_deq) \ (((tmp_tot_jrec_size) <= (jnl_alq) || !(jnl_deq)) \ ? (jnl_alq) \ : ((jnl_alq) + ROUND_UP((tmp_tot_jrec_size) - (jnl_alq), (jnl_deq)))) /* this macro aligns the input size to account that journal file sizes can increase only in multiples of the extension size */ #define ALIGNED_ROUND_DOWN(tmp_tot_jrec_size, jnl_alq, jnl_deq) \ (((tmp_tot_jrec_size) <= (jnl_alq) || !(jnl_deq)) \ ? (jnl_alq) \ : ((jnl_alq) + ROUND_DOWN((tmp_tot_jrec_size) - (jnl_alq), (jnl_deq)))) /* the following macro uses 8-byte quantities (gtm_uint64_t) to perform additions that might cause a 4G overflow */ #define DISK_BLOCKS_SUM(freeaddr, jrec_size) DIVIDE_ROUND_UP((((gtm_uint64_t)(freeaddr)) + (jrec_size)), DISK_BLOCK_SIZE) #if defined(UNIX) /* For future portability JNLBUFF_ALLOC is defined in jnl.h instead of jnlsp.h */ #define JPC_ALLOC(csa) \ { \ csa->jnl = (jnl_private_control *)malloc(SIZEOF(*csa->jnl)); \ memset(csa->jnl, 0, SIZEOF(*csa->jnl)); \ } #define ASSERT_JNLFILEID_NOT_NULL(csa) \ { \ assert(0 != csa->nl->jnl_file.u.inode); \ assert(0 != csa->nl->jnl_file.u.device); \ } #define NULLIFY_JNL_FILE_ID(csa) \ { \ csa->nl->jnl_file.u.inode = 0; \ csa->nl->jnl_file.u.device = 0; \ } #elif defined(VMS) #define JPC_ALLOC(csa) \ { \ vms_lock_sb *tmp_jnllsb; \ if (NULL == csa->jnl) \ { \ csa->jnl = (jnl_private_control *)malloc(SIZEOF(*csa->jnl)); \ memset(csa->jnl, 0, SIZEOF(*csa->jnl)); \ csa->jnl->jnllsb = malloc(SIZEOF(vms_lock_sb)); \ } else \ { \ tmp_jnllsb = csa->jnl->jnllsb; \ memset(csa->jnl, 0, SIZEOF(*csa->jnl)); \ csa->jnl->jnllsb = tmp_jnllsb; \ } \ memset(csa->jnl->jnllsb, 0, SIZEOF(vms_lock_sb)); \ } #define ASSERT_JNLFILEID_NOT_NULL(csa) assert(0 != memcmp(csa->nl->jnl_file.jnl_file_id.fid, zero_fid, SIZEOF(zero_fid))); #define NULLIFY_JNL_FILE_ID(csa) memset(&csa->nl->jnl_file.jnl_file_id, 0, SIZEOF(gds_file_id)) #endif #define JNL_INIT(csa, reg, csd) \ { \ csa->jnl_state = csd->jnl_state; \ csa->jnl_before_image = csd->jnl_before_image; \ csa->repl_state = csd->repl_state; \ if JNL_ALLOWED(csa) \ { \ JPC_ALLOC(csa); \ csa->jnl->region = reg; \ csa->jnl->jnl_buff = (jnl_buffer_ptr_t)((sm_uc_ptr_t)(csa->nl) + NODE_LOCAL_SPACE(csd) + JNL_NAME_EXP_SIZE); \ csa->jnl->channel = NOJNL; \ } else \ csa->jnl = NULL; \ } #define JNL_FD_CLOSE(CHANNEL, RC) \ { \ fd_type lcl_channel; \ \ /* Reset incoming channel BEFORE closing it. This way, if we get interrupted BEFORE the close but \ * after we have reset channel, we could at most end up with a file descriptor leak. Doing it the \ * other way around could cause us to close the channel but yet have a dangling pointer to it that \ * could result in more than one close of the same file descriptor where the second close could \ * be on some other valid open file descriptor. \ */ \ lcl_channel = CHANNEL; \ CHANNEL = NOJNL; \ F_CLOSE(lcl_channel, RC); /* resets "lcl_channel" to FD_INVALID */ \ assert(SS_NORMAL == RC); \ } #define MAX_EPOCH_DELAY 30 #define EXT_NEW "_new" #define PREFIX_ROLLED_BAK "rolled_bak_" #define REC_TOKEN(jnlrec) ((struct_jrec_upd *)jnlrec)->token_seq.token #define REC_JNL_SEQNO(jnlrec) ((struct_jrec_upd *)jnlrec)->token_seq.jnl_seqno #define REC_LEN_FROM_SUFFIX(ptr, reclen) ((jrec_suffix *)((unsigned char *)ptr + reclen - JREC_SUFFIX_SIZE))->backptr /* The below macro now relies on MAX_STRLEN value rather than on CSD->blk_size used previously because * with nodes spanning blocks journal records might be comprised of several blocks, with the limit of * MAX_STRLEN for the actual database record. */ #ifdef UNIX # define JNL_MAX_SET_KILL_RECLEN(CSD) (uint4)ROUND_UP2((FIXED_UPD_RECLEN + JREC_SUFFIX_SIZE) + MAX_STRLEN + \ SIZEOF(jnl_str_len_t) + SIZEOF(mstr_len_t), JNL_REC_START_BNDRY) #else # define JNL_MAX_SET_KILL_RECLEN(CSD) (uint4)ROUND_UP2(FIXED_UPD_RECLEN + JREC_SUFFIX_SIZE \ + ((CSD)->blk_size - SIZEOF(blk_hdr) - SIZEOF(rec_hdr)) \ + SIZEOF(jnl_str_len_t) + SIZEOF(mstr_len_t), JNL_REC_START_BNDRY) \ /* fixed size part of update record + MAX possible (key + data) len + keylen-len + datalen-len */ #endif #define JNL_MAX_PBLK_RECLEN(CSD) (uint4)ROUND_UP2(MIN_PBLK_RECLEN + (CSD)->blk_size, JNL_REC_START_BNDRY) /* Macro to compute the maximum possible journal record length in the journal file. * In order to compute the maximum jnl record length, note that an align record is written whenever * a would cause the jnl file offset to move past an aligned boundary. * Therefore after computing the maximum possible non-align-jnl-record-length, we need to add MIN_ALIGN_RECLEN * as this is the maximum possible align-jnl-record-length and should be the eventual max_jrec_len. */ #define JNL_MAX_RECLEN(JINFO, CSD) \ { \ /* This macro used to compare the value returned from JNL_MAX_SET_KILL_RECLEN with that from \ * JNL_MAX_PBLK_RECLEN and, in case of triggers, MAX_ZTWORK_JREC_LEN. However, in the current design \ * max_logi_reclen includes MAX_STR_LEN as one of its summants, thus always exceeding both \ * MAX_ZTWORK_JREC_LEN and JNL_MAX_PBLK_RECLEN. \ * \ * A logical record is a SET/KILL record. The SET could be as big as (CSD)->max_rec_size, but since \ * csd->max_rec_size can be changed independent of journal file creation (through DSE), we consider \ * the max possible record size that can be ever produced. \ */ \ (JINFO)->max_jrec_len = JNL_MAX_SET_KILL_RECLEN(CSD) + MIN_ALIGN_RECLEN; \ } /* Macro that checks that the region seqno in the filehdr is never more than the seqno in the journal pool */ #define ASSERT_JNL_SEQNO_FILEHDR_JNLPOOL(csd, jnlpool_ctl) \ { /* The seqno in the file header should be at most 1 greater than that in the journal pool. \ * See step (5) of of commit logic flow in secshr_db_clnup.c for why. Assert that. \ */ \ assert((NULL == jnlpool_ctl) || (csd->reg_seqno <= (jnlpool_ctl->jnl_seqno + 1))); \ } #ifdef GTM_CRYPT # define MUR_DECRYPT_LOGICAL_RECS(MUMPS_NODE_PTR, REC_SIZE, KEY_HANDLE, RC) \ { \ int span_length, fixed_prefix; \ \ RC = 0; \ assert(FIXED_UPD_RECLEN == FIXED_ZTWORM_RECLEN); \ fixed_prefix = FIXED_UPD_RECLEN; \ ASSERT_ENCRYPTION_INITIALIZED; \ span_length = REC_SIZE - fixed_prefix - JREC_SUFFIX_SIZE; \ GTMCRYPT_DECRYPT(NULL, KEY_HANDLE, (char *)MUMPS_NODE_PTR, span_length, NULL, RC); \ } #endif /* The following define an appendix message, used along with JNLBUFFREGUPD and JNLBUFFDBUPD messages in * various places, as well as its length, allowing for six digits for both lower and upper journal buffer * size limits, even though neither is expected to have more than five in the near future. */ #define JNLBUFFUPDAPNDX "The previous value was outside the allowable range of %d to %d" #define JNLBUFFUPDAPNDX_SIZE (SIZEOF(JNLBUFFUPDAPNDX) - 4 + (2 * 6)) /* Yields a portable value for the minimum journal buffer size */ #define JNL_BUFF_PORT_MIN(CSD) (UNIX_ONLY(JNL_BUFFER_MIN) VMS_ONLY(CSD->blk_size / DISK_BLOCK_SIZE + 1)) /* Defines the increment value for journal buffer size's rounding-up */ #define JNL_BUFF_ROUND_UP_STEP(CSD) (UNIX_ONLY(MIN(MAX_IO_BLOCK_SIZE, CSD->blk_size)) VMS_ONLY(CSD->blk_size) / DISK_BLOCK_SIZE) /* Rounds up the passed journal buffer value and assigns it to the specified variable */ #define ROUND_UP_JNL_BUFF_SIZE(DEST, VALUE, CSD) \ { \ DEST = ROUND_UP(VALUE, JNL_BUFF_ROUND_UP_STEP(CSD)); \ } /* Rounds up the minimum journal buffer value and assigns it to the specified variable */ #define ROUND_UP_MIN_JNL_BUFF_SIZE(DEST, CSD) \ { \ DEST = ROUND_UP(JNL_BUFF_PORT_MIN(CSD), JNL_BUFF_ROUND_UP_STEP(CSD)); \ } /* Rounds down the maximum journal buffer value and assigns it to the specified variable */ #define ROUND_DOWN_MAX_JNL_BUFF_SIZE(DEST, CSD) \ { \ int jnl_buffer_adj_value, jnl_buffer_decr_step; \ \ jnl_buffer_decr_step = JNL_BUFF_ROUND_UP_STEP(CSD); \ jnl_buffer_adj_value = ROUND_UP(JNL_BUFFER_MAX, jnl_buffer_decr_step); \ while (JNL_BUFFER_MAX < jnl_buffer_adj_value) \ jnl_buffer_adj_value -= jnl_buffer_decr_step; \ DEST = jnl_buffer_adj_value; \ } #ifdef UNIX # define CURRENT_JNL_IO_WRITER(JB) JB->io_in_prog_latch.u.parts.latch_pid # define CURRENT_JNL_FSYNC_WRITER(JB) JB->fsync_in_prog_latch.u.parts.latch_pid #else # define CURRENT_JNL_IO_WRITER(JB) JB->now_writer #endif /* jnl_ prototypes */ uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size); uint4 jnl_file_lost(jnl_private_control *jpc, uint4 jnl_stat); uint4 jnl_qio_start(jnl_private_control *jpc); uint4 jnl_write_attempt(jnl_private_control *jpc, uint4 threshold); void jnl_prc_vector(jnl_process_vector *pv); void jnl_send_oper(jnl_private_control *jpc, uint4 status); uint4 cre_jnl_file(jnl_create_info *info); uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_len); void jfh_from_jnl_info (jnl_create_info *info, jnl_file_header *header); uint4 jnl_ensure_open(void); void set_jnl_info(gd_region *reg, jnl_create_info *set_jnl_info); void jnl_write_epoch_rec(sgmnt_addrs *csa); void jnl_write_inctn_rec(sgmnt_addrs *csa); void jnl_write_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb, uint4 com_csum); void jnl_write_ztp_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb, uint4 com_csum); void jnl_write_eof_rec(sgmnt_addrs *csa, struct_jrec_eof *eof_record); void jnl_write_trunc_rec(sgmnt_addrs *csa, uint4 orig_total_blks, uint4 orig_free_blocks, uint4 total_blks_after_trunc); void jnl_write_poolonly(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_record *jnl_rec, jnl_format_buffer *jfb); jnl_format_buffer *jnl_format(jnl_action_code opcode, gv_key *key, mval *val, uint4 nodeflags); #ifdef VMS void finish_active_jnl_qio(void); void jnl_start_ast(jnl_private_control *jpc); uint4 jnl_permit_ast(jnl_private_control *jpc); void jnl_qio_end(jnl_private_control *jpc); #endif void wcs_defer_wipchk_ast(jnl_private_control *jpc); uint4 set_jnl_file_close(set_jnl_file_close_opcode_t set_jnl_file_close_opcode); uint4 jnl_file_open_common(gd_region *reg, off_jnl_t os_file_size); uint4 jnl_file_open_switch(gd_region *reg, uint4 sts); void jnl_file_close(gd_region *reg, bool clean, bool dummy); /* Consider putting followings in a mupip only header file : Layek 2/18/2003 */ boolean_t mupip_set_journal_parse(set_jnl_options *jnl_options, jnl_create_info *jnl_info); uint4 mupip_set_journal_newstate(set_jnl_options *jnl_options, jnl_create_info *jnl_info, mu_set_rlist *rptr); void mupip_set_journal_fname(jnl_create_info *jnl_info); uint4 mupip_set_jnlfile_aux(jnl_file_header *header, char *jnl_fname); void jnl_extr_init(void); int exttime(uint4 time, char *buffer, int extract_len); char *ext2jnlcvt(char *ext_buff, int4 ext_len, jnl_record *rec, seq_num saved_jnl_seqno, seq_num saved_strm_seqno); char *ext2jnl(char *ptr, jnl_record *rec, seq_num saved_jnl_seqno, seq_num saved_strm_seqno); char *jnl2extcvt(jnl_record *rec, int4 jnl_len, char *ext_buff); char *jnl2ext(char *jnl_buff, char *ext_buff); #endif /* JNL_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/jnl2ext.c0000644000032200000250000001770312201176160015570 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include /* for offsetof macro */ #include "gtm_string.h" #include "gtm_stdio.h" #include "gdsroot.h" /* for filestruct.h */ #include "gdsbt.h" /* for gdsfhead.h */ #include "gtm_facility.h" /* for fileinfo.h */ #include "fileinfo.h" /* for gdsfhead.h */ #include "gdsfhead.h" /* for filestruct.h */ #include "filestruct.h" /* for jnl.h */ #include "jnl.h" #include "copy.h" /* for REF_CHAR macro */ #include "repl_filter.h" #include "format_targ_key.h" #include "mlkdef.h" #include "zshow.h" #include "buddy_list.h" /* needed for muprec.h */ #include "hashtab_mname.h" /* needed for muprec.h */ #include "hashtab_int4.h" /* needed for muprec.h */ #include "hashtab_int8.h" /* needed for muprec.h */ #include "muprec.h" #include "real_len.h" /* for real_len() prototype */ #define DELIMIT_CURR *curr++ = '\\'; #define ZERO_TIME_DELIM "0,0\\" #define PIDS_DELIM "0\\0\\" #define JNL2EXT_STRM_SEQNO(CURR, STRM_SEQNO) \ { \ seq_num lcl_strm_seqno; \ uint4 lcl_strm_num; \ \ DELIMIT_CURR; \ lcl_strm_seqno = STRM_SEQNO; \ UNIX_ONLY(lcl_strm_num = GET_STRM_INDEX(lcl_strm_seqno);) \ VMS_ONLY(lcl_strm_num = 0;) \ CURR = (char *)i2ascl((uchar_ptr_t)CURR, lcl_strm_num); \ DELIMIT_CURR; \ UNIX_ONLY(lcl_strm_seqno = GET_STRM_SEQ60(lcl_strm_seqno);) \ VMS_ONLY(lcl_strm_seqno = 0;) \ CURR = (char *)i2ascl((uchar_ptr_t)CURR, lcl_strm_seqno); \ } /* * Generic function to convert a journal record into an extract format record. * Expects a pointer to the journal record and the length of the buffer and * returns the result in ext_buff. If there is a bad format record in between, * it returns NULL. It sets jb_stop to the offset of the jnl_buff where * the last jnlrecord was processed. On successful conversion, it returns a value * ptr, such that ptr - ext_buff would be the length of the extracted buffer. * If the ext_len is not enough for the conversion, it returns ext_buff + ext_len */ GBLREF char *jb_stop; GBLREF char muext_code[][2]; static boolean_t first_tstart = FALSE; static int4 num_tstarts = 0; static int4 num_tcommits = 0; char *jnl2extcvt(jnl_record *rec, int4 jnl_len, char *ext_buff) { int4 rec_len; for ( ; jnl_len > JREC_PREFIX_UPTO_LEN_SIZE && jnl_len >= (rec_len = rec->prefix.forwptr) && rec_len > MIN_JNLREC_SIZE; ) { ext_buff = jnl2ext((char *)rec, ext_buff); jnl_len -= rec_len; rec = (jnl_record *)((char *)rec + rec_len); } jb_stop = (char *)rec; return ext_buff; } /* This was earlier declared as a local variable, but was moved up, because the HPIA compiler for some reason seems to * optimize things, and thus not update the buffer correctly. Problem shows up only in optimized builds. Moving it to * global status fixed the issue */ GBLDEF char key_buff[SIZEOF(gv_key) + MAX_KEY_SZ + 7]; char *jnl2ext(char *jnl_buff, char *ext_buff) { char *curr, *val_ptr, rectype; unsigned char *ptr; jnl_record *rec; gv_key *key; jnl_string *keystr, *ztwormstr; int val_extr_len, val_len, rec_len, tid_len; rec = (jnl_record *)jnl_buff; rectype = rec->prefix.jrec_type; rec_len = rec->prefix.forwptr; if ((ROUND_DOWN2(rec_len, JNL_REC_START_BNDRY) != rec_len) || rec_len != REC_LEN_FROM_SUFFIX(jnl_buff, rec_len)) { assert(FALSE); return ext_buff; } if (!IS_REPLICATED(rectype)) { assert(FALSE); return ext_buff; } curr = ext_buff; /* The following assumes the journal extract format is "GDSJEX06". Whenever that changes (in mur_jnl_ext.c), * the below code as well as ext2jnl.c needs to change. Add an assert to let us know of that event. */ assert(!MEMCMP_LIT(JNL_EXTR_LABEL,"GDSJEX06")); if (IS_TUPD(rectype)) { if (FALSE == first_tstart) { GET_SHORTP(curr, &muext_code[MUEXT_TSTART][0]); curr += 2; DELIMIT_CURR; MEMCPY_LIT(curr, ZERO_TIME_DELIM); curr += STR_LIT_LEN(ZERO_TIME_DELIM); curr = (char *)i2ascl((uchar_ptr_t)curr, rec->jrec_set_kill.prefix.tn); DELIMIT_CURR; MEMCPY_LIT(curr, PIDS_DELIM); curr += STR_LIT_LEN(PIDS_DELIM); curr = (char *)i2ascl((uchar_ptr_t)curr, rec->jrec_set_kill.token_seq.jnl_seqno); JNL2EXT_STRM_SEQNO(curr, rec->jrec_set_kill.strm_seqno); /* Note: updates "curr" */ *curr++ = '\n'; *curr = '\0'; first_tstart = TRUE; } num_tstarts++; } else if (JRT_TCOM == rectype) { num_tcommits++; if (num_tcommits == num_tstarts) { num_tcommits = num_tstarts = 0; first_tstart = FALSE; GET_SHORTP(curr, &muext_code[MUEXT_TCOMMIT][0]); curr += 2; DELIMIT_CURR; MEMCPY_LIT(curr, ZERO_TIME_DELIM); curr += STR_LIT_LEN(ZERO_TIME_DELIM); curr = (char *)i2ascl((uchar_ptr_t)curr, rec->jrec_tcom.prefix.tn); DELIMIT_CURR; MEMCPY_LIT(curr, PIDS_DELIM); curr += STR_LIT_LEN(PIDS_DELIM); curr = (char *)i2ascl((uchar_ptr_t)curr, rec->jrec_tcom.token_seq.jnl_seqno); JNL2EXT_STRM_SEQNO(curr, rec->jrec_tcom.strm_seqno); /* Note: updates "curr" */ DELIMIT_CURR; *curr = '1'; /* Only ONE TSTART..TCOM in the external filter format */ curr++; DELIMIT_CURR; ptr = (unsigned char *)rec->jrec_tcom.jnl_tid; tid_len = real_len(SIZEOF(rec->jrec_tcom.jnl_tid), ptr); memcpy(curr, ptr, tid_len); curr += tid_len; *curr++ = '\n'; *curr = '\0'; return curr; } return ext_buff; } if (IS_SET(rectype)) GET_SHORTP(curr, &muext_code[MUEXT_SET][0]); else if (IS_KILL(rectype)) GET_SHORTP(curr, &muext_code[MUEXT_KILL][0]); else if (IS_ZKILL(rectype)) GET_SHORTP(curr, &muext_code[MUEXT_ZKILL][0]); else if (IS_ZTWORM(rectype)) GET_SHORTP(curr, &muext_code[MUEXT_ZTWORM][0]); else if (IS_ZTRIG(rectype)) GET_SHORTP(curr, &muext_code[MUEXT_ZTRIG][0]); else /* if (JRT_NULL == rectype) */ { assert(JRT_NULL == rectype); GET_SHORTP(curr, &muext_code[MUEXT_NULL][0]); } curr += 2; DELIMIT_CURR; MEMCPY_LIT(curr, ZERO_TIME_DELIM); curr += STR_LIT_LEN(ZERO_TIME_DELIM); curr = (char *)i2ascl((uchar_ptr_t)curr, rec->jrec_set_kill.prefix.tn); DELIMIT_CURR; MEMCPY_LIT(curr, PIDS_DELIM); curr += STR_LIT_LEN(PIDS_DELIM); curr = (char *)i2ascl((uchar_ptr_t)curr, rec->jrec_set_kill.token_seq.jnl_seqno); JNL2EXT_STRM_SEQNO(curr, rec->jrec_set_kill.strm_seqno); /* Note: updates "curr" */ if (rectype == JRT_NULL) { *curr++ = '\n'; *curr='\0'; return curr; } DELIMIT_CURR; /* print "update_num" */ assert(IS_SET_KILL_ZKILL_ZTRIG_ZTWORM(rectype)); assert(&rec->jrec_set_kill.update_num == &rec->jrec_ztworm.update_num); curr = (char *)i2ascl((uchar_ptr_t)curr, rec->jrec_set_kill.update_num); DELIMIT_CURR; if (IS_ZTWORM(rectype)) { ztwormstr = &rec->jrec_ztworm.ztworm_str; val_len = ztwormstr->length; val_ptr = &ztwormstr->text[0]; format2zwr((sm_uc_ptr_t)val_ptr, val_len, (uchar_ptr_t)curr, &val_extr_len); curr += val_extr_len; *curr++ = '\n'; *curr='\0'; return curr; } /* print "nodeflags" */ keystr = (jnl_string *)&rec->jrec_set_kill.mumps_node; curr = (char *)i2ascl((uchar_ptr_t)curr, keystr->nodeflags); DELIMIT_CURR; /* print "node" */ key = (gv_key *)ROUND_UP((unsigned long)key_buff, 8); key->top = MAX_KEY_SZ; key->end = keystr->length; if (key->end > key->top) { assert(FALSE); return ext_buff; } memcpy(key->base, &keystr->text[0], keystr->length); key->base[key->end] = 0; curr = (char *)format_targ_key((uchar_ptr_t)curr, MAX_ZWR_KEY_SZ, key, TRUE); if (IS_SET(rectype)) { *curr++ = '='; val_ptr = &keystr->text[keystr->length]; GET_MSTR_LEN(val_len, val_ptr); val_ptr += SIZEOF(mstr_len_t); format2zwr((sm_uc_ptr_t)val_ptr, val_len, (uchar_ptr_t)curr, &val_extr_len); curr += val_extr_len; } *curr++ = '\n'; *curr='\0'; return curr; } fis-gtm-V6.0-003/sr_port/jnl_ensure_open.c0000644000032200000250000000714012201176160017361 0ustar librarygtc/**************************************************************** * * * Copyright 2010, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsdbver.h" #include "gdsroot.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "iosp.h" #include "repl_sp.h" #include "gtmio.h" #include "gtmimagename.h" #include "wbox_test_init.h" #include "gtcm_jnl_switched.h" GBLREF boolean_t is_src_server; GBLREF gd_region *gv_cur_region; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; /* make sure that the journal file is available if appropriate */ uint4 jnl_ensure_open(void) { uint4 jnl_status; jnl_private_control *jpc; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; boolean_t first_open_of_jnl, need_to_open_jnl; int close_res; # if defined(VMS) static const gds_file_id file; uint4 status; # endif error_def(ERR_JNLFILOPN); csa = cs_addrs; csd = csa->hdr; assert(csa->now_crit); jpc = csa->jnl; assert(NULL != jpc); assert(JNL_ENABLED(csa->hdr)); /* The goal is to change the code below to do only one JNL_FILE_SWITCHED(jpc) check instead of the additional * (NOJNL == jpc->channel) check done below. The assert below ensures that the NOJNL check can indeed * be subsumed by the JNL_FILE_SWITCHED check (with the exception of the source-server which has a special case that * needs to be fixed in C9D02-002241). Over time, this has to be changed to one check. */ assert((NOJNL != jpc->channel) || JNL_FILE_SWITCHED(jpc) || is_src_server); need_to_open_jnl = FALSE; jnl_status = 0; if (NOJNL == jpc->channel) { # ifdef VMS if (NOJNL != jpc->old_channel) { if (lib$ast_in_prog()) /* called from wcs_wipchk_ast */ jnl_oper_user_ast(gv_cur_region); else { status = sys$setast(DISABLE); jnl_oper_user_ast(gv_cur_region); if (SS$_WASSET == status) ENABLE_AST; } } # endif need_to_open_jnl = TRUE; } else if (JNL_FILE_SWITCHED(jpc)) { /* The journal file has been changed "on the fly"; close the old one and open the new one */ VMS_ONLY(assert(FALSE);) /* everyone having older jnl open should have closed it at time of switch in VMS */ JNL_FD_CLOSE(jpc->channel, close_res); /* sets jpc->channel to NOJNL */ need_to_open_jnl = TRUE; } if (need_to_open_jnl) { /* Whenever journal file get switch, reset the pini_addr and new_freeaddr. */ jpc->pini_addr = 0; jpc->new_freeaddr = 0; if (IS_GTCM_GNP_SERVER_IMAGE) gtcm_jnl_switched(jpc->region); /* Reset pini_addr of all clients that had any older journal file open */ UNIX_ONLY(first_open_of_jnl = (0 == csa->nl->jnl_file.u.inode);) VMS_ONLY(first_open_of_jnl = (0 == memcmp(csa->nl->jnl_file.jnl_file_id.fid, file.fid, SIZEOF(file.fid)))); jnl_status = jnl_file_open(gv_cur_region, first_open_of_jnl, NULL); } DEBUG_ONLY( else GTM_WHITE_BOX_TEST(WBTEST_JNL_FILE_OPEN_FAIL, jnl_status, ERR_JNLFILOPN); ) assert((0 != jnl_status) || !JNL_FILE_SWITCHED(jpc) UNIX_ONLY(|| (is_src_server && !JNL_ENABLED(csa) && REPL_WAS_ENABLED(csa)))); return jnl_status; } fis-gtm-V6.0-003/sr_port/jnl_file_close.c0000644000032200000250000001415012201176160017142 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_time.h" #include "gtm_string.h" #if defined(UNIX) #include "gtm_unistd.h" #include "aswp.h" #include "lockconst.h" #include "interlock.h" #include "sleep_cnt.h" #include "performcaslatchcheck.h" #include "wcs_sleep.h" #include "gt_timer.h" #include "wbox_test_init.h" #elif defined(VMS) #include #include #include #include #include #include "iosb_disk.h" #endif #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "jnl_write.h" #include "gtmio.h" #include "repl_sp.h" /* F_CLOSE */ #include "iosp.h" /* for SS_NORMAL */ #include "ccp.h" #include "send_msg.h" #include "eintr_wrappers.h" #include "anticipatory_freeze.h" #ifdef UNIX #include "wcs_clean_dbsync.h" #endif #if defined(VMS) GBLREF short astq_dyn_avail; static const unsigned short zero_fid[3]; #endif GBLREF jnl_gbls_t jgbl; error_def(ERR_JNLCLOSE); error_def(ERR_JNLFLUSH); error_def(ERR_JNLFSYNCERR); error_def(ERR_JNLWRERR); error_def(ERR_PREMATEOF); error_def(ERR_TEXT); void jnl_file_close(gd_region *reg, bool clean, bool dummy) { jnl_file_header *header; unsigned char hdr_base[REAL_JNL_HDR_LEN + MAX_IO_BLOCK_SIZE]; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; jnl_private_control *jpc; jnl_buffer_ptr_t jb; struct_jrec_eof eof_record; off_jnl_t eof_addr; uint4 status, read_write_size; int rc, save_errno, idx; uint4 jnl_fs_block_size; csa = &FILE_INFO(reg)->s_addrs; csd = csa->hdr; assert(!clean || csa->now_crit || (csd->clustered && (CCST_CLOSED == csa->nl->ccp_state))); DEBUG_ONLY( if (clean) ASSERT_JNLFILEID_NOT_NULL(csa); ) jpc = csa->jnl; #if defined(UNIX) if (csa->dbsync_timer) CANCEL_DBSYNC_TIMER(csa); #elif defined(VMS) /* See comment about ordering of the two statements below, in similar code in gds_rundown */ if (csa->dbsync_timer) { csa->dbsync_timer = FALSE; ++astq_dyn_avail; } sys$cantim(csa, PSL$C_USER); /* cancel all dbsync-timers for this region */ #endif if ((NULL == jpc) || (NOJNL == jpc->channel)) return; jb = jpc->jnl_buff; jnl_fs_block_size = jb->fs_block_size; header = (jnl_file_header *)(ROUND_UP2((uintszofptr_t)hdr_base, jnl_fs_block_size)); if (clean) { if(!jgbl.mur_extract) jnl_write_eof_rec(csa, &eof_record); if (SS_NORMAL != (jpc->status = jnl_flush(reg))) { send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during jnl_file_close"), jpc->status); assert(FALSE); rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during jnl_file_close"), jpc->status); } assert(jb->dskaddr == jb->freeaddr); UNIX_ONLY(jnl_fsync(reg, jb->dskaddr);) UNIX_ONLY(assert(jb->freeaddr == jb->fsync_dskaddr);) eof_addr = jb->freeaddr - EOF_RECLEN; read_write_size = ROUND_UP2(REAL_JNL_HDR_LEN, jnl_fs_block_size); assert((unsigned char *)header + read_write_size <= ARRAYTOP(hdr_base)); DO_FILE_READ(jpc->channel, 0, header, read_write_size, jpc->status, jpc->status2); if (SYSCALL_SUCCESS(jpc->status)) { if(!jgbl.mur_extract) { assert(header->end_of_data <= eof_addr); header->end_of_data = eof_addr; header->eov_timestamp = eof_record.prefix.time; assert(header->eov_timestamp >= header->bov_timestamp); header->eov_tn = eof_record.prefix.tn; assert(header->eov_tn >= header->bov_tn); header->end_seqno = eof_record.jnl_seqno; } # ifdef UNIX for (idx = 0; idx < MAX_SUPPL_STRMS; idx++) header->strm_end_seqno[idx] = csd->strm_reg_seqno[idx]; if (jgbl.forw_phase_recovery) { /* If MUPIP JOURNAL -ROLLBACK, might need some adjustment. See macro definition for comments */ MUR_ADJUST_STRM_REG_SEQNO_IF_NEEDED(csd, header->strm_end_seqno); } # endif header->crash = FALSE; JNL_DO_FILE_WRITE(csa, csd->jnl_file_name, jpc->channel, 0, header, read_write_size, jpc->status, jpc->status2); if (SYSCALL_ERROR(jpc->status)) { assert(FALSE); rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLWRERR, 2, JNL_LEN_STR(csd), jpc->status); } UNIX_ONLY( GTM_JNL_FSYNC(csa, jpc->channel, rc); if (-1 == rc) { save_errno = errno; send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with fsync during jnl_file_close"), save_errno); assert(FALSE); rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd), ERR_TEXT, 2, RTS_ERROR_TEXT("Error with fsync during jnl_file_close"), save_errno); } ) } /* jnl_file_id should be nullified only after the jnl file header has been written to disk. * Nullifying the jnl_file_id signals that the jnl file has been switched. The replication source server * assumes that the jnl file has been completely written to disk (including the header) before the switch is * signalled. */ NULLIFY_JNL_FILE_ID(csa); jb->cycle++; /* increment shared cycle so all future callers of jnl_ensure_open recognize journal switch */ } JNL_FD_CLOSE(jpc->channel, rc); /* sets jpc->channel to NOJNL */ #ifdef UNIX GTM_WHITE_BOX_TEST(WBTEST_ANTIFREEZE_JNLCLOSE, rc, EIO); #endif jpc->cycle--; /* decrement cycle so jnl_ensure_open() knows to reopen the journal */ VMS_ONLY(jpc->qio_active = FALSE;) jpc->pini_addr = 0; if (clean && (SS_NORMAL != jpc->status || SS_NORMAL != rc)) { status = jpc->status; /* jnl_send_oper resets jpc->status, so save it */ jnl_send_oper(jpc, ERR_JNLCLOSE); rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLCLOSE, 2, JNL_LEN_STR(csd), status); } } fis-gtm-V6.0-003/sr_port/jnl_file_lost.c0000644000032200000250000001120112201176160017010 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_inet.h" #ifdef VMS #include #include #include #include #include #endif #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "ccp.h" #include "jnl.h" #ifdef VMS #include "locks.h" #endif #include "send_msg.h" #include "repl_msg.h" #include "gtmsource.h" #ifdef UNIX #include "anticipatory_freeze.h" #endif GBLREF jnlpool_addrs jnlpool; GBLREF gd_region *gv_cur_region; GBLREF volatile boolean_t in_wcs_recover; GBLREF int process_exiting; #ifdef UNIX GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; #endif error_def(ERR_JNLCLOSED); error_def(ERR_REPLJNLCLOSED); static const unsigned short zero_fid[3]; uint4 jnl_file_lost(jnl_private_control *jpc, uint4 jnl_stat) { /* Notify operator and terminate journaling */ unsigned int status; sgmnt_addrs *csa; seq_num reg_seqno, jnlseqno; boolean_t was_lockid = FALSE, instfreeze_environ; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; switch(jpc->region->dyn.addr->acc_meth) { case dba_mm: case dba_bg: csa = &FILE_INFO(jpc->region)->s_addrs; break; default: GTMASSERT; } # ifdef VMS /* The following assert has been removed as it could be FALSE if the caller is "jnl_file_extend" * assert(0 != memcmp(csa->nl->jnl_file.jnl_file_id.fid, zero_fid, SIZEOF(zero_fid))); */ # endif assert(csa->now_crit); /* We issue an rts_error (instead of shutting off journaling) in the following cases : {BYPASSOK} * 1) $gtm_error_on_jnl_file_lost is set to issue runtime error (if not already issued) in case of journaling issues. * 2) The process has $gtm_custom_errors set (indicative of anticipatory freeze setup) in which case the goal is to * never shut-off journaling * 3) If $gtm_custom_errors is not set for this process, but the source server was started with $gtm_custom_errors * set. This way, as long as the environment is configured for $gtm_custom_errors individual processes never turn * off journaling. */ UNIX_ONLY(instfreeze_environ = (ANTICIPATORY_FREEZE_AVAILABLE || ((NULL != jnlpool_ctl) && jnlpool_ctl->instfreeze_environ_inited))); VMS_ONLY(instfreeze_environ = FALSE); if ((JNL_FILE_LOST_ERRORS == TREF(error_on_jnl_file_lost)) || instfreeze_environ) { VMS_ONLY(assert(FALSE)); /* Not fully implemented / supported on VMS. */ if (!process_exiting || instfreeze_environ || !csa->jnl->error_reported) { csa->jnl->error_reported = TRUE; in_wcs_recover = FALSE; /* in case we're called in wcs_recover() */ if (SS_NORMAL != jpc->status) rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) jnl_stat, 4, JNL_LEN_STR(csa->hdr), DB_LEN_STR(gv_cur_region), jpc->status); else rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_stat, 4, JNL_LEN_STR(csa->hdr), DB_LEN_STR(gv_cur_region)); } return jnl_stat; } if (0 != jnl_stat) jnl_send_oper(jpc, jnl_stat); csa->hdr->jnl_state = jnl_closed; jpc->jnl_buff->cycle++; /* increment shared cycle so all future callers of jnl_ensure_open recognize journal switch */ assert(jpc->cycle < jpc->jnl_buff->cycle); if (REPL_ENABLED(csa->hdr)) { csa->hdr->repl_state = repl_was_open; reg_seqno = csa->hdr->reg_seqno; jnlseqno = (NULL != jnlpool.jnlpool_ctl) ? jnlpool.jnlpool_ctl->jnl_seqno : MAX_SEQNO; send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_REPLJNLCLOSED, 6, DB_LEN_STR(jpc->region), ®_seqno, ®_seqno, &jnlseqno, &jnlseqno); } else send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLCLOSED, 3, DB_LEN_STR(jpc->region), &csa->ti->curr_tn); #ifdef VMS /* We can get a jnl_file_lost before the file is even created, so locking is done only if the lock exist */ if (0 != csa->jnl->jnllsb->lockid) { was_lockid = TRUE; status = gtm_enqw(EFN$C_ENF, LCK$K_EXMODE, csa->jnl->jnllsb, LCK$M_CONVERT | LCK$M_NODLCKBLK, NULL, 0, NULL, 0, NULL, PSL$C_USER, 0); if (SS$_NORMAL == status) status = csa->jnl->jnllsb->cond; } jnl_file_close(jpc->region, FALSE, FALSE); if (was_lockid) { if (SS$_NORMAL == status) status = gtm_deq(csa->jnl->jnllsb->lockid, NULL, PSL$C_USER, 0); if (SS$_NORMAL != status) GTMASSERT; } # else jnl_file_close(jpc->region, FALSE, FALSE); #endif return EXIT_NRM; } fis-gtm-V6.0-003/sr_port/jnl_file_open_common.c0000644000032200000250000002574212201176160020357 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stat.h" #include "gtm_string.h" #include "gtm_time.h" #include "gtm_inet.h" #if defined(UNIX) #include #include "gtm_fcntl.h" #include "gtm_unistd.h" #include "interlock.h" #include "lockconst.h" #include "aswp.h" #elif defined(VMS) #include #include #include #include #include #include #include #include #include #include #include "iosb_disk.h" #endif #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "gtmio.h" #include "eintr_wrappers.h" #include "repl_msg.h" #include "gtmsource.h" #include "is_file_identical.h" #include "gtmmsg.h" #include "send_msg.h" #include "repl_sp.h" #include "iosp.h" /* for SS_NORMAL */ #include "get_fs_block_size.h" #include "anticipatory_freeze.h" GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; GBLREF boolean_t pool_init; GBLREF jnl_process_vector *prc_vec; GBLREF jnl_gbls_t jgbl; error_def(ERR_FILEIDMATCH); error_def(ERR_JNLOPNERR); error_def(ERR_JNLRDERR); error_def(ERR_JNLBADRECFMT); error_def(ERR_JNLRECTYPE); error_def(ERR_JNLTRANSGTR); error_def(ERR_JNLTRANSLSS); error_def(ERR_JNLWRERR); error_def(ERR_JNLVSIZE); error_def(ERR_PREMATEOF); error_def(ERR_JNLPREVRECOV); #ifdef GTM_CRYPT error_def(ERR_CRYPTJNLWRONGHASH); #endif /* note: returns 0 on success */ uint4 jnl_file_open_common(gd_region *reg, off_jnl_t os_file_size) { sgmnt_addrs *csa; sgmnt_data_ptr_t csd; jnl_private_control *jpc; jnl_buffer_ptr_t jb; jnl_file_header *header; unsigned char hdr_buff[REAL_JNL_HDR_LEN + MAX_IO_BLOCK_SIZE]; struct_jrec_eof eof_record; /* pointer is in an attempt to use make code portable */ unsigned char *eof_rec_buffer; unsigned char eof_rec[(DISK_BLOCK_SIZE * 2) + MAX_IO_BLOCK_SIZE]; off_jnl_t adjust; #if defined(VMS) io_status_block_disk iosb; #endif uint4 jnl_fs_block_size, read_write_size, read_size; gtm_uint64_t header_virtual_size; csa = &FILE_INFO(reg)->s_addrs; csd = csa->hdr; jpc = csa->jnl; jb = jpc->jnl_buff; jpc->status = jpc->status2 = SS_NORMAL; jnl_fs_block_size = get_fs_block_size(jpc->channel); /* check that the filesystem block size is a power of 2 as we do a lot of calculations below assuming this is the case */ assert(!(jnl_fs_block_size & (jnl_fs_block_size - 1))); header = (jnl_file_header *)(ROUND_UP2((uintszofptr_t)hdr_buff, jnl_fs_block_size)); eof_rec_buffer = (unsigned char *)(ROUND_UP2((uintszofptr_t)eof_rec, jnl_fs_block_size)); /* Read the journal file header */ read_write_size = ROUND_UP2(REAL_JNL_HDR_LEN, jnl_fs_block_size); assert((unsigned char *)header + read_write_size <= ARRAYTOP(hdr_buff)); DO_FILE_READ(jpc->channel, 0, header, read_write_size, jpc->status, jpc->status2); if (SS_NORMAL != jpc->status) { /* A PREMATEOF error is possible in Unix if a V54001 version is trying to open a pre-V54001 journal file * This is because starting V54001, the journal file size is always maintained as a multiple of the underlying * filesystem block size. And so in case of a previous version created journal file, it is possible the * entire unaligned journal file size is lesser than the aligned journal file header size. */ UNIX_ONLY(assert(ERR_PREMATEOF == jpc->status);) VMS_ONLY(assert(FALSE);) return ERR_JNLRDERR; } /* Check if the header format matches our format. Cannot access any fields inside header unless this matches */ CHECK_JNL_FILE_IS_USABLE(header, jpc->status, FALSE, 0, NULL); /* FALSE => NO gtm_putmsg even if errors */ if (SS_NORMAL != jpc->status) return ERR_JNLOPNERR; adjust = header->end_of_data & (jnl_fs_block_size - 1); /* Read the journal JRT_EOF at header->end_of_data offset. * Make sure the buffer being read to is big enough and that as part of the read, * we never touch touch the journal file header territory. */ read_size = ROUND_UP2((EOF_RECLEN + adjust), jnl_fs_block_size); assert(eof_rec_buffer + read_size <= ARRAYTOP(eof_rec)); assert(header->end_of_data - adjust >= JNL_HDR_LEN); DO_FILE_READ(jpc->channel, header->end_of_data - adjust, eof_rec_buffer, read_size, jpc->status, jpc->status2); if (SS_NORMAL != jpc->status) { return ERR_JNLRDERR; } if (header->prev_recov_end_of_data) { /* not possible for run time. In case it happens user must fix it */ jpc->status = ERR_JNLPREVRECOV; return ERR_JNLOPNERR; } if (!is_gdid_file_identical(&FILE_ID(reg), (char *)header->data_file_name, header->data_file_name_length)) { rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_JNLOPNERR, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg), ERR_FILEIDMATCH); assert(FALSE); /* we dont expect the rts_error in the line above to return */ return ERR_JNLOPNERR; } memcpy(&eof_record, (unsigned char *)eof_rec_buffer + adjust, EOF_RECLEN); if (JRT_EOF != eof_record.prefix.jrec_type) { jpc->status = ERR_JNLRECTYPE; return ERR_JNLOPNERR; } if (eof_record.prefix.tn != csd->trans_hist.curr_tn) { if (eof_record.prefix.tn < csd->trans_hist.curr_tn) jpc->status = ERR_JNLTRANSLSS; else jpc->status = ERR_JNLTRANSGTR; return ERR_JNLOPNERR; } if (eof_record.suffix.suffix_code != JNL_REC_SUFFIX_CODE || eof_record.suffix.backptr != eof_record.prefix.forwptr) { jpc->status = ERR_JNLBADRECFMT; return ERR_JNLOPNERR; } GTMCRYPT_ONLY( if (memcmp(header->encryption_hash, csd->encryption_hash, GTMCRYPT_HASH_LEN)) { send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_CRYPTJNLWRONGHASH, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg)); jpc->status = ERR_CRYPTJNLWRONGHASH; return ERR_JNLOPNERR; } ) assert(header->eov_tn == eof_record.prefix.tn); header->eov_tn = eof_record.prefix.tn; assert(header->eov_timestamp == eof_record.prefix.time); header->eov_timestamp = eof_record.prefix.time; assert(header->eov_timestamp >= header->bov_timestamp); assert(((off_jnl_t)os_file_size) % JNL_REC_START_BNDRY == 0); assert(((off_jnl_t)os_file_size) % DISK_BLOCK_SIZE == 0); assert(((off_jnl_t)os_file_size) % jnl_fs_block_size == 0); header_virtual_size = header->virtual_size; /* saving in 8-byte int to avoid overflow below */ if ((ROUND_UP2((header_virtual_size * DISK_BLOCK_SIZE), jnl_fs_block_size) < os_file_size) || (header->jnl_deq && 0 != ((header_virtual_size - header->jnl_alq) % header->jnl_deq))) { send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_JNLVSIZE, 6, JNL_LEN_STR(csd), header->virtual_size, header->jnl_alq, header->jnl_deq, os_file_size, jnl_fs_block_size); jpc->status = ERR_JNLVSIZE; return ERR_JNLOPNERR; } /* For performance reasons (to be able to do aligned writes to the journal file), we need to ensure the journal buffer * address is filesystem-block-size aligned in Unix. Although this is needed only in case of sync_io/direct-io, we ensure * this alignment unconditionally in Unix. jb->buff_off is the number of bytes to go past before getting an aligned buffer. * For VMS, this performance enhancement is currently not done and can be revisited later. */ UNIX_ONLY(jb->buff_off = (uintszofptr_t)ROUND_UP2((uintszofptr_t)&jb->buff[0], jnl_fs_block_size) - (uintszofptr_t)&jb->buff[0];) VMS_ONLY(jb->buff_off = 0;) jb->size = ROUND_DOWN2(csd->jnl_buffer_size * DISK_BLOCK_SIZE - jb->buff_off, jnl_fs_block_size); /* Assert that journal buffer does NOT spill past the allocated journal buffer size in shared memory */ assert((sm_uc_ptr_t)&jb->buff[jb->buff_off + jb->size] < ((sm_uc_ptr_t)csa->nl + NODE_LOCAL_SPACE(csd) + JNL_SHARE_SIZE(csd))); assert((sm_uc_ptr_t)jb == ((sm_uc_ptr_t)csa->nl + NODE_LOCAL_SPACE(csd) + JNL_NAME_EXP_SIZE)); jb->freeaddr = jb->dskaddr = UNIX_ONLY(jb->fsync_dskaddr = ) header->end_of_data; jb->fs_block_size = jnl_fs_block_size; /* The following is to make sure that the data in jnl_buffer is aligned with the data in the * disk file on an jnl_fs_block_size boundary. Since we assert that jb->size is a multiple of jnl_fs_block_size, * alignment with respect to jb->size implies alignment with jnl_fs_block_size. */ assert(0 == (jb->size % jnl_fs_block_size)); jb->free = jb->dsk = header->end_of_data % jb->size; UNIX_ONLY( SET_LATCH_GLOBAL(&jb->fsync_in_prog_latch, LOCK_AVAILABLE); SET_LATCH_GLOBAL(&jb->io_in_prog_latch, LOCK_AVAILABLE); ) VMS_ONLY( assert(0 == jb->now_writer); bci(&jb->io_in_prog); jb->now_writer = 0; assert((jb->free % DISK_BLOCK_SIZE) == adjust); ) assert(0 == (jnl_fs_block_size % DISK_BLOCK_SIZE)); if (adjust) { /* if jb->free does not start at a filesystem-block-size aligned boundary (which is the alignment granularity used * by "jnl_output_sp" for flushing to disk), copy as much pre-existing data from the journal file as necessary into * the journal buffer to fill the gap so we do not lose this information in the next write to disk. */ memcpy(&jb->buff[ROUND_DOWN2(jb->free, jnl_fs_block_size) + jb->buff_off], eof_rec_buffer, adjust); } jb->filesize = header->virtual_size; jb->min_write_size = JNL_MIN_WRITE; jb->max_write_size = JNL_MAX_WRITE; jb->before_images = header->before_images; jb->epoch_tn = eof_record.prefix.tn; csd->jnl_checksum = header->checksum; LOG2_OF_INTEGER(header->alignsize, jb->log2_of_alignsize); assert(header->autoswitchlimit == csd->autoswitchlimit); assert(header->jnl_alq == csd->jnl_alq); assert(header->jnl_deq == csd->jnl_deq); assert(csd->autoswitchlimit >= csd->jnl_alq); assert(ALIGNED_ROUND_UP(csd->autoswitchlimit, csd->jnl_alq, csd->jnl_deq) == csd->autoswitchlimit); assert(csd->autoswitchlimit); JNL_WHOLE_TIME(prc_vec->jpv_time); jb->epoch_interval = header->epoch_interval; jb->next_epoch_time = (uint4)(MID_TIME(prc_vec->jpv_time) + jb->epoch_interval); jb->max_jrec_len = header->max_jrec_len; memcpy(&header->who_opened, prc_vec, SIZEOF(jnl_process_vector)); header->crash = TRUE; /* in case this processes is crashed, this will remain TRUE */ VMS_ONLY( if (REPL_ENABLED(csd) && pool_init) header->update_disabled = jnlpool_ctl->upd_disabled; ) JNL_DO_FILE_WRITE(csa, csd->jnl_file_name, jpc->channel, 0, header, read_write_size, jpc->status, jpc->status2); if (SS_NORMAL != jpc->status) { assert(WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC)); return ERR_JNLWRERR; } if (!jb->prev_jrec_time || !header->prev_jnl_file_name_length) { /* This is the first time a journal file for this database is being opened OR the previous link is NULL. * In both these cases, we dont know or care about the timestamp of the last written journal record. * Set it to the current time as we know it. */ jb->prev_jrec_time = jgbl.gbl_jrec_time; } jb->end_of_data = 0; jb->eov_tn = 0; jb->eov_timestamp = 0; jb->end_seqno = 0; return 0; } fis-gtm-V6.0-003/sr_port/jnl_file_open_switch.c0000644000032200000250000000460312201176160020361 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_time.h" #include "gtm_unistd.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "send_msg.h" #include "gtmio.h" #include "repl_sp.h" #include "iosp.h" /* for SS_NORMAL */ #include "wbox_test_init.h" GBLREF jnl_gbls_t jgbl; error_def(ERR_JNLFILOPN); error_def(ERR_JNLINVALID); error_def(ERR_PREVJNLLINKCUT); uint4 jnl_file_open_switch(gd_region *reg, uint4 sts) { sgmnt_addrs *csa; jnl_private_control *jpc; jnl_create_info create; char prev_jnl_fn[JNL_NAME_SIZE]; int status; csa = &FILE_INFO(reg)->s_addrs; jpc = csa->jnl; assert((ERR_JNLFILOPN != sts) && (NOJNL != jpc->channel) || (ERR_JNLFILOPN == sts) && (NOJNL == jpc->channel)); if (NOJNL != jpc->channel) JNL_FD_CLOSE(jpc->channel, status); /* sets jpc->channel to NOJNL */ jnl_send_oper(jpc, sts); /* attempt to create a new journal file */ memset(&create, 0, SIZEOF(create)); create.status = create.status2 = SS_NORMAL; create.prev_jnl = &prev_jnl_fn[0]; set_jnl_info(reg, &create); create.no_prev_link = TRUE; create.no_rename = FALSE; assert(!jgbl.forw_phase_recovery || WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC)); if (!jgbl.dont_reset_gbl_jrec_time) SET_GBL_JREC_TIME; /* needed for cre_jnl_file() */ /* else mur_output_record() would have already set jgbl.gbl_jrec_time */ assert(jgbl.gbl_jrec_time); if (EXIT_NRM != cre_jnl_file(&create)) { jpc->status = create.status; jpc->status2 = create.status2; return ERR_JNLINVALID; } else { jpc->status = SS_NORMAL; csa->hdr->jnl_checksum = create.checksum; csa->hdr->jnl_eovtn = csa->hdr->trans_hist.curr_tn; } send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4, JNL_LEN_STR(csa->hdr), DB_LEN_STR(reg)); assert(csa->hdr->jnl_file_len == create.jnl_len); assert(0 == memcmp(csa->hdr->jnl_file_name, create.jnl, create.jnl_len)); return 0; } fis-gtm-V6.0-003/sr_port/jnl_flush.c0000644000032200000250000000322512201176160016160 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "iosp.h" #include "jnl.h" #include "wbox_test_init.h" #ifdef UNIX #include "gtm_threadgbl.h" #endif GBLREF uint4 process_id; uint4 jnl_flush(gd_region *reg) { sgmnt_addrs *csa; node_local_ptr_t cnl; jnl_private_control *jpc; jnl_buffer_ptr_t jb; uint4 status; #ifdef UNIX DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; #endif if (!reg || !reg->open) return SS_NORMAL; csa = &FILE_INFO(reg)->s_addrs; assert(csa->now_crit); jpc = csa->jnl; if (!JNL_ENABLED(csa->hdr) || (NULL == jpc) || (NOJNL == jpc->channel)) return SS_NORMAL; jb = jpc->jnl_buff; jb->blocked = process_id; if (jb->freeaddr != jb->dskaddr) { status = jnl_write_attempt(jpc, jb->freeaddr); if (SS_NORMAL == status) { cnl = csa->nl; INCR_GVSTATS_COUNTER(csa, cnl, n_jnl_flush, 1); } } else status = SS_NORMAL; assert(((SS_NORMAL == status) && (jb->dskaddr == jb->freeaddr)) UNIX_ONLY(|| TREF(gtm_test_fake_enospc)) || (gtm_white_box_test_case_enabled && (WBTEST_JNL_FILE_LOST_DSKADDR == gtm_white_box_test_case_number))); jb->blocked = 0; return status; } fis-gtm-V6.0-003/sr_port/jnl_format.c0000644000032200000250000003357012201176177016345 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include /* for offsetof() macro */ #include "gtm_string.h" #include "gdsroot.h" #include "gdskill.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "cdb_sc.h" #include "min_max.h" /* needed for gdsblkops.h */ #include "gdsblkops.h" #include "jnl.h" #include "gdscc.h" #include "iosp.h" #include #include "ccp.h" #include "buddy_list.h" /* needed for tp.h */ #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "copy.h" #include "jnl_get_checksum.h" #include "gdsblk.h" /* for blk_hdr usage in JNL_MAX_SET_KILL_RECLEN macro */ #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif #ifdef GTM_TRIGGER /* In case of a ZTWORMHOLE, it should be immediately followed by a SET or KILL record. We do not maintain different * update_num values for the ZTWORMHOLE and its corresponding SET or KILL record. So we should decrement the * update_num before returning from this function in the hope that the next time jnl_format is called for the SET * or KILL, update_num will be incremented thereby using the exact same value that was used for the ZTWORMHOLE record. * An exception is journal recovery forward phase in which case, we dont do any increments of jgbl.tp_ztp_jnl_upd_num * so we should do no decrements either. */ #define ZTWORM_DECR_UPD_NUM { if (!jgbl.forw_phase_recovery) jgbl.tp_ztp_jnl_upd_num--; } #define SET_PREV_ZTWORM_JFB_IF_NEEDED(is_ztworm_rec, src_ptr) \ { \ if (is_ztworm_rec && !jgbl.forw_phase_recovery) \ { \ jgbl.save_ztworm_ptr = jgbl.prev_ztworm_ptr; \ jgbl.prev_ztworm_ptr = (unsigned char *)src_ptr; \ ZTWORM_DECR_UPD_NUM; \ } \ } #else #define SET_PREV_ZTWORM_JFB_IF_NEEDED(is_ztworm_rec, src_ptr) #endif GBLREF gd_region *gv_cur_region; GBLREF uint4 dollar_tlevel; GBLREF jnl_fence_control jnl_fence_ctl; GBLREF sgm_info *sgm_info_ptr; GBLREF jnl_format_buffer *non_tp_jfb_ptr; GBLREF jnl_gbls_t jgbl; #ifdef GTM_TRIGGER GBLREF int4 gtm_trigger_depth; GBLREF int4 tstart_trigger_depth; #endif /* Do NOT define first dimension of jnl_opcode array to be JA_MAX_TYPES. Instead let compiler fill in the value according * to the number of rows actually specified in the array. This way, if ever a new entry is added in jnl.h to jnl_action_code * (thereby increasing JA_MAX_TYPES) but is forgotten to add a corresponding row here, an assert (in this module) will fail * indicating the inconsistency. Defining jnl_opcode[JA_MAX_TYPES][5] causes any changes to JA_MAX_TYPES to automatically * allocate a bigger array filled with 0s which might cause one to overlook the inconsistency. */ static const enum jnl_record_type jnl_opcode[][5] = { { JRT_KILL, JRT_FKILL, JRT_TKILL, JRT_GKILL, JRT_UKILL }, /* KILL record types */ { JRT_SET, JRT_FSET, JRT_TSET, JRT_GSET, JRT_USET }, /* SET record types */ { JRT_ZKILL, JRT_FZKILL, JRT_TZKILL, JRT_GZKILL, JRT_UZKILL }, /* ZKILL record types */ # ifdef GTM_TRIGGER { JRT_BAD, JRT_BAD, JRT_TZTWORM, JRT_BAD, JRT_UZTWORM }, /* ZTWORM record types */ { JRT_BAD, JRT_BAD, JRT_TZTRIG, JRT_BAD, JRT_UZTRIG }, /* ZTRIG record types */ # endif }; jnl_format_buffer *jnl_format(jnl_action_code opcode, gv_key *key, mval *val, uint4 nodeflags) { char *local_buffer, *mumps_node_ptr; enum jnl_record_type rectype; int subcode; jnl_record *rec; jnl_action *ja; jnl_format_buffer *prev_jfb, *jfb, *prev_prev_jfb; jnl_str_len_t keystrlen; mstr_len_t valstrlen; sgm_info *si; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; uint4 align_fill_size, jrec_size, tmp_jrec_size, update_length; boolean_t is_ztworm_rec = FALSE; uint4 cursum; DEBUG_ONLY( static boolean_t dbg_in_jnl_format = FALSE; ) # ifdef GTM_CRYPT int gtmcrypt_errno; gd_segment *seg; # endif # ifdef GTM_TRIGGER boolean_t ztworm_matched, match_possible; mstr prev_str, *cur_str; # endif /* The below assert ensures that if ever jnl_format is interrupted by a signal, the interrupt handler never calls * jnl_format again. This is because jnl_format plays with global pointers and we would possibly end up in a bad * state if the interrupt handler calls jnl_format again. */ assert(!dbg_in_jnl_format); DEBUG_ONLY(dbg_in_jnl_format = TRUE;) if (jgbl.forw_phase_recovery) /* In case of recovery, copy "nodeflags" from journal record being played */ nodeflags = jgbl.mur_jrec_nodeflags; csa = &FILE_INFO(gv_cur_region)->s_addrs; csd = csa->hdr; # ifdef GTM_TRIGGER /* If opcode is JNL_ZTWORM then check if ztwormhole operation can be avoided altogether. * This is the case if the value of $ZTWORMHOLE passed in is identical to the value of * $ZTWORMHOLE written for the immediately previous update stored in (global variable) jgbl.prev_ztworm_ptr * across regions in the current TP transaction. In that case, return right away. * For journal recovery, we skip this part since we want the ztwormhole record to be unconditionally written * (because GT.M wrote it in the first place). */ is_ztworm_rec = (JNL_ZTWORM == opcode); if (is_ztworm_rec && !jgbl.forw_phase_recovery) { assert(REPL_ALLOWED(csa) || jgbl.forw_phase_recovery); assert(dollar_tlevel); assert(tstart_trigger_depth == gtm_trigger_depth); assert((NULL != val) && (NULL == key)); assert(MV_IS_STRING(val)); assert(FIXED_UPD_RECLEN == FIXED_ZTWORM_RECLEN); if (NULL != jgbl.prev_ztworm_ptr) { cur_str = &val->str; prev_str.len = (*(jnl_str_len_t *)jgbl.prev_ztworm_ptr); prev_str.addr = (char *)(jgbl.prev_ztworm_ptr + SIZEOF(jnl_str_len_t)); if ((prev_str.len == cur_str->len) && !memcmp(prev_str.addr, cur_str->addr, prev_str.len)) { DEBUG_ONLY(dbg_in_jnl_format = FALSE;) return NULL; } } } # endif /* Allocate a jfb structure */ if (!dollar_tlevel) { jfb = non_tp_jfb_ptr; /* already malloced in gvcst_init() */ jgbl.cumul_jnl_rec_len = 0; DEBUG_ONLY(jgbl.cumul_index = jgbl.cu_jnl_index = 0;) } else { si = sgm_info_ptr; /* reset "si" since previous set was #ifdef GTM_TRIGGER only code while this is not */ assert(si->tp_csa == csa); assert((NULL != si->jnl_head) || (NULL == csa->next_fenced)); assert((NULL == si->jnl_head) || (NULL != csa->next_fenced)); assert((NULL == csa->next_fenced) || (JNL_FENCE_LIST_END == csa->next_fenced) || (NULL != csa->next_fenced->sgm_info_ptr->jnl_head)); jfb = (jnl_format_buffer *)get_new_element(si->jnl_list, 1); jfb->next = NULL; assert(NULL != si->jnl_tail); GTMTRIG_ONLY(SET_PREV_JFB(si, jfb->prev);) assert(NULL == *si->jnl_tail); *si->jnl_tail = jfb; si->jnl_tail = &jfb->next; si->update_trans |= UPDTRNS_JNL_LOGICAL_MASK; /* record that we are writing a logical jnl record in this region */ if (!(nodeflags & JS_NOT_REPLICATED_MASK)) si->update_trans |= UPDTRNS_JNL_REPLICATED_MASK; } ja = &(jfb->ja); ja->operation = opcode; ja->nodeflags = nodeflags; /* Proceed with formatting the journal record in the allocated jfb */ if (!jnl_fence_ctl.level && !dollar_tlevel) { /* Non-TP */ subcode = 0; tmp_jrec_size = FIXED_UPD_RECLEN + JREC_SUFFIX_SIZE; assert(0 == jgbl.tp_ztp_jnl_upd_num); } else { if (NULL == csa->next_fenced) { /* F (or T) */ assert((NULL != jnl_fence_ctl.fence_list) || (0 == jgbl.tp_ztp_jnl_upd_num)); subcode = 1; csa->next_fenced = jnl_fence_ctl.fence_list; jnl_fence_ctl.fence_list = csa; } else /* G (or U) */ { /* At least one call to "jnl_format" has occurred in this TP transaction already. We therefore * expect jgbl.tp_ztp_jnl_upd_num to be non-zero at this point. The only exception is if "jnl_format" * had been called just once before and that was for a ZTWORM type of record in which case it would be * zero (both ZTWORM and following SET/KILL record will have the same update_num value of 1). */ assert(jgbl.tp_ztp_jnl_upd_num GTMTRIG_ONLY(|| ((jfb->prev == si->jnl_head) && (JRT_TZTWORM == jfb->prev->rectype)))); subcode = 3; } if (dollar_tlevel) ++subcode; /* TP */ tmp_jrec_size = FIXED_UPD_RECLEN + JREC_SUFFIX_SIZE; assert(FIXED_UPD_RECLEN == FIXED_ZTWORM_RECLEN); if (!jgbl.forw_phase_recovery) jgbl.tp_ztp_jnl_upd_num++; /* In case of forward phase of journal recovery, this would have already been set to appropriate value. * It is necessary to honor the incoming jgbl value for ZTP (since recovery could be playing records * from the middle of a ZTP transaction because the rest are before the EPOCH), but for TP it is not * necessary since all records are guaranteed to be AFTER the EPOCH so we can generate the numbers in * this function too. But since we expect recovery to play the TP records in the exact order in which * GT.M wrote them no point regenerating the same set of numbers again here. So we use incoming jgbl always. */ } assert(ARRAYSIZE(jnl_opcode) == JA_MAX_TYPES); assert(JA_MAX_TYPES > opcode); rectype = jnl_opcode[opcode][subcode]; assert(IS_VALID_JRECTYPE(rectype)); assert(IS_SET_KILL_ZKILL_ZTRIG_ZTWORM(rectype)); GTMTRIG_ONLY(assert((JNL_ZTWORM != opcode) || (NULL == key));) GTMTRIG_ONLY(assert((JNL_ZTWORM == opcode) || (NULL != key));) /* Compute actual record length */ if (NULL != key) { keystrlen = key->end; tmp_jrec_size += keystrlen + SIZEOF(jnl_str_len_t); } GTMTRIG_ONLY(assert((JNL_ZTWORM != opcode) || (NULL != val));) assert((JNL_SET != opcode) || (NULL != val)); if (NULL != val) { valstrlen = val->str.len; tmp_jrec_size += valstrlen + SIZEOF(mstr_len_t); } jrec_size = ROUND_UP2(tmp_jrec_size, JNL_REC_START_BNDRY); align_fill_size = jrec_size - tmp_jrec_size; /* For JNL_REC_START_BNDRY alignment */ if (dollar_tlevel) { assert((1 << JFB_ELE_SIZE_IN_BITS) == JNL_REC_START_BNDRY); assert(JFB_ELE_SIZE == JNL_REC_START_BNDRY); jfb->buff = (char *)get_new_element(si->format_buff_list, jrec_size >> JFB_ELE_SIZE_IN_BITS); GTMCRYPT_ONLY( if (REPL_ALLOWED(csa)) jfb->alt_buff = (char *)get_new_element(si->format_buff_list, jrec_size >> JFB_ELE_SIZE_IN_BITS); ) /* assume an align record will be written while computing maximum jnl-rec size requirements */ si->total_jnl_rec_size += (int)(jrec_size + MIN_ALIGN_RECLEN); } /* else if (!dollar_tlevel) jfb->buff/jfb->alt_buff already malloced in gvcst_init. */ jfb->record_size = jrec_size; jgbl.cumul_jnl_rec_len += jfb->record_size; assert(0 == jgbl.cumul_jnl_rec_len % JNL_REC_START_BNDRY); DEBUG_ONLY(jgbl.cumul_index++;) jfb->rectype = rectype; /* PREFIX */ rec = (jnl_record *)jfb->buff; rec->prefix.jrec_type = rectype; assert(!IS_SET_KILL_ZKILL_ZTRIG(rectype) || (JNL_MAX_SET_KILL_RECLEN(csd) >= jrec_size)); GTMTRIG_ONLY(assert(!IS_ZTWORM(rectype) || (MAX_ZTWORM_JREC_LEN >= jrec_size));) rec->prefix.forwptr = jrec_size; assert(&rec->jrec_set_kill.update_num == &rec->jrec_ztworm.update_num); rec->jrec_set_kill.update_num = jgbl.tp_ztp_jnl_upd_num; rec->jrec_set_kill.num_participants = 0; local_buffer = (char *)rec + FIXED_UPD_RECLEN; mumps_node_ptr = local_buffer; if (NULL != key) { ((jnl_string *)local_buffer)->length = keystrlen; ((jnl_string *)local_buffer)->nodeflags = nodeflags; local_buffer += SIZEOF(jnl_str_len_t); memcpy(local_buffer, (uchar_ptr_t)key->base, keystrlen); local_buffer += keystrlen; } if (NULL != val) { PUT_MSTR_LEN(local_buffer, valstrlen); /* SET command's data may not be aligned */ /* The below assert ensures that it is okay for us to increment by jnl_str_len_t (uint4) * even though valstrlen (above) is of type mstr_len_t (int). This is because PUT_MSTR_LEN * casts the input to (uint4*) before storing it in the destination pointer (in this case * local_buffer) */ assert(SIZEOF(uint4) == SIZEOF(jnl_str_len_t)); local_buffer += SIZEOF(jnl_str_len_t); memcpy(local_buffer, (uchar_ptr_t)val->str.addr, valstrlen); local_buffer += valstrlen; } if (0 != align_fill_size) { memset(local_buffer, 0, align_fill_size); local_buffer += align_fill_size; } /* SUFFIX */ ((jrec_suffix *)local_buffer)->backptr = jrec_size; ((jrec_suffix *)local_buffer)->suffix_code = JNL_REC_SUFFIX_CODE; update_length = (jrec_size - (JREC_SUFFIX_SIZE + FIXED_UPD_RECLEN)); # ifdef GTM_CRYPT assert(REPL_ALLOWED(csa) || !is_ztworm_rec || jgbl.forw_phase_recovery); if (csd->is_encrypted) { /* At this point we have all the components of *SET, *KILL, *ZTWORM and *ZTRIG records filled. */ if (REPL_ALLOWED(csa)) { /* Before encrypting the journal record, copy the unencrypted buffer to an alternate buffer * that eventually gets copied to the journal pool (in jnl_write). This way, the replication * stream sends unencrypted data. */ memcpy(jfb->alt_buff, rec, jrec_size); SET_PREV_ZTWORM_JFB_IF_NEEDED(is_ztworm_rec, (jfb->alt_buff + FIXED_UPD_RECLEN)); } ASSERT_ENCRYPTION_INITIALIZED; /* Encrypt the logical portion of the record which eventually gets written to the journal buffer/file */ GTMCRYPT_ENCRYPT(csa, csa->encr_key_handle, mumps_node_ptr, update_length, NULL, gtmcrypt_errno); if (0 != gtmcrypt_errno) { seg = gv_cur_region->dyn.addr; GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, rts_error, seg->fname_len, seg->fname); } } else # endif { SET_PREV_ZTWORM_JFB_IF_NEEDED(is_ztworm_rec, mumps_node_ptr); } /* The below call to jnl_get_checksum makes sure that checksum computation happens AFTER the encryption (if turned on) */ jfb->checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)mumps_node_ptr, (int)(local_buffer - mumps_node_ptr)); assert(0 == ((UINTPTR_T)local_buffer % SIZEOF(jrec_suffix))); DEBUG_ONLY(dbg_in_jnl_format = FALSE;) return jfb; } fis-gtm-V6.0-003/sr_port/jnl_get_checksum.c0000644000032200000250000007272512201176160017513 0ustar librarygtc/**************************************************************** * * * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gdsbt.h" #include "gdsfhead.h" #include "jnl_get_checksum.h" /* The following four looktable are generated using following paramenters. * Generator Polynomial = ................. 0x1EDC6F41 * Generator Polynomial Length = .......... 32 bits * Reflected Bits = ....................... TRUE * Number of Slices = ..................... 4 slices */ GBLDEF uint4 csum_table[SLICE_BY][TABLE_SIZE] = { #ifdef BIGENDIAN { 0x0, 0x3836bf2, 0xf7703be1, 0xf4f35013, 0x1f979ac7, 0x1c14f135, 0xe8e7a126, 0xeb64cad4, 0xcf58d98a, 0xccdbb278, 0x3828e26b, 0x3bab8999, 0xd0cf434d, 0xd34c28bf, 0x27bf78ac, 0x243c135e, 0x6fc75e10, 0x6c4435e2, 0x98b765f1, 0x9b340e03, 0x7050c4d7, 0x73d3af25, 0x8720ff36, 0x84a394c4, 0xa09f879a, 0xa31cec68, 0x57efbc7b, 0x546cd789, 0xbf081d5d, 0xbc8b76af, 0x487826bc, 0x4bfb4d4e, 0xde8ebd20, 0xdd0dd6d2, 0x29fe86c1, 0x2a7ded33, 0xc11927e7, 0xc29a4c15, 0x36691c06, 0x35ea77f4, 0x11d664aa, 0x12550f58, 0xe6a65f4b, 0xe52534b9, 0xe41fe6d, 0xdc2959f, 0xf931c58c, 0xfab2ae7e, 0xb149e330, 0xb2ca88c2, 0x4639d8d1, 0x45bab323, 0xaede79f7, 0xad5d1205, 0x59ae4216, 0x5a2d29e4, 0x7e113aba, 0x7d925148, 0x8961015b, 0x8ae26aa9, 0x6186a07d, 0x6205cb8f, 0x96f69b9c, 0x9575f06e, 0xbc1d7b41, 0xbf9e10b3, 0x4b6d40a0, 0x48ee2b52, 0xa38ae186, 0xa0098a74, 0x54fada67, 0x5779b195, 0x7345a2cb, 0x70c6c939, 0x8435992a, 0x87b6f2d8, 0x6cd2380c, 0x6f5153fe, 0x9ba203ed, 0x9821681f, 0xd3da2551, 0xd0594ea3, 0x24aa1eb0, 0x27297542, 0xcc4dbf96, 0xcfced464, 0x3b3d8477, 0x38beef85, 0x1c82fcdb, 0x1f019729, 0xebf2c73a, 0xe871acc8, 0x315661c, 0x960dee, 0xf4655dfd, 0xf7e6360f, 0x6293c661, 0x6110ad93, 0x95e3fd80, 0x96609672, 0x7d045ca6, 0x7e873754, 0x8a746747, 0x89f70cb5, 0xadcb1feb, 0xae487419, 0x5abb240a, 0x59384ff8, 0xb25c852c, 0xb1dfeede, 0x452cbecd, 0x46afd53f, 0xd549871, 0xed7f383, 0xfa24a390, 0xf9a7c862, 0x12c302b6, 0x11406944, 0xe5b33957, 0xe63052a5, 0xc20c41fb, 0xc18f2a09, 0x357c7a1a, 0x36ff11e8, 0xdd9bdb3c, 0xde18b0ce, 0x2aebe0dd, 0x29688b2f, 0x783bf682, 0x7bb89d70, 0x8f4bcd63, 0x8cc8a691, 0x67ac6c45, 0x642f07b7, 0x90dc57a4, 0x935f3c56, 0xb7632f08, 0xb4e044fa, 0x401314e9, 0x43907f1b, 0xa8f4b5cf, 0xab77de3d, 0x5f848e2e, 0x5c07e5dc, 0x17fca892, 0x147fc360, 0xe08c9373, 0xe30ff881, 0x86b3255, 0xbe859a7, 0xff1b09b4, 0xfc986246, 0xd8a47118, 0xdb271aea, 0x2fd44af9, 0x2c57210b, 0xc733ebdf, 0xc4b0802d, 0x3043d03e, 0x33c0bbcc, 0xa6b54ba2, 0xa5362050, 0x51c57043, 0x52461bb1, 0xb922d165, 0xbaa1ba97, 0x4e52ea84, 0x4dd18176, 0x69ed9228, 0x6a6ef9da, 0x9e9da9c9, 0x9d1ec23b, 0x767a08ef, 0x75f9631d, 0x810a330e, 0x828958fc, 0xc97215b2, 0xcaf17e40, 0x3e022e53, 0x3d8145a1, 0xd6e58f75, 0xd566e487, 0x2195b494, 0x2216df66, 0x62acc38, 0x5a9a7ca, 0xf15af7d9, 0xf2d99c2b, 0x19bd56ff, 0x1a3e3d0d, 0xeecd6d1e, 0xed4e06ec, 0xc4268dc3, 0xc7a5e631, 0x3356b622, 0x30d5ddd0, 0xdbb11704, 0xd8327cf6, 0x2cc12ce5, 0x2f424717, 0xb7e5449, 0x8fd3fbb, 0xfc0e6fa8, 0xff8d045a, 0x14e9ce8e, 0x176aa57c, 0xe399f56f, 0xe01a9e9d, 0xabe1d3d3, 0xa862b821, 0x5c91e832, 0x5f1283c0, 0xb4764914, 0xb7f522e6, 0x430672f5, 0x40851907, 0x64b90a59, 0x673a61ab, 0x93c931b8, 0x904a5a4a, 0x7b2e909e, 0x78adfb6c, 0x8c5eab7f, 0x8fddc08d, 0x1aa830e3, 0x192b5b11, 0xedd80b02, 0xee5b60f0, 0x53faa24, 0x6bcc1d6, 0xf24f91c5, 0xf1ccfa37, 0xd5f0e969, 0xd673829b, 0x2280d288, 0x2103b97a, 0xca6773ae, 0xc9e4185c, 0x3d17484f, 0x3e9423bd, 0x756f6ef3, 0x76ec0501, 0x821f5512, 0x819c3ee0, 0x6af8f434, 0x697b9fc6, 0x9d88cfd5, 0x9e0ba427, 0xba37b779, 0xb9b4dc8b, 0x4d478c98, 0x4ec4e76a, 0xa5a02dbe, 0xa623464c, 0x52d0165f, 0x51537dad }, { 0x0, 0x7798a213, 0xee304527, 0x99a8e734, 0xdc618a4e, 0xabf9285d, 0x3251cf69, 0x45c96d7a, 0xb8c3149d, 0xcf5bb68e, 0x56f351ba, 0x216bf3a9, 0x64a29ed3, 0x133a3cc0, 0x8a92dbf4, 0xfd0a79e7, 0x81f1c53f, 0xf669672c, 0x6fc18018, 0x1859220b, 0x5d904f71, 0x2a08ed62, 0xb3a00a56, 0xc438a845, 0x3932d1a2, 0x4eaa73b1, 0xd7029485, 0xa09a3696, 0xe5535bec, 0x92cbf9ff, 0xb631ecb, 0x7cfbbcd8, 0x2e38b7f, 0x757b296c, 0xecd3ce58, 0x9b4b6c4b, 0xde820131, 0xa91aa322, 0x30b24416, 0x472ae605, 0xba209fe2, 0xcdb83df1, 0x5410dac5, 0x238878d6, 0x664115ac, 0x11d9b7bf, 0x8871508b, 0xffe9f298, 0x83124e40, 0xf48aec53, 0x6d220b67, 0x1abaa974, 0x5f73c40e, 0x28eb661d, 0xb1438129, 0xc6db233a, 0x3bd15add, 0x4c49f8ce, 0xd5e11ffa, 0xa279bde9, 0xe7b0d093, 0x90287280, 0x98095b4, 0x7e1837a7, 0x4c617ff, 0x735eb5ec, 0xeaf652d8, 0x9d6ef0cb, 0xd8a79db1, 0xaf3f3fa2, 0x3697d896, 0x410f7a85, 0xbc050362, 0xcb9da171, 0x52354645, 0x25ade456, 0x6064892c, 0x17fc2b3f, 0x8e54cc0b, 0xf9cc6e18, 0x8537d2c0, 0xf2af70d3, 0x6b0797e7, 0x1c9f35f4, 0x5956588e, 0x2ecefa9d, 0xb7661da9, 0xc0febfba, 0x3df4c65d, 0x4a6c644e, 0xd3c4837a, 0xa45c2169, 0xe1954c13, 0x960dee00, 0xfa50934, 0x783dab27, 0x6259c80, 0x71bd3e93, 0xe815d9a7, 0x9f8d7bb4, 0xda4416ce, 0xaddcb4dd, 0x347453e9, 0x43ecf1fa, 0xbee6881d, 0xc97e2a0e, 0x50d6cd3a, 0x274e6f29, 0x62870253, 0x151fa040, 0x8cb74774, 0xfb2fe567, 0x87d459bf, 0xf04cfbac, 0x69e41c98, 0x1e7cbe8b, 0x5bb5d3f1, 0x2c2d71e2, 0xb58596d6, 0xc21d34c5, 0x3f174d22, 0x488fef31, 0xd1270805, 0xa6bfaa16, 0xe376c76c, 0x94ee657f, 0xd46824b, 0x7ade2058, 0xf9fac3fb, 0x8e6261e8, 0x17ca86dc, 0x605224cf, 0x259b49b5, 0x5203eba6, 0xcbab0c92, 0xbc33ae81, 0x4139d766, 0x36a17575, 0xaf099241, 0xd8913052, 0x9d585d28, 0xeac0ff3b, 0x7368180f, 0x4f0ba1c, 0x780b06c4, 0xf93a4d7, 0x963b43e3, 0xe1a3e1f0, 0xa46a8c8a, 0xd3f22e99, 0x4a5ac9ad, 0x3dc26bbe, 0xc0c81259, 0xb750b04a, 0x2ef8577e, 0x5960f56d, 0x1ca99817, 0x6b313a04, 0xf299dd30, 0x85017f23, 0xfb194884, 0x8c81ea97, 0x15290da3, 0x62b1afb0, 0x2778c2ca, 0x50e060d9, 0xc94887ed, 0xbed025fe, 0x43da5c19, 0x3442fe0a, 0xadea193e, 0xda72bb2d, 0x9fbbd657, 0xe8237444, 0x718b9370, 0x6133163, 0x7ae88dbb, 0xd702fa8, 0x94d8c89c, 0xe3406a8f, 0xa68907f5, 0xd111a5e6, 0x48b942d2, 0x3f21e0c1, 0xc22b9926, 0xb5b33b35, 0x2c1bdc01, 0x5b837e12, 0x1e4a1368, 0x69d2b17b, 0xf07a564f, 0x87e2f45c, 0xfd3cd404, 0x8aa47617, 0x130c9123, 0x64943330, 0x215d5e4a, 0x56c5fc59, 0xcf6d1b6d, 0xb8f5b97e, 0x45ffc099, 0x3267628a, 0xabcf85be, 0xdc5727ad, 0x999e4ad7, 0xee06e8c4, 0x77ae0ff0, 0x36ade3, 0x7ccd113b, 0xb55b328, 0x92fd541c, 0xe565f60f, 0xa0ac9b75, 0xd7343966, 0x4e9cde52, 0x39047c41, 0xc40e05a6, 0xb396a7b5, 0x2a3e4081, 0x5da6e292, 0x186f8fe8, 0x6ff72dfb, 0xf65fcacf, 0x81c768dc, 0xffdf5f7b, 0x8847fd68, 0x11ef1a5c, 0x6677b84f, 0x23bed535, 0x54267726, 0xcd8e9012, 0xba163201, 0x471c4be6, 0x3084e9f5, 0xa92c0ec1, 0xdeb4acd2, 0x9b7dc1a8, 0xece563bb, 0x754d848f, 0x2d5269c, 0x7e2e9a44, 0x9b63857, 0x901edf63, 0xe7867d70, 0xa24f100a, 0xd5d7b219, 0x4c7f552d, 0x3be7f73e, 0xc6ed8ed9, 0xb1752cca, 0x28ddcbfe, 0x5f4569ed, 0x1a8c0497, 0x6d14a684, 0xf4bc41b0, 0x8324e3a3 }, { 0x0, 0x7e9241a5, 0xd526f4f, 0x73c02eea, 0x1aa4de9e, 0x64369f3b, 0x17f6b1d1, 0x6964f074, 0xc53e5138, 0xbbac109d, 0xc86c3e77, 0xb6fe7fd2, 0xdf9a8fa6, 0xa108ce03, 0xd2c8e0e9, 0xac5aa14c, 0x8a7da270, 0xf4efe3d5, 0x872fcd3f, 0xf9bd8c9a, 0x90d97cee, 0xee4b3d4b, 0x9d8b13a1, 0xe3195204, 0x4f43f348, 0x31d1b2ed, 0x42119c07, 0x3c83dda2, 0x55e72dd6, 0x2b756c73, 0x58b54299, 0x2627033c, 0x14fb44e1, 0x6a690544, 0x19a92bae, 0x673b6a0b, 0xe5f9a7f, 0x70cddbda, 0x30df530, 0x7d9fb495, 0xd1c515d9, 0xaf57547c, 0xdc977a96, 0xa2053b33, 0xcb61cb47, 0xb5f38ae2, 0xc633a408, 0xb8a1e5ad, 0x9e86e691, 0xe014a734, 0x93d489de, 0xed46c87b, 0x8422380f, 0xfab079aa, 0x89705740, 0xf7e216e5, 0x5bb8b7a9, 0x252af60c, 0x56ead8e6, 0x28789943, 0x411c6937, 0x3f8e2892, 0x4c4e0678, 0x32dc47dd, 0xd98065c7, 0xa7122462, 0xd4d20a88, 0xaa404b2d, 0xc324bb59, 0xbdb6fafc, 0xce76d416, 0xb0e495b3, 0x1cbe34ff, 0x622c755a, 0x11ec5bb0, 0x6f7e1a15, 0x61aea61, 0x7888abc4, 0xb48852e, 0x75dac48b, 0x53fdc7b7, 0x2d6f8612, 0x5eafa8f8, 0x203de95d, 0x49591929, 0x37cb588c, 0x440b7666, 0x3a9937c3, 0x96c3968f, 0xe851d72a, 0x9b91f9c0, 0xe503b865, 0x8c674811, 0xf2f509b4, 0x8135275e, 0xffa766fb, 0xcd7b2126, 0xb3e96083, 0xc0294e69, 0xbebb0fcc, 0xd7dfffb8, 0xa94dbe1d, 0xda8d90f7, 0xa41fd152, 0x845701e, 0x76d731bb, 0x5171f51, 0x7b855ef4, 0x12e1ae80, 0x6c73ef25, 0x1fb3c1cf, 0x6121806a, 0x47068356, 0x3994c2f3, 0x4a54ec19, 0x34c6adbc, 0x5da25dc8, 0x23301c6d, 0x50f03287, 0x2e627322, 0x8238d26e, 0xfcaa93cb, 0x8f6abd21, 0xf1f8fc84, 0x989c0cf0, 0xe60e4d55, 0x95ce63bf, 0xeb5c221a, 0x4377278b, 0x3de5662e, 0x4e2548c4, 0x30b70961, 0x59d3f915, 0x2741b8b0, 0x5481965a, 0x2a13d7ff, 0x864976b3, 0xf8db3716, 0x8b1b19fc, 0xf5895859, 0x9ceda82d, 0xe27fe988, 0x91bfc762, 0xef2d86c7, 0xc90a85fb, 0xb798c45e, 0xc458eab4, 0xbacaab11, 0xd3ae5b65, 0xad3c1ac0, 0xdefc342a, 0xa06e758f, 0xc34d4c3, 0x72a69566, 0x166bb8c, 0x7ff4fa29, 0x16900a5d, 0x68024bf8, 0x1bc26512, 0x655024b7, 0x578c636a, 0x291e22cf, 0x5ade0c25, 0x244c4d80, 0x4d28bdf4, 0x33bafc51, 0x407ad2bb, 0x3ee8931e, 0x92b23252, 0xec2073f7, 0x9fe05d1d, 0xe1721cb8, 0x8816eccc, 0xf684ad69, 0x85448383, 0xfbd6c226, 0xddf1c11a, 0xa36380bf, 0xd0a3ae55, 0xae31eff0, 0xc7551f84, 0xb9c75e21, 0xca0770cb, 0xb495316e, 0x18cf9022, 0x665dd187, 0x159dff6d, 0x6b0fbec8, 0x26b4ebc, 0x7cf90f19, 0xf3921f3, 0x71ab6056, 0x9af7424c, 0xe46503e9, 0x97a52d03, 0xe9376ca6, 0x80539cd2, 0xfec1dd77, 0x8d01f39d, 0xf393b238, 0x5fc91374, 0x215b52d1, 0x529b7c3b, 0x2c093d9e, 0x456dcdea, 0x3bff8c4f, 0x483fa2a5, 0x36ade300, 0x108ae03c, 0x6e18a199, 0x1dd88f73, 0x634aced6, 0xa2e3ea2, 0x74bc7f07, 0x77c51ed, 0x79ee1048, 0xd5b4b104, 0xab26f0a1, 0xd8e6de4b, 0xa6749fee, 0xcf106f9a, 0xb1822e3f, 0xc24200d5, 0xbcd04170, 0x8e0c06ad, 0xf09e4708, 0x835e69e2, 0xfdcc2847, 0x94a8d833, 0xea3a9996, 0x99fab77c, 0xe768f6d9, 0x4b325795, 0x35a01630, 0x466038da, 0x38f2797f, 0x5196890b, 0x2f04c8ae, 0x5cc4e644, 0x2256a7e1, 0x471a4dd, 0x7ae3e578, 0x923cb92, 0x77b18a37, 0x1ed57a43, 0x60473be6, 0x1387150c, 0x6d1554a9, 0xc14ff5e5, 0xbfddb440, 0xcc1d9aaa, 0xb28fdb0f, 0xdbeb2b7b, 0xa5796ade, 0xd6b94434, 0xa82b0591 }, { 0x0, 0xb8aa45dd, 0x812367bf, 0x39892262, 0xf331227b, 0x4b9b67a6, 0x721245c4, 0xcab80019, 0xe66344f6, 0x5ec9012b, 0x67402349, 0xdfea6694, 0x1552668d, 0xadf82350, 0x94710132, 0x2cdb44ef, 0x3db164e9, 0x851b2134, 0xbc920356, 0x438468b, 0xce804692, 0x762a034f, 0x4fa3212d, 0xf70964f0, 0xdbd2201f, 0x637865c2, 0x5af147a0, 0xe25b027d, 0x28e30264, 0x904947b9, 0xa9c065db, 0x116a2006, 0x8b1425d7, 0x33be600a, 0xa374268, 0xb29d07b5, 0x782507ac, 0xc08f4271, 0xf9066013, 0x41ac25ce, 0x6d776121, 0xd5dd24fc, 0xec54069e, 0x54fe4343, 0x9e46435a, 0x26ec0687, 0x1f6524e5, 0xa7cf6138, 0xb6a5413e, 0xe0f04e3, 0x37862681, 0x8f2c635c, 0x45946345, 0xfd3e2698, 0xc4b704fa, 0x7c1d4127, 0x50c605c8, 0xe86c4015, 0xd1e56277, 0x694f27aa, 0xa3f727b3, 0x1b5d626e, 0x22d4400c, 0x9a7e05d1, 0xe75fa6ab, 0x5ff5e376, 0x667cc114, 0xded684c9, 0x146e84d0, 0xacc4c10d, 0x954de36f, 0x2de7a6b2, 0x13ce25d, 0xb996a780, 0x801f85e2, 0x38b5c03f, 0xf20dc026, 0x4aa785fb, 0x732ea799, 0xcb84e244, 0xdaeec242, 0x6244879f, 0x5bcda5fd, 0xe367e020, 0x29dfe039, 0x9175a5e4, 0xa8fc8786, 0x1056c25b, 0x3c8d86b4, 0x8427c369, 0xbdaee10b, 0x504a4d6, 0xcfbca4cf, 0x7716e112, 0x4e9fc370, 0xf63586ad, 0x6c4b837c, 0xd4e1c6a1, 0xed68e4c3, 0x55c2a11e, 0x9f7aa107, 0x27d0e4da, 0x1e59c6b8, 0xa6f38365, 0x8a28c78a, 0x32828257, 0xb0ba035, 0xb3a1e5e8, 0x7919e5f1, 0xc1b3a02c, 0xf83a824e, 0x4090c793, 0x51fae795, 0xe950a248, 0xd0d9802a, 0x6873c5f7, 0xa2cbc5ee, 0x1a618033, 0x23e8a251, 0x9b42e78c, 0xb799a363, 0xf33e6be, 0x36bac4dc, 0x8e108101, 0x44a88118, 0xfc02c4c5, 0xc58be6a7, 0x7d21a37a, 0x3fc9a052, 0x8763e58f, 0xbeeac7ed, 0x6408230, 0xccf88229, 0x7452c7f4, 0x4ddbe596, 0xf571a04b, 0xd9aae4a4, 0x6100a179, 0x5889831b, 0xe023c6c6, 0x2a9bc6df, 0x92318302, 0xabb8a160, 0x1312e4bd, 0x278c4bb, 0xbad28166, 0x835ba304, 0x3bf1e6d9, 0xf149e6c0, 0x49e3a31d, 0x706a817f, 0xc8c0c4a2, 0xe41b804d, 0x5cb1c590, 0x6538e7f2, 0xdd92a22f, 0x172aa236, 0xaf80e7eb, 0x9609c589, 0x2ea38054, 0xb4dd8585, 0xc77c058, 0x35fee23a, 0x8d54a7e7, 0x47eca7fe, 0xff46e223, 0xc6cfc041, 0x7e65859c, 0x52bec173, 0xea1484ae, 0xd39da6cc, 0x6b37e311, 0xa18fe308, 0x1925a6d5, 0x20ac84b7, 0x9806c16a, 0x896ce16c, 0x31c6a4b1, 0x84f86d3, 0xb0e5c30e, 0x7a5dc317, 0xc2f786ca, 0xfb7ea4a8, 0x43d4e175, 0x6f0fa59a, 0xd7a5e047, 0xee2cc225, 0x568687f8, 0x9c3e87e1, 0x2494c23c, 0x1d1de05e, 0xa5b7a583, 0xd89606f9, 0x603c4324, 0x59b56146, 0xe11f249b, 0x2ba72482, 0x930d615f, 0xaa84433d, 0x122e06e0, 0x3ef5420f, 0x865f07d2, 0xbfd625b0, 0x77c606d, 0xcdc46074, 0x756e25a9, 0x4ce707cb, 0xf44d4216, 0xe5276210, 0x5d8d27cd, 0x640405af, 0xdcae4072, 0x1616406b, 0xaebc05b6, 0x973527d4, 0x2f9f6209, 0x34426e6, 0xbbee633b, 0x82674159, 0x3acd0484, 0xf075049d, 0x48df4140, 0x71566322, 0xc9fc26ff, 0x5382232e, 0xeb2866f3, 0xd2a14491, 0x6a0b014c, 0xa0b30155, 0x18194488, 0x219066ea, 0x993a2337, 0xb5e167d8, 0xd4b2205, 0x34c20067, 0x8c6845ba, 0x46d045a3, 0xfe7a007e, 0xc7f3221c, 0x7f5967c1, 0x6e3347c7, 0xd699021a, 0xef102078, 0x57ba65a5, 0x9d0265bc, 0x25a82061, 0x1c210203, 0xa48b47de, 0x88500331, 0x30fa46ec, 0x973648e, 0xb1d92153, 0x7b61214a, 0xc3cb6497, 0xfa4246f5, 0x42e80328 } #else { 0x0, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, 0x105ec76f, 0xe235446c, 0xf165b798, 0x30e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, 0xe72719c1, 0x154c9ac2, 0x61c6936, 0xf477ea35, 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x5125dad, 0x1642ae59, 0xe4292d5a, 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0xc38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0xf36e6f7, 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, 0xeb1fcbad, 0x197448ae, 0xa24bb5a, 0xf84f3859, 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, 0xfb410cc2, 0x92a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, 0x82f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0xb21572c, 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975, 0xe330a81, 0xfc588982, 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0xd3d3e1a, 0x1e6dcdee, 0xec064eed, 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x7198540, 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, 0xe330a81a, 0x115b2b19, 0x20bd8ed, 0xf0605bee, 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, 0xf36e6f75, 0x105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351 }, { 0x0, 0x13a29877, 0x274530ee, 0x34e7a899, 0x4e8a61dc, 0x5d28f9ab, 0x69cf5132, 0x7a6dc945, 0x9d14c3b8, 0x8eb65bcf, 0xba51f356, 0xa9f36b21, 0xd39ea264, 0xc03c3a13, 0xf4db928a, 0xe7790afd, 0x3fc5f181, 0x2c6769f6, 0x1880c16f, 0xb225918, 0x714f905d, 0x62ed082a, 0x560aa0b3, 0x45a838c4, 0xa2d13239, 0xb173aa4e, 0x859402d7, 0x96369aa0, 0xec5b53e5, 0xfff9cb92, 0xcb1e630b, 0xd8bcfb7c, 0x7f8be302, 0x6c297b75, 0x58ced3ec, 0x4b6c4b9b, 0x310182de, 0x22a31aa9, 0x1644b230, 0x5e62a47, 0xe29f20ba, 0xf13db8cd, 0xc5da1054, 0xd6788823, 0xac154166, 0xbfb7d911, 0x8b507188, 0x98f2e9ff, 0x404e1283, 0x53ec8af4, 0x670b226d, 0x74a9ba1a, 0xec4735f, 0x1d66eb28, 0x298143b1, 0x3a23dbc6, 0xdd5ad13b, 0xcef8494c, 0xfa1fe1d5, 0xe9bd79a2, 0x93d0b0e7, 0x80722890, 0xb4958009, 0xa737187e, 0xff17c604, 0xecb55e73, 0xd852f6ea, 0xcbf06e9d, 0xb19da7d8, 0xa23f3faf, 0x96d89736, 0x857a0f41, 0x620305bc, 0x71a19dcb, 0x45463552, 0x56e4ad25, 0x2c896460, 0x3f2bfc17, 0xbcc548e, 0x186eccf9, 0xc0d23785, 0xd370aff2, 0xe797076b, 0xf4359f1c, 0x8e585659, 0x9dface2e, 0xa91d66b7, 0xbabffec0, 0x5dc6f43d, 0x4e646c4a, 0x7a83c4d3, 0x69215ca4, 0x134c95e1, 0xee0d96, 0x3409a50f, 0x27ab3d78, 0x809c2506, 0x933ebd71, 0xa7d915e8, 0xb47b8d9f, 0xce1644da, 0xddb4dcad, 0xe9537434, 0xfaf1ec43, 0x1d88e6be, 0xe2a7ec9, 0x3acdd650, 0x296f4e27, 0x53028762, 0x40a01f15, 0x7447b78c, 0x67e52ffb, 0xbf59d487, 0xacfb4cf0, 0x981ce469, 0x8bbe7c1e, 0xf1d3b55b, 0xe2712d2c, 0xd69685b5, 0xc5341dc2, 0x224d173f, 0x31ef8f48, 0x50827d1, 0x16aabfa6, 0x6cc776e3, 0x7f65ee94, 0x4b82460d, 0x5820de7a, 0xfbc3faf9, 0xe861628e, 0xdc86ca17, 0xcf245260, 0xb5499b25, 0xa6eb0352, 0x920cabcb, 0x81ae33bc, 0x66d73941, 0x7575a136, 0x419209af, 0x523091d8, 0x285d589d, 0x3bffc0ea, 0xf186873, 0x1cbaf004, 0xc4060b78, 0xd7a4930f, 0xe3433b96, 0xf0e1a3e1, 0x8a8c6aa4, 0x992ef2d3, 0xadc95a4a, 0xbe6bc23d, 0x5912c8c0, 0x4ab050b7, 0x7e57f82e, 0x6df56059, 0x1798a91c, 0x43a316b, 0x30dd99f2, 0x237f0185, 0x844819fb, 0x97ea818c, 0xa30d2915, 0xb0afb162, 0xcac27827, 0xd960e050, 0xed8748c9, 0xfe25d0be, 0x195cda43, 0xafe4234, 0x3e19eaad, 0x2dbb72da, 0x57d6bb9f, 0x447423e8, 0x70938b71, 0x63311306, 0xbb8de87a, 0xa82f700d, 0x9cc8d894, 0x8f6a40e3, 0xf50789a6, 0xe6a511d1, 0xd242b948, 0xc1e0213f, 0x26992bc2, 0x353bb3b5, 0x1dc1b2c, 0x127e835b, 0x68134a1e, 0x7bb1d269, 0x4f567af0, 0x5cf4e287, 0x4d43cfd, 0x1776a48a, 0x23910c13, 0x30339464, 0x4a5e5d21, 0x59fcc556, 0x6d1b6dcf, 0x7eb9f5b8, 0x99c0ff45, 0x8a626732, 0xbe85cfab, 0xad2757dc, 0xd74a9e99, 0xc4e806ee, 0xf00fae77, 0xe3ad3600, 0x3b11cd7c, 0x28b3550b, 0x1c54fd92, 0xff665e5, 0x759baca0, 0x663934d7, 0x52de9c4e, 0x417c0439, 0xa6050ec4, 0xb5a796b3, 0x81403e2a, 0x92e2a65d, 0xe88f6f18, 0xfb2df76f, 0xcfca5ff6, 0xdc68c781, 0x7b5fdfff, 0x68fd4788, 0x5c1aef11, 0x4fb87766, 0x35d5be23, 0x26772654, 0x12908ecd, 0x13216ba, 0xe64b1c47, 0xf5e98430, 0xc10e2ca9, 0xd2acb4de, 0xa8c17d9b, 0xbb63e5ec, 0x8f844d75, 0x9c26d502, 0x449a2e7e, 0x5738b609, 0x63df1e90, 0x707d86e7, 0xa104fa2, 0x19b2d7d5, 0x2d557f4c, 0x3ef7e73b, 0xd98eedc6, 0xca2c75b1, 0xfecbdd28, 0xed69455f, 0x97048c1a, 0x84a6146d, 0xb041bcf4, 0xa3e32483 }, { 0x0, 0xa541927e, 0x4f6f520d, 0xea2ec073, 0x9edea41a, 0x3b9f3664, 0xd1b1f617, 0x74f06469, 0x38513ec5, 0x9d10acbb, 0x773e6cc8, 0xd27ffeb6, 0xa68f9adf, 0x3ce08a1, 0xe9e0c8d2, 0x4ca15aac, 0x70a27d8a, 0xd5e3eff4, 0x3fcd2f87, 0x9a8cbdf9, 0xee7cd990, 0x4b3d4bee, 0xa1138b9d, 0x45219e3, 0x48f3434f, 0xedb2d131, 0x79c1142, 0xa2dd833c, 0xd62de755, 0x736c752b, 0x9942b558, 0x3c032726, 0xe144fb14, 0x4405696a, 0xae2ba919, 0xb6a3b67, 0x7f9a5f0e, 0xdadbcd70, 0x30f50d03, 0x95b49f7d, 0xd915c5d1, 0x7c5457af, 0x967a97dc, 0x333b05a2, 0x47cb61cb, 0xe28af3b5, 0x8a433c6, 0xade5a1b8, 0x91e6869e, 0x34a714e0, 0xde89d493, 0x7bc846ed, 0xf382284, 0xaa79b0fa, 0x40577089, 0xe516e2f7, 0xa9b7b85b, 0xcf62a25, 0xe6d8ea56, 0x43997828, 0x37691c41, 0x92288e3f, 0x78064e4c, 0xdd47dc32, 0xc76580d9, 0x622412a7, 0x880ad2d4, 0x2d4b40aa, 0x59bb24c3, 0xfcfab6bd, 0x16d476ce, 0xb395e4b0, 0xff34be1c, 0x5a752c62, 0xb05bec11, 0x151a7e6f, 0x61ea1a06, 0xc4ab8878, 0x2e85480b, 0x8bc4da75, 0xb7c7fd53, 0x12866f2d, 0xf8a8af5e, 0x5de93d20, 0x29195949, 0x8c58cb37, 0x66760b44, 0xc337993a, 0x8f96c396, 0x2ad751e8, 0xc0f9919b, 0x65b803e5, 0x1148678c, 0xb409f5f2, 0x5e273581, 0xfb66a7ff, 0x26217bcd, 0x8360e9b3, 0x694e29c0, 0xcc0fbbbe, 0xb8ffdfd7, 0x1dbe4da9, 0xf7908dda, 0x52d11fa4, 0x1e704508, 0xbb31d776, 0x511f1705, 0xf45e857b, 0x80aee112, 0x25ef736c, 0xcfc1b31f, 0x6a802161, 0x56830647, 0xf3c29439, 0x19ec544a, 0xbcadc634, 0xc85da25d, 0x6d1c3023, 0x8732f050, 0x2273622e, 0x6ed23882, 0xcb93aafc, 0x21bd6a8f, 0x84fcf8f1, 0xf00c9c98, 0x554d0ee6, 0xbf63ce95, 0x1a225ceb, 0x8b277743, 0x2e66e53d, 0xc448254e, 0x6109b730, 0x15f9d359, 0xb0b84127, 0x5a968154, 0xffd7132a, 0xb3764986, 0x1637dbf8, 0xfc191b8b, 0x595889f5, 0x2da8ed9c, 0x88e97fe2, 0x62c7bf91, 0xc7862def, 0xfb850ac9, 0x5ec498b7, 0xb4ea58c4, 0x11abcaba, 0x655baed3, 0xc01a3cad, 0x2a34fcde, 0x8f756ea0, 0xc3d4340c, 0x6695a672, 0x8cbb6601, 0x29faf47f, 0x5d0a9016, 0xf84b0268, 0x1265c21b, 0xb7245065, 0x6a638c57, 0xcf221e29, 0x250cde5a, 0x804d4c24, 0xf4bd284d, 0x51fcba33, 0xbbd27a40, 0x1e93e83e, 0x5232b292, 0xf77320ec, 0x1d5de09f, 0xb81c72e1, 0xccec1688, 0x69ad84f6, 0x83834485, 0x26c2d6fb, 0x1ac1f1dd, 0xbf8063a3, 0x55aea3d0, 0xf0ef31ae, 0x841f55c7, 0x215ec7b9, 0xcb7007ca, 0x6e3195b4, 0x2290cf18, 0x87d15d66, 0x6dff9d15, 0xc8be0f6b, 0xbc4e6b02, 0x190ff97c, 0xf321390f, 0x5660ab71, 0x4c42f79a, 0xe90365e4, 0x32da597, 0xa66c37e9, 0xd29c5380, 0x77ddc1fe, 0x9df3018d, 0x38b293f3, 0x7413c95f, 0xd1525b21, 0x3b7c9b52, 0x9e3d092c, 0xeacd6d45, 0x4f8cff3b, 0xa5a23f48, 0xe3ad36, 0x3ce08a10, 0x99a1186e, 0x738fd81d, 0xd6ce4a63, 0xa23e2e0a, 0x77fbc74, 0xed517c07, 0x4810ee79, 0x4b1b4d5, 0xa1f026ab, 0x4bdee6d8, 0xee9f74a6, 0x9a6f10cf, 0x3f2e82b1, 0xd50042c2, 0x7041d0bc, 0xad060c8e, 0x8479ef0, 0xe2695e83, 0x4728ccfd, 0x33d8a894, 0x96993aea, 0x7cb7fa99, 0xd9f668e7, 0x9557324b, 0x3016a035, 0xda386046, 0x7f79f238, 0xb899651, 0xaec8042f, 0x44e6c45c, 0xe1a75622, 0xdda47104, 0x78e5e37a, 0x92cb2309, 0x378ab177, 0x437ad51e, 0xe63b4760, 0xc158713, 0xa954156d, 0xe5f54fc1, 0x40b4ddbf, 0xaa9a1dcc, 0xfdb8fb2, 0x7b2bebdb, 0xde6a79a5, 0x3444b9d6, 0x91052ba8 }, { 0x0, 0xdd45aab8, 0xbf672381, 0x62228939, 0x7b2231f3, 0xa6679b4b, 0xc4451272, 0x1900b8ca, 0xf64463e6, 0x2b01c95e, 0x49234067, 0x9466eadf, 0x8d665215, 0x5023f8ad, 0x32017194, 0xef44db2c, 0xe964b13d, 0x34211b85, 0x560392bc, 0x8b463804, 0x924680ce, 0x4f032a76, 0x2d21a34f, 0xf06409f7, 0x1f20d2db, 0xc2657863, 0xa047f15a, 0x7d025be2, 0x6402e328, 0xb9474990, 0xdb65c0a9, 0x6206a11, 0xd725148b, 0xa60be33, 0x6842370a, 0xb5079db2, 0xac072578, 0x71428fc0, 0x136006f9, 0xce25ac41, 0x2161776d, 0xfc24ddd5, 0x9e0654ec, 0x4343fe54, 0x5a43469e, 0x8706ec26, 0xe524651f, 0x3861cfa7, 0x3e41a5b6, 0xe3040f0e, 0x81268637, 0x5c632c8f, 0x45639445, 0x98263efd, 0xfa04b7c4, 0x27411d7c, 0xc805c650, 0x15406ce8, 0x7762e5d1, 0xaa274f69, 0xb327f7a3, 0x6e625d1b, 0xc40d422, 0xd1057e9a, 0xaba65fe7, 0x76e3f55f, 0x14c17c66, 0xc984d6de, 0xd0846e14, 0xdc1c4ac, 0x6fe34d95, 0xb2a6e72d, 0x5de23c01, 0x80a796b9, 0xe2851f80, 0x3fc0b538, 0x26c00df2, 0xfb85a74a, 0x99a72e73, 0x44e284cb, 0x42c2eeda, 0x9f874462, 0xfda5cd5b, 0x20e067e3, 0x39e0df29, 0xe4a57591, 0x8687fca8, 0x5bc25610, 0xb4868d3c, 0x69c32784, 0xbe1aebd, 0xd6a40405, 0xcfa4bccf, 0x12e11677, 0x70c39f4e, 0xad8635f6, 0x7c834b6c, 0xa1c6e1d4, 0xc3e468ed, 0x1ea1c255, 0x7a17a9f, 0xdae4d027, 0xb8c6591e, 0x6583f3a6, 0x8ac7288a, 0x57828232, 0x35a00b0b, 0xe8e5a1b3, 0xf1e51979, 0x2ca0b3c1, 0x4e823af8, 0x93c79040, 0x95e7fa51, 0x48a250e9, 0x2a80d9d0, 0xf7c57368, 0xeec5cba2, 0x3380611a, 0x51a2e823, 0x8ce7429b, 0x63a399b7, 0xbee6330f, 0xdcc4ba36, 0x181108e, 0x1881a844, 0xc5c402fc, 0xa7e68bc5, 0x7aa3217d, 0x52a0c93f, 0x8fe56387, 0xedc7eabe, 0x30824006, 0x2982f8cc, 0xf4c75274, 0x96e5db4d, 0x4ba071f5, 0xa4e4aad9, 0x79a10061, 0x1b838958, 0xc6c623e0, 0xdfc69b2a, 0x2833192, 0x60a1b8ab, 0xbde41213, 0xbbc47802, 0x6681d2ba, 0x4a35b83, 0xd9e6f13b, 0xc0e649f1, 0x1da3e349, 0x7f816a70, 0xa2c4c0c8, 0x4d801be4, 0x90c5b15c, 0xf2e73865, 0x2fa292dd, 0x36a22a17, 0xebe780af, 0x89c50996, 0x5480a32e, 0x8585ddb4, 0x58c0770c, 0x3ae2fe35, 0xe7a7548d, 0xfea7ec47, 0x23e246ff, 0x41c0cfc6, 0x9c85657e, 0x73c1be52, 0xae8414ea, 0xcca69dd3, 0x11e3376b, 0x8e38fa1, 0xd5a62519, 0xb784ac20, 0x6ac10698, 0x6ce16c89, 0xb1a4c631, 0xd3864f08, 0xec3e5b0, 0x17c35d7a, 0xca86f7c2, 0xa8a47efb, 0x75e1d443, 0x9aa50f6f, 0x47e0a5d7, 0x25c22cee, 0xf8878656, 0xe1873e9c, 0x3cc29424, 0x5ee01d1d, 0x83a5b7a5, 0xf90696d8, 0x24433c60, 0x4661b559, 0x9b241fe1, 0x8224a72b, 0x5f610d93, 0x3d4384aa, 0xe0062e12, 0xf42f53e, 0xd2075f86, 0xb025d6bf, 0x6d607c07, 0x7460c4cd, 0xa9256e75, 0xcb07e74c, 0x16424df4, 0x106227e5, 0xcd278d5d, 0xaf050464, 0x7240aedc, 0x6b401616, 0xb605bcae, 0xd4273597, 0x9629f2f, 0xe6264403, 0x3b63eebb, 0x59416782, 0x8404cd3a, 0x9d0475f0, 0x4041df48, 0x22635671, 0xff26fcc9, 0x2e238253, 0xf36628eb, 0x9144a1d2, 0x4c010b6a, 0x5501b3a0, 0x88441918, 0xea669021, 0x37233a99, 0xd867e1b5, 0x5224b0d, 0x6700c234, 0xba45688c, 0xa345d046, 0x7e007afe, 0x1c22f3c7, 0xc167597f, 0xc747336e, 0x1a0299d6, 0x782010ef, 0xa565ba57, 0xbc65029d, 0x6120a825, 0x302211c, 0xde478ba4, 0x31035088, 0xec46fa30, 0x8e647309, 0x5321d9b1, 0x4a21617b, 0x9764cbc3, 0xf54642fa, 0x2803e842 } #endif }; /* * Input : * buff : Pointer to the input buffer whose checksum needs to be computed. * sgmnt_addrs : Segment address * bufflen : Buffer size in bytes * * Returns: * Computed checksum. */ uint4 jnl_get_checksum(uint4 *buff, sgmnt_addrs *csa, int bufflen) { uint4 *top, *blk_base, *blk_top, blen; # ifdef GTM_CRYPT DEBUG_ONLY( sm_uc_ptr_t orig_buff = NULL; ) if (NULL != csa && (csa->hdr->is_encrypted)) { DBG_ENSURE_PTR_IS_VALID_GLOBUFF(csa, csa->hdr, (sm_uc_ptr_t)buff); DEBUG_ONLY(orig_buff = (unsigned char *)buff;) buff = (uint4 *)GDS_ANY_ENCRYPTGLOBUF(buff, csa); DBG_ENSURE_PTR_IS_VALID_ENCTWINGLOBUFF(csa, csa->hdr, (sm_uc_ptr_t)buff); } # endif return (compute_checksum(INIT_CHECKSUM_SEED, buff, bufflen)); } /* * Input : * buff : Pointer to the input buffer whose checksum needs to be computed. * bufflen : Buffer size in bytes * * Returns: * Computed checksum. * * Algorithm: * The checksum is calculated using slice-by-4 checksum calculation algorithm */ uint4 compute_checksum(uint4 init_checksum, uint4 *buff, int bufflen) { uint4 checksum = init_checksum; char *byte; int word_cnt, i, rem_bytes; /* calculate checksum one byte at a time so that subsequent data read will be at addresses aligned to multiple of 4*/ #ifdef GTM64 for (byte = (char *)buff; ((gtm_uint8)byte & SIZEOF(gtm_uint8)) != 0; byte++, bufflen--) #else for (byte = (char *)buff; ((uint4)byte & SIZEOF(uint4)) != 0; byte++, bufflen--) #endif { #ifdef BIGENDIAN checksum = (checksum << BITS_PER_UCHAR) ^ csum_table[0][((checksum >> (3 * BITS_PER_UCHAR)) ^ *byte) & BYTEMASK]; #else checksum = (checksum >> BITS_PER_UCHAR) ^ csum_table[0][(checksum ^ *byte) & BYTEMASK]; #endif } word_cnt = bufflen / SIZEOF(uint4); rem_bytes = bufflen & (int)(SIZEOF(uint4) - 1); /* Equivalent to bufflen % SIZEOF(uint4) */ for(i = 0; i < word_cnt; i++) { checksum = checksum ^ *(uint4 *)byte; byte = byte + SIZEOF(uint4); #ifdef BIGENDIAN checksum = csum_table[LOBYTE + 0][checksum & BYTEMASK] ^ csum_table[LOBYTE + 1][(checksum >> (1 * BITS_PER_UCHAR)) & BYTEMASK] ^ csum_table[LOBYTE + 2][(checksum >> (2 * BITS_PER_UCHAR)) & BYTEMASK] ^ csum_table[LOBYTE + 3][(checksum >> (3 * BITS_PER_UCHAR)) & BYTEMASK]; #else checksum = csum_table[HIBYTE - 0][checksum & BYTEMASK] ^ csum_table[HIBYTE - 1][(checksum >> (1 * BITS_PER_UCHAR)) & BYTEMASK] ^ csum_table[HIBYTE - 2][(checksum >> (2 * BITS_PER_UCHAR)) & BYTEMASK] ^ csum_table[HIBYTE - 3][(checksum >> (3 * BITS_PER_UCHAR)) & BYTEMASK]; #endif } for(i = 0; i < rem_bytes; i++, byte++) { #ifdef BIGENDIAN checksum = (checksum << BITS_PER_UCHAR) ^ csum_table[0][((checksum >> (3 * BITS_PER_UCHAR)) ^ *byte) & BYTEMASK]; #else checksum = (checksum >> BITS_PER_UCHAR) ^ csum_table[0][(checksum ^ *byte) & BYTEMASK]; #endif } return (checksum ? checksum : INIT_CHECKSUM_SEED); } fis-gtm-V6.0-003/sr_port/jnl_get_checksum.h0000644000032200000250000001515112201176160017506 0ustar librarygtc/**************************************************************** * * * Copyright 2005, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __JNL_GET_CHECKSUM_H_ #define __JNL_GET_CHECKSUM_H_ #define INIT_CHECKSUM_SEED 0xFFFFFFFF #define SLICE_BY 4 #define TABLE_SIZE 256 #define BYTEMASK 0xFF GBLREF uint4 csum_table[SLICE_BY][TABLE_SIZE]; #ifdef BIGENDIAN #define LOBYTE 0 #define ADJUST_CHECKSUM(cursum, num4, newsum) \ { \ uint4 tmpsum = csum_table[LOBYTE + 0][(cursum ^ num4) & BYTEMASK] ^ \ csum_table[LOBYTE + 1][((cursum ^ num4) >> (1 * BITS_PER_UCHAR)) & BYTEMASK] ^ \ csum_table[LOBYTE + 2][((cursum ^ num4) >> (2 * BITS_PER_UCHAR)) & BYTEMASK] ^ \ csum_table[LOBYTE + 3][((cursum ^ num4) >> (3 * BITS_PER_UCHAR)) & BYTEMASK]; \ newsum = tmpsum ? tmpsum : INIT_CHECKSUM_SEED; \ } #else #define HIBYTE 3 #define ADJUST_CHECKSUM(cursum, num4, newsum) \ { \ uint4 tmpsum = csum_table[HIBYTE - 0][(cursum ^ num4) & BYTEMASK] ^ \ csum_table[HIBYTE - 1][((cursum ^ num4) >> (1 * BITS_PER_UCHAR)) & BYTEMASK] ^ \ csum_table[HIBYTE - 2][((cursum ^ num4) >> (2 * BITS_PER_UCHAR)) & BYTEMASK] ^ \ csum_table[HIBYTE - 3][((cursum ^ num4) >> (3 * BITS_PER_UCHAR)) & BYTEMASK]; \ newsum = tmpsum ? tmpsum : INIT_CHECKSUM_SEED; \ } #endif #define ADJUST_CHECKSUM_TN(cursum, tn, newsum) \ { \ uint4 tmpsum_tn; \ ADJUST_CHECKSUM(cursum, *(uint4 *)tn, tmpsum_tn); \ ADJUST_CHECKSUM(tmpsum_tn, *(uint4 *)((char *)tn+SIZEOF(uint4)), newsum); \ } #define COMPUTE_COMMON_CHECKSUM(common_cksum, prefix) \ { \ ADJUST_CHECKSUM_TN(INIT_CHECKSUM_SEED, &(prefix.tn), common_cksum); \ ADJUST_CHECKSUM(common_cksum, prefix.pini_addr, common_cksum); \ ADJUST_CHECKSUM(common_cksum, prefix.time, common_cksum); \ } #define COMPUTE_PBLK_CHECKSUM(blk_checksum, pblk_rec, common_cksum, jrec_checksum) \ { \ ADJUST_CHECKSUM(blk_checksum, (pblk_rec)->prefix.jrec_type, jrec_checksum); \ ADJUST_CHECKSUM(jrec_checksum, (pblk_rec)->blknum, jrec_checksum); \ ADJUST_CHECKSUM(jrec_checksum, (pblk_rec)->bsiz, jrec_checksum); \ ADJUST_CHECKSUM(jrec_checksum, (pblk_rec)->ondsk_blkver, jrec_checksum); \ ADJUST_CHECKSUM(jrec_checksum, common_cksum, jrec_checksum); \ } #define COMPUTE_AIMG_CHECKSUM(blk_checksum, aimg_rec, common_cksum, jrec_checksum) \ COMPUTE_PBLK_CHECKSUM(blk_checksum, aimg_rec, common_cksum, jrec_checksum); #define COMPUTE_LOGICAL_REC_CHECKSUM(jfb_checksum, jrec, common_cksum, jrec_checksum) \ { \ ADJUST_CHECKSUM(jfb_checksum, (jrec)->prefix.jrec_type, jrec_checksum); \ ADJUST_CHECKSUM(jrec_checksum, (jrec)->update_num, jrec_checksum); \ ADJUST_CHECKSUM(jrec_checksum, (jrec)->token_seq.token, jrec_checksum); \ ADJUST_CHECKSUM(jrec_checksum, (jrec)->strm_seqno, jrec_checksum); \ ADJUST_CHECKSUM(jrec_checksum, (jrec)->num_participants, jrec_checksum); \ ADJUST_CHECKSUM(jrec_checksum, common_cksum, jrec_checksum); \ } /* This macro is to be used whenever we are computing the checksum of a block that has been acquired. */ #define JNL_GET_CHECKSUM_ACQUIRED_BLK(cse, csd, csa, old_blk, bsize) \ { \ cache_rec_ptr_t cr; \ boolean_t cr_is_null; \ \ GBLREF uint4 dollar_tlevel; \ \ /* Record current database tn before computing checksum of acquired block. This is used \ * later by the commit logic to determine if the block contents have changed (and hence \ * if recomputation of checksum is necessary). For BG, we have two-phase commit where \ * phase2 is done outside of crit. So it is possible that we note down the current database \ * tn and then compute checksums outside of crit and then get crit and yet in the validation \ * logic find the block header tn is LESSER than the noted dbtn (even though the block \ * contents changed after the noted dbtn). This will cause us to falsely validate this block \ * as not needing checksum recomputation. To ensure the checksum is recomputed inside crit, \ * we note down a tn of 0 in case the block is locked for update (cr->in_tend is non-zero). \ */ \ assert((gds_t_acquired == cse->mode) || (gds_t_create == cse->mode) \ || (gds_t_recycled2free == cse->mode)); \ assert(cse->old_block == (sm_uc_ptr_t)(old_blk)); \ assert((bsize) <= csd->blk_size); \ /* Since this macro is invoked only in case of before-image journaling and since MM does not \ * support before-image journaling, we can safely assert that BG is the only access method. \ */ \ assert(dba_bg == csd->acc_meth); \ /* In rare cases cse->cr can be NULL even though this block is an acquired block. This is \ * possible if we are in TP and this block was part of the tree in the initial phase of the \ * transaction but was marked free (by another process concurrently) in the later phase of \ * the same TP transaction. But this case is a sureshot restart situation so be safe and \ * ensure recomputation happens inside of crit just in case we dont restart. Also add asserts \ * (using donot_commit variable) to ensure we do restart this transaction. \ */ \ cr = cse->cr; \ cr_is_null = (NULL == cr); \ assert(!cr_is_null || dollar_tlevel); \ DEBUG_ONLY(if (cr_is_null) TREF(donot_commit) |= DONOTCOMMIT_JNLGETCHECKSUM_NULL_CR;) \ cse->tn = ((cr_is_null || cr->in_tend) ? 0 : csd->trans_hist.curr_tn); \ /* If cr is NULL, it is a restartable situation. So dont waste time computing checksums. Also \ * if the db is encrypted, we cannot get at the encryption global buffer (jnl_get_checksum \ * requires this) since we dont even have a regular global buffer corresponding to this block \ * so there is no way jnl_get_checksum can proceed in that case. So it is actually necessary \ * to avoid computing checksums if cr is NULL. \ */ \ cse->blk_checksum = !cr_is_null ? jnl_get_checksum((uint4 *)(old_blk), csa, (bsize)) : 0; \ } uint4 jnl_get_checksum(uint4 *buff, sgmnt_addrs *csa, int bufflen); uint4 compute_checksum(uint4 init_sum, uint4 *buff, int bufflen); #endif fis-gtm-V6.0-003/sr_port/jnl_put_jrt_pfin.c0000644000032200000250000000315612201176160017545 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_time.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "jnl_write.h" #include "jnl_get_checksum.h" GBLREF jnl_gbls_t jgbl; void jnl_put_jrt_pfin(sgmnt_addrs *csa) { struct_jrec_pfin pfin_record; jnl_private_control *jpc; assert(csa->now_crit); jpc = csa->jnl; assert(0 != jpc->pini_addr); pfin_record.prefix.jrec_type = JRT_PFIN; pfin_record.prefix.forwptr = pfin_record.suffix.backptr = PFIN_RECLEN; pfin_record.suffix.suffix_code = JNL_REC_SUFFIX_CODE; pfin_record.prefix.pini_addr = (0 == jpc->pini_addr) ? JNL_HDR_LEN : jpc->pini_addr; pfin_record.prefix.tn = csa->ti->curr_tn; /* At this point jgbl.gbl_jrec_time should be set by the caller */ assert(jgbl.gbl_jrec_time); pfin_record.prefix.time = jgbl.gbl_jrec_time; pfin_record.prefix.checksum = INIT_CHECKSUM_SEED; pfin_record.filler = 0; pfin_record.prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&pfin_record, SIZEOF(struct_jrec_pfin)); jnl_write(jpc, JRT_PFIN, (jnl_record *)&pfin_record, NULL, NULL); } fis-gtm-V6.0-003/sr_port/jnl_put_jrt_pini.c0000644000032200000250000000743612201176160017555 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_time.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "jnl_write.h" #include "gtmimagename.h" #include "jnl_get_checksum.h" #include "buddy_list.h" /* needed for muprec.h */ #include "hashtab_int4.h" /* needed for muprec.h */ #include "hashtab_int8.h" /* needed for muprec.h */ #include "hashtab_mname.h" /* needed for muprec.h */ #include "muprec.h" GBLREF jnl_fence_control jnl_fence_ctl; GBLREF jnl_process_vector *prc_vec; GBLREF jnl_process_vector *originator_prc_vec; GBLREF jnl_gbls_t jgbl; void jnl_put_jrt_pini(sgmnt_addrs *csa) { struct_jrec_pini pini_record; jnl_private_control *jpc; jnl_buffer_ptr_t jbp; struct pini_list *mur_plst; assert(csa->now_crit); jpc = csa->jnl; jbp = jpc->jnl_buff; assert(prc_vec); assert((csa->ti->early_tn == csa->ti->curr_tn) || (csa->ti->early_tn == csa->ti->curr_tn + 1)); pini_record.prefix.jrec_type = JRT_PINI; pini_record.prefix.forwptr = pini_record.suffix.backptr = PINI_RECLEN; pini_record.suffix.suffix_code = JNL_REC_SUFFIX_CODE; pini_record.prefix.pini_addr = jbp->freeaddr; /* in case an ALIGN record is written before the PINI record in jnl_write(), pini_addr above is updated appropriately. */ pini_record.prefix.tn = csa->ti->curr_tn; /* At this point jgbl.gbl_jrec_time should be set by the caller */ assert(jgbl.gbl_jrec_time); pini_record.prefix.time = jgbl.gbl_jrec_time; JNL_WHOLE_FROM_SHORT_TIME(prc_vec->jpv_time, jgbl.gbl_jrec_time); pini_record.prefix.checksum = INIT_CHECKSUM_SEED; /* Note that only pini_record.prefix.time is considered in mupip journal command processing. * prc_vec->jpv_time is for accounting purpose only. Usually it is kind of redundant too. */ if (!jgbl.forw_phase_recovery) { assert(NULL == jgbl.mur_pini_addr_reset_fnptr); assert(NULL == csa->rctl); mur_plst = NULL; if (IS_GTCM_GNP_SERVER_IMAGE && (NULL != originator_prc_vec)) { memcpy((unsigned char*)&pini_record.process_vector[ORIG_JPV], (unsigned char*)originator_prc_vec, SIZEOF(jnl_process_vector)); } else memset((unsigned char*)&pini_record.process_vector[ORIG_JPV], 0, SIZEOF(jnl_process_vector)); } else { assert(NULL != csa->rctl); mur_plst = csa->rctl->mur_plst; if (NULL != jgbl.mur_pini_addr_reset_fnptr) { memcpy((unsigned char*)&pini_record.process_vector[ORIG_JPV], (unsigned char *)&mur_plst->origjpv, SIZEOF(jnl_process_vector)); } else { /* gdsfilext done during "mur_block_count_correct" */ assert(NULL == mur_plst); memset((unsigned char*)&pini_record.process_vector[ORIG_JPV], 0, SIZEOF(jnl_process_vector)); } } memcpy((unsigned char*)&pini_record.process_vector[CURR_JPV], (unsigned char*)prc_vec, SIZEOF(jnl_process_vector)); pini_record.filler = 0; pini_record.prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&pini_record, SIZEOF(struct_jrec_pini)); jnl_write(jpc, JRT_PINI, (jnl_record *)&pini_record, NULL, NULL); /* Note : jpc->pini_addr should not be updated until PINI record is written [C9D08-002376] */ jpc->pini_addr = jbp->freeaddr - PINI_RECLEN; assert(jgbl.forw_phase_recovery || (NULL == mur_plst)); if (NULL != mur_plst) mur_plst->new_pini_addr = jpc->pini_addr;/* note down for future forward play logical record processing */ } fis-gtm-V6.0-003/sr_port/jnl_rec_table.h0000644000032200000250000001362012201176160016764 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* New entries should be added at the end to maintain backward compatibility with previous journal files */ /* Note: This is an exception where we have 132+ characters in a line. It is needed so that from a * particular number we can find record type. */ /* JNL_TABLE_ENTRY (rectype, extract_rtn, label, update, fixed_size, is_replicated) */ JNL_TABLE_ENTRY (JRT_BAD, NULL, "*BAD* ", NA, FALSE, FALSE) /* 0: Catch-all for invalid record types (must be first) */ JNL_TABLE_ENTRY (JRT_PINI, mur_extract_pini, "PINI ", NA, TRUE, FALSE) /* 1: Process initialization */ JNL_TABLE_ENTRY (JRT_PFIN, mur_extract_pfin, "PFIN ", NA, TRUE, FALSE) /* 2: Process termination */ JNL_TABLE_ENTRY (JRT_ZTCOM, mur_extract_tcom, "ZTCOM ", ZTCOMREC, TRUE, FALSE) /* 3: End of "fenced" transaction */ JNL_TABLE_ENTRY (JRT_KILL, mur_extract_set, "KILL ", KILLREC, FALSE, TRUE) /* 4: After-image logical journal transaction */ JNL_TABLE_ENTRY (JRT_FKILL, mur_extract_set, "FKILL ", KILLREC|FUPDREC, FALSE, FALSE) /* 5: Like KILL, but the first in a "fenced" transaction */ JNL_TABLE_ENTRY (JRT_GKILL, mur_extract_set, "GKILL ", KILLREC|GUPDREC, FALSE, FALSE) /* 6: Like FKILL, but not the first */ JNL_TABLE_ENTRY (JRT_SET, mur_extract_set, "SET ", SETREC, FALSE, TRUE) /* 7: After-image logical journal transaction */ JNL_TABLE_ENTRY (JRT_FSET, mur_extract_set, "FSET ", SETREC|FUPDREC, FALSE, FALSE) /* 8: Like SET, but the first in a "fenced" transaction */ JNL_TABLE_ENTRY (JRT_GSET, mur_extract_set, "GSET ", SETREC|GUPDREC, FALSE, FALSE) /* 9: Like FSET, but not the first */ JNL_TABLE_ENTRY (JRT_PBLK, mur_extract_blk, "PBLK ", NA, FALSE, FALSE) /* 10: Before-image physical journal transaction */ JNL_TABLE_ENTRY (JRT_EPOCH, mur_extract_epoch, "EPOCH ", NA, TRUE, FALSE) /* 11: A "new epoch" */ JNL_TABLE_ENTRY (JRT_EOF, mur_extract_eof, "EOF ", NA, TRUE, FALSE) /* 12: End of file */ JNL_TABLE_ENTRY (JRT_TKILL, mur_extract_set, "TKILL ", KILLREC|TUPDREC, FALSE, TRUE) /* 13: Like KILL, but the first in a TP transaction */ JNL_TABLE_ENTRY (JRT_UKILL, mur_extract_set, "UKILL ", KILLREC|UUPDREC, FALSE, TRUE) /* 14: Like TKILL, but not the first */ JNL_TABLE_ENTRY (JRT_TSET, mur_extract_set, "TSET ", SETREC|TUPDREC, FALSE, TRUE) /* 15: Like SET, but the first in a TP transaction */ JNL_TABLE_ENTRY (JRT_USET, mur_extract_set, "USET ", SETREC|UUPDREC, FALSE, TRUE) /* 16: Like TSET, but not the first */ JNL_TABLE_ENTRY (JRT_TCOM, mur_extract_tcom, "TCOM ", TCOMREC, TRUE, TRUE) /* 17: End of TP transaction */ JNL_TABLE_ENTRY (JRT_ALIGN, mur_extract_align, "ALIGN ", NA, FALSE, FALSE) /* 18: Align record */ JNL_TABLE_ENTRY (JRT_NULL, mur_extract_null, "NULL ", NA, TRUE, TRUE) /* 19: Null record */ JNL_TABLE_ENTRY (JRT_ZKILL, mur_extract_set, "ZKILL ", ZKILLREC, FALSE, TRUE) /* 20: After-image logical journal transaction */ JNL_TABLE_ENTRY (JRT_FZKILL, mur_extract_set, "FZKILL ", ZKILLREC|FUPDREC, FALSE, FALSE) /* 21: Like ZKILL, but the first in a "fenced" transaction */ JNL_TABLE_ENTRY (JRT_GZKILL, mur_extract_set, "GZKILL ", ZKILLREC|GUPDREC, FALSE, FALSE) /* 22: Like FZKILL, but not the first */ JNL_TABLE_ENTRY (JRT_TZKILL, mur_extract_set, "TZKILL ", ZKILLREC|TUPDREC, FALSE, TRUE) /* 23: Like ZKILL, but the first in a TP transaction */ JNL_TABLE_ENTRY (JRT_UZKILL, mur_extract_set, "UZKILL ", ZKILLREC|UUPDREC, FALSE, TRUE) /* 24: Like TZKILL, but not the first */ JNL_TABLE_ENTRY (JRT_INCTN, mur_extract_inctn, "INCTN ", NA, TRUE, FALSE) /* 25: Increment curr_tn only, no logical update */ JNL_TABLE_ENTRY (JRT_AIMG, mur_extract_blk, "AIMG ", NA, FALSE, FALSE) /* 26: After-image physical journal transaction */ JNL_TABLE_ENTRY (JRT_TRIPLE, NULL, "TRIPLE ", NA, TRUE, TRUE) /* 27: A REPL_OLD_TRIPLE message minus the 8-byte message * header ("type" and "len"). Only used in the * replication pipe. Never part of a journal file. */ JNL_TABLE_ENTRY (JRT_TZTWORM, mur_extract_set, "TZTWORM", ZTWORMREC|TUPDREC, FALSE, TRUE) /* 28: If $ZTWORMHOLE is first record in TP */ JNL_TABLE_ENTRY (JRT_UZTWORM, mur_extract_set, "UZTWORM", ZTWORMREC|UUPDREC, FALSE, TRUE) /* 29: Like TZTWORM but not the first record in TP */ JNL_TABLE_ENTRY (JRT_TZTRIG, mur_extract_set, "TZTRIG ", ZTRIGREC|TUPDREC, FALSE, TRUE) /* 30: If ZTRIGGER is first record in TP */ JNL_TABLE_ENTRY (JRT_UZTRIG, mur_extract_set, "UZTRIG ", ZTRIGREC|UUPDREC, FALSE, TRUE) /* 31: Like TZTRIG but not the first record in TP */ JNL_TABLE_ENTRY (JRT_HISTREC, NULL, "HISTREC", NA, TRUE, TRUE) /* 32: A REPL_HISTREC message minus the 8-byte message * header ("type" and "len"). Only used in the * replication pipe. Never part of a journal file. */ JNL_TABLE_ENTRY (JRT_TRUNC, mur_extract_trunc, "TRUNC ", NA, TRUE, FALSE) /* 33: Record DB file truncate details */ fis-gtm-V6.0-003/sr_port/jnl_send_oper.c0000644000032200000250000000706312201176160017021 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "iosp.h" #include "jnl.h" #include "error.h" #include "send_msg.h" #include "caller_id.h" #include "wbox_test_init.h" #define ENOSPC_LOGGING_PERIOD 100 /* every 100th ENOSPC error is logged to avoid flooding the operator log */ GBLREF bool caller_id_flag; GBLREF uint4 process_id; void jnl_send_oper(jnl_private_control *jpc, uint4 status) { sgmnt_addrs *csa; sgmnt_data_ptr_t csd; jnl_buffer_ptr_t jb; uint4 now_writer, fsync_pid; int4 io_in_prog, fsync_in_prog; boolean_t ok_to_log; /* TRUE except when we avoid flooding operator log due to ENOSPC error */ error_def(ERR_CALLERID); error_def(ERR_JNLBUFINFO); error_def(ERR_JNLPVTINFO); error_def(ERR_JNLSENDOPER); switch(jpc->region->dyn.addr->acc_meth) { case dba_mm: case dba_bg: csa = &FILE_INFO(jpc->region)->s_addrs; break; default: GTMASSERT; } csd = csa->hdr; jb = jpc->jnl_buff; UNIX_ONLY(assert((ENOSPC != jpc->status) || jb->enospc_errcnt || WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC))); UNIX_ONLY(assert((SS_NORMAL == jpc->status) || (ENOSPC == jpc->status) || !jb->enospc_errcnt)); VMS_ONLY(assert(!jb->enospc_errcnt)); /* currently not updated in VMS, so should be 0 */ ok_to_log = (jb->enospc_errcnt ? (1 == (jb->enospc_errcnt % ENOSPC_LOGGING_PERIOD)) : TRUE); caller_id_flag = FALSE; if (ok_to_log) { SEND_CALLERID("jnl_send_oper()"); if (0 != status) { if (SS_NORMAL != jpc->status) { if (SS_NORMAL != jpc->status2) { send_msg(VARLSTCNT(14) ERR_JNLSENDOPER, 5, process_id, status, jpc->status, jpc->status2, jb->iosb.cond, status, 2, JNL_LEN_STR(csd), jpc->status, 0, jpc->status2); } else send_msg(VARLSTCNT(12) ERR_JNLSENDOPER, 5, process_id, status, jpc->status, jpc->status2, jb->iosb.cond, status, 2, JNL_LEN_STR(csd), jpc->status); } else send_msg(VARLSTCNT(11) ERR_JNLSENDOPER, 5, process_id, status, jpc->status, jpc->status2, jb->iosb.cond, status, 2, JNL_LEN_STR(csd)); } } jpc->status = SS_NORMAL; jpc->status2 = SS_NORMAL; UNIX_ONLY( io_in_prog = (jb->io_in_prog_latch.u.parts.latch_pid ? TRUE : FALSE); now_writer = jb->io_in_prog_latch.u.parts.latch_pid; ) VMS_ONLY( io_in_prog = jb->io_in_prog; now_writer = jb->now_writer; ) fsync_in_prog = jb->fsync_in_prog_latch.u.parts.latch_pid ? TRUE : FALSE; fsync_pid = jb->fsync_in_prog_latch.u.parts.latch_pid; /* note: the alignment of the parameters below is modelled on the alignment defined for JNLBUFINFO in merrors.msg */ if (ok_to_log) { send_msg(VARLSTCNT(18) ERR_JNLBUFINFO, 16, process_id, jb->dsk, jb->free, jb->bytcnt, io_in_prog, fsync_in_prog, jb->dskaddr, jb->freeaddr, jb->qiocnt, now_writer, fsync_pid, jb->filesize, jb->cycle, jb->errcnt, jb->wrtsize, jb->fsync_dskaddr); send_msg(VARLSTCNT(10) ERR_JNLPVTINFO, 8, process_id, jpc->cycle, jpc->fd_mismatch, jpc->channel, jpc->sync_io, jpc->pini_addr, jpc->qio_active, jpc->old_channel); } caller_id_flag = TRUE; } fis-gtm-V6.0-003/sr_port/jnl_typedef.h0000644000032200000250000000721112201176160016503 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef JNL_TYPEDEF_H_INCLUDED #define JNL_TYPEDEF_H_INCLUDED #define NA 0 #define SETREC 0x00000001 #define KILLREC 0x00000002 #define ZKILLREC 0x00000004 #define ZTWORMREC 0x00000008 #define ZTRIGREC 0x00000800 #define SET_KILL_ZKILL_MASK (SETREC | KILLREC | ZKILLREC) #define SET_KILL_ZKILL_ZTWORM_MASK (SETREC | KILLREC | ZKILLREC | ZTWORMREC) #define SET_KILL_ZKILL_ZTWORM_ZTRIG_MASK (SETREC | KILLREC | ZKILLREC | ZTWORMREC | ZTRIGREC) #define TUPDREC 0x00000010 #define UUPDREC 0x00000020 #define TCOMREC 0x00000040 #define TPREC_MASK (TUPDREC | UUPDREC | TCOMREC) #define FUPDREC 0x00000100 #define GUPDREC 0x00000200 #define ZTCOMREC 0x00000400 #define ZTPREC_MASK (FUPDREC | GUPDREC | ZTCOMREC) #define FENCE_MASK (TPREC_MASK | ZTPREC_MASK) /* the following LITREFs are needed by the below macros */ LITREF int jrt_update[JRT_RECTYPES]; LITREF boolean_t jrt_fixed_size[JRT_RECTYPES]; LITREF boolean_t jrt_is_replicated[JRT_RECTYPES]; #define IS_VALID_RECTYPES_RANGE(rectype) ((JRT_BAD < rectype) && (JRT_RECTYPES > rectype)) #define IS_REPLICATED(rectype) (jrt_is_replicated[rectype]) #define IS_FIXED_SIZE(rectype) (jrt_fixed_size[rectype]) #define IS_SET(rectype) (jrt_update[rectype] & SETREC) #define IS_KILL(rectype) (jrt_update[rectype] & KILLREC) #define IS_ZKILL(rectype) (jrt_update[rectype] & ZKILLREC) #define IS_ZTWORM(rectype) (jrt_update[rectype] & ZTWORMREC) #define IS_ZTRIG(rectype) (jrt_update[rectype] & ZTRIGREC) #define IS_KILL_ZKILL(rectype) (jrt_update[rectype] & (KILLREC | ZKILLREC)) #define IS_KILL_ZKILL_ZTRIG(rectype) (jrt_update[rectype] & (KILLREC | ZKILLREC | ZTRIGREC)) #define IS_SET_KILL_ZKILL_ZTRIG(rectype) (jrt_update[rectype] & (SET_KILL_ZKILL_MASK | ZTRIGREC)) #define IS_SET_KILL_ZKILL_ZTWORM(rectype) (jrt_update[rectype] & SET_KILL_ZKILL_ZTWORM_MASK) #define IS_SET_KILL_ZKILL_ZTRIG_ZTWORM(rectype) (jrt_update[rectype] & SET_KILL_ZKILL_ZTWORM_ZTRIG_MASK) #define IS_FENCED(rectype) (jrt_update[rectype] & FENCE_MASK) #define IS_TP(rectype) (jrt_update[rectype] & TPREC_MASK) #define IS_ZTP(rectype) (jrt_update[rectype] & ZTPREC_MASK) #define IS_COM(rectype) (jrt_update[rectype] & (TCOMREC | ZTCOMREC)) #define IS_FUPD(rectype) (jrt_update[rectype] & FUPDREC) #define IS_GUPD(rectype) (jrt_update[rectype] & GUPDREC) #define IS_TUPD(rectype) (jrt_update[rectype] & TUPDREC) #define IS_UUPD(rectype) (jrt_update[rectype] & UUPDREC) #define IS_FUPD_TUPD(rectype) (jrt_update[rectype] & (FUPDREC | TUPDREC)) #define IS_GUPD_UUPD(rectype) (jrt_update[rectype] & (GUPDREC | UUPDREC)) #ifdef GTM_TRIGGER # define IS_VALID_JRECTYPE(rectype) IS_VALID_RECTYPES_RANGE(rectype) #else /* On trigger non-supporting platforms, it is an error if a ZTWORM or ZTRIG rectype is seen. */ # define IS_VALID_JRECTYPE(rectype) (IS_VALID_RECTYPES_RANGE(rectype) && !IS_ZTWORM(rectype) && !IS_ZTRIG(rectype)) #endif #define GET_REC_FENCE_TYPE(rectype) (!IS_FENCED(rectype)) ? NOFENCE : (IS_TP(rectype)) ? TPFENCE : ZTPFENCE #define REC_HAS_TOKEN_SEQ(rectype) (IS_SET_KILL_ZKILL_ZTRIG_ZTWORM(rectype) || IS_COM(rectype) \ || (JRT_EPOCH == (rectype)) || (JRT_EOF == (rectype)) \ || (JRT_NULL == (rectype))) #endif /* JNL_TYPEDEF_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/jnl_wait.c0000644000032200000250000000220412201176160015777 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2003 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "gdsbt.h" #include "fileinfo.h" #include "gdsfhead.h" #include "filestruct.h" #include "iosp.h" #include "jnl.h" #include "is_file_identical.h" void jnl_wait(gd_region *reg) { jnl_private_control *jpc; sgmnt_addrs *csa; uint4 status; if ((NULL != reg) && (TRUE == reg->open)) { csa = &FILE_INFO(reg)->s_addrs; jpc = csa->jnl; if ((TRUE == JNL_ENABLED(csa->hdr)) && (NULL != jpc)) { /* wait on jnl writes for region */ status = jnl_write_attempt(jpc, jpc->new_freeaddr); UNIX_ONLY( if (SS_NORMAL == status && !JNL_FILE_SWITCHED(jpc)) jnl_fsync(reg, jpc->new_freeaddr); ); } } return; } fis-gtm-V6.0-003/sr_port/jnl_write.c0000644000032200000250000006200212201176160016167 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_inet.h" #include /* for offsetof() macro */ #ifdef VMS #include /* Required for gtmsource.h */ #endif #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "filestruct.h" #include "ccp.h" #include "iosp.h" #include "jnl.h" #include "repl_msg.h" #include "gtmsource.h" #include "min_max.h" #include "sleep_cnt.h" #include "jnl_write.h" #include "copy.h" #include "jnl_get_checksum.h" #include "memcoherency.h" #include "is_proc_alive.h" #include "wbox_test_init.h" #include "gtmimagename.h" GBLREF jnlpool_ctl_ptr_t temp_jnlpool_ctl; GBLREF uint4 process_id; GBLREF sm_uc_ptr_t jnldata_base; GBLREF jnlpool_addrs jnlpool; GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; GBLREF jnl_gbls_t jgbl; GBLREF boolean_t is_src_server; GBLREF boolean_t in_jnl_file_autoswitch; #ifdef DEBUG STATICDEF int jnl_write_recursion_depth; #define MAX_JNL_WRITE_RECURSION_DEPTH 2 #endif error_def(ERR_JNLWRTNOWWRTR); error_def(ERR_JNLWRTDEFER); #ifdef DEBUG /* The fancy ordering of operators/operands in the JNL_SPACE_AVAILABLE calculation is to avoid overflows. */ #define JNL_SPACE_AVAILABLE(jb, lcl_dskaddr, lcl_freeaddr, lcl_size, jnl_wrt_start_mask) \ ( \ assert(((jb)->dskaddr <= lcl_freeaddr) \ || (gtm_white_box_test_case_enabled \ && (WBTEST_JNL_FILE_LOST_DSKADDR == gtm_white_box_test_case_number))), \ /* the following assert is an || to take care of 4G value overflows or 0 underflows */ \ assert((lcl_freeaddr <= lcl_size) || ((jb)->dskaddr >= lcl_freeaddr - lcl_size) \ || (gtm_white_box_test_case_enabled \ && (WBTEST_JNL_FILE_LOST_DSKADDR == gtm_white_box_test_case_number))), \ (lcl_size - (lcl_freeaddr - ((lcl_dskaddr = (jb)->dskaddr) & jnl_wrt_start_mask))) \ ) #else #define JNL_SPACE_AVAILABLE(jb, dummy, lcl_freeaddr, lcl_size, jnl_wrt_start_mask) \ (lcl_size - (lcl_freeaddr - ((jb)->dskaddr & jnl_wrt_start_mask))) #endif #define JNL_PUTSTR(lcl_free, lcl_buff, src, len, lcl_size) \ { \ int size_before_wrap; \ \ size_before_wrap = lcl_size - lcl_free; \ if (len <= size_before_wrap) \ { \ memcpy(&lcl_buff[lcl_free], src, len); \ lcl_free += len; \ if (len == size_before_wrap) \ lcl_free = 0; \ } else \ { \ memcpy(&lcl_buff[lcl_free], src, size_before_wrap); \ lcl_free = len - size_before_wrap; \ memcpy(&lcl_buff[0], src + size_before_wrap, lcl_free); \ } \ } /* Note: DO_JNL_WRITE_ATTEMPT_IF_NEEDED and DO_JNL_FILE_EXTEND_IF_NEEDED are macros (instead of functions) for performance * reasons since they are invoked for the fast path (no-align-record) always and for the ALIGN record once in a while. */ #define DO_JNL_WRITE_ATTEMPT_IF_NEEDED(JPC, JB, LCL_DSKADDR, LCL_FREEADDR, LCL_SIZE, \ JNL_WRT_START_MASK, REC_LEN, JNL_WRT_START_MODULUS) \ { \ GBLREF uint4 process_id; \ \ assert((!JB->blocked) || (FALSE == is_proc_alive(JB->blocked, 0)) \ VMS_ONLY(|| ((JB->blocked == process_id) && lib$ast_in_prog()))); \ JB->blocked = process_id; \ /* We should differentiate between a full and an empty journal buffer, hence the pessimism reflected \ * in the <= check below. Hence also the -1 in LCL_FREEADDR - (LCL_SIZE - REC_LEN - 1).* This means \ * that although we have space we might still be invoking jnl_write_attempt (very unlikely). \ */ \ if (JNL_SPACE_AVAILABLE(JB, LCL_DSKADDR, LCL_FREEADDR, LCL_SIZE, JNL_WRT_START_MASK) <= REC_LEN) \ { /* The fancy ordering of operators/operands in the calculation done below is to avoid overflows. */ \ if (SS_NORMAL != jnl_write_attempt(JPC, \ ROUND_UP2(LCL_FREEADDR - (LCL_SIZE - REC_LEN- 1), JNL_WRT_START_MODULUS))) \ { \ assert(NOJNL == JPC->channel); /* jnl file lost */ \ DEBUG_ONLY(jnl_write_recursion_depth--); \ return; /* let the caller handle the error */ \ } \ } \ JB->blocked = 0; \ } #define DO_JNL_FILE_EXTEND_IF_NEEDED(JREC_LEN, JB, LCL_FREEADDR, CSA, RECTYPE, BLK_PTR, JFB, REG, JPC, JNL_REC) \ { \ int4 jrec_len_padded; \ \ GBLREF boolean_t in_jnl_file_autoswitch; \ \ /* Before writing a journal record, check if we have some padding space \ * to close the journal file in case we are on the verge of an autoswitch. \ * If we are about to autoswitch the journal file at this point, dont \ * do the padding check since the padding space has already been checked \ * in jnl_write calls before this autoswitch invocation. We can safely \ * write the input record without worrying about autoswitch limit overflow. \ */ \ jrec_len_padded = JREC_LEN; \ if (!in_jnl_file_autoswitch) \ jrec_len_padded = JREC_LEN + JNL_FILE_TAIL_PRESERVE; \ if (JB->filesize < DISK_BLOCKS_SUM(LCL_FREEADDR, jrec_len_padded)) /* not enough room in jnl file, extend it */ \ { /* We should never reach here if we are called from t_end/tp_tend. We check that by using the fact that \ * early_tn is different from curr_tn in the t_end/tp_tend case. The only exception is wcs_recover which \ * also sets these to be different in case of writing an INCTN record. For this case though it is okay to \ * extend/autoswitch the file. So allow that. \ */ \ assertpro((CSA->ti->early_tn == CSA->ti->curr_tn) || (JRT_INCTN == RECTYPE)); \ assert(!IS_REPLICATED(RECTYPE)); /* all replicated jnl records should have gone through t_end/tp_tend */ \ assert(jrt_fixed_size[RECTYPE]); /* this is used later in re-computing checksums */ \ assert(NULL == BLK_PTR); /* as otherwise it is a PBLK or AIMG record which is of variable record \ * length that conflicts with the immediately above assert. \ */ \ assert(NULL == JFB); /* as otherwise it is a logical record with formatted journal records which \ * is of variable record length (conflicts with the jrt_fixed_size assert). \ */ \ assertpro(!in_jnl_file_autoswitch); /* avoid recursion of jnl_file_extend */ \ if (SS_NORMAL != jnl_flush(REG)) \ { \ assert(NOJNL == JPC->channel); /* jnl file lost */ \ DEBUG_ONLY(jnl_write_recursion_depth--); \ return; /* let the caller handle the error */ \ } \ assert(LCL_FREEADDR == JB->dskaddr); \ if (EXIT_ERR == jnl_file_extend(JPC, JREC_LEN)) /* if extension fails, not much we can do */ \ { \ DEBUG_ONLY(jnl_write_recursion_depth--); \ assert(FALSE); \ return; \ } \ if (0 == JPC->pini_addr) \ { /* This can happen only if jnl got switched in jnl_file_extend above. \ * Write a PINI record in the new journal file and then continue writing the input record. \ * Basically we need to redo the processing in jnl_write because a lot of the local variables \ * have changed state (e.g. JB->freeaddr etc.). So we instead call jnl_write() \ * recursively and then return immediately. \ */ \ jnl_put_jrt_pini(CSA); \ assertpro(JPC->pini_addr); /* should have been set in "jnl_put_jrt_pini" */ \ if (JRT_PINI != RECTYPE) \ { \ JNL_REC->prefix.pini_addr = JPC->pini_addr; \ /* Checksum needs to be recomputed since prefix.pini_addr is changed in above statement */ \ JNL_REC->prefix.checksum = INIT_CHECKSUM_SEED; \ JNL_REC->prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, \ (uint4 *)JNL_REC, JNL_REC->prefix.forwptr); \ jnl_write(JPC, RECTYPE, JNL_REC, NULL, NULL); \ } \ DEBUG_ONLY(jnl_write_recursion_depth--); \ return; \ } \ } \ } /* jpc : Journal private control * rectype : Record type * jnl_rec : This contains fixed part of a variable size record or the complete fixed size records. * blk_ptr : For JRT_PBLK and JRT_AIMG this has the block image * jfb : For SET/KILL/ZKILL/ZTWORM records entire record is formatted in this. * For JRT_PBLK and JRT_AIMG it contains partial records */ void jnl_write(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_record *jnl_rec, blk_hdr_ptr_t blk_ptr, jnl_format_buffer *jfb) { int4 align_rec_len, rlen, rlen_with_align, dstlen, lcl_size, lcl_free, lcl_orig_free; jnl_buffer_ptr_t jb; sgmnt_addrs *csa; sgmnt_data_ptr_t csd; node_local_ptr_t cnl; struct_jrec_align align_rec; uint4 status; jrec_suffix suffix; boolean_t nowrap, is_replicated; struct_jrec_blk *jrec_blk; uint4 checksum, jnlpool_size, lcl_freeaddr; sm_uc_ptr_t lcl_buff; gd_region *reg; char *ptr; int jnl_wrt_start_modulus, jnl_wrt_start_mask; uint4 jnl_fs_block_size, aligned_lcl_free, padding_size; uint4 tmp_csum1, tmp_csum2; # ifdef DEBUG uint4 lcl_dskaddr, mumps_node_sz; char *mumps_node_ptr; # endif assert(jnl_write_recursion_depth++ < MAX_JNL_WRITE_RECURSION_DEPTH); reg = jpc->region; csa = &FILE_INFO(reg)->s_addrs; csd = csa->hdr; is_replicated = jrt_is_replicated[rectype]; /* Ensure that no replicated journal record is written by this routine if REPL-WAS_ENABLED(csa) is TRUE */ assert((JNL_ENABLED(csa) && !REPL_WAS_ENABLED(csa)) || !is_replicated); /* Assert that the only journal records that the source server ever writes are PINI/PFIN/EPOCH/EOF * which it does at the very end when the database is about to be shut down */ assert(!is_src_server || (JRT_EOF == rectype) || (JRT_PINI == rectype) || (JRT_EPOCH == rectype) || (JRT_PFIN == rectype)); assert(csa->now_crit || (csd->clustered && csa->nl->ccp_state == CCST_CLOSED)); assert(rectype > JRT_BAD && rectype < JRT_RECTYPES && JRT_ALIGN != rectype); jb = jpc->jnl_buff; /* Before taking a copy of jb->freeaddr, determine if both free and freeaddr are in sync. If not fix that first. */ if (jb->free_update_pid) { FIX_NONZERO_FREE_UPDATE_PID(csa, jb); } lcl_freeaddr = jb->freeaddr; lcl_free = jb->free; lcl_size = jb->size; lcl_buff = &jb->buff[jb->buff_off]; DBG_CHECK_JNL_BUFF_FREEADDR(jb); ++jb->reccnt[rectype]; assert(NULL != jnl_rec); rlen = jnl_rec->prefix.forwptr; /* Do high-level check on rlen */ assert(rlen <= jb->max_jrec_len); /* Do fine-grained checks on rlen */ GTMTRIG_ONLY(assert(!IS_ZTWORM(rectype) || (MAX_ZTWORM_JREC_LEN >= rlen));) /* ZTWORMHOLE */ assert(!IS_SET_KILL_ZKILL_ZTRIG(rectype) || (JNL_MAX_SET_KILL_RECLEN(csd) >= rlen)); /* SET, KILL, ZKILL */ assert((NULL == blk_ptr) || (JNL_MAX_PBLK_RECLEN(csd) >= rlen)); /* PBLK and AIMG */ jb->bytcnt += rlen; assert (0 == rlen % JNL_REC_START_BNDRY); rlen_with_align = rlen + (int4)MIN_ALIGN_RECLEN; assert(0 == rlen_with_align % JNL_REC_START_BNDRY); assert((uint4)rlen_with_align < ((uint4)1 << jb->log2_of_alignsize)); if ((lcl_freeaddr >> jb->log2_of_alignsize) == ((lcl_freeaddr + rlen_with_align - 1) >> jb->log2_of_alignsize)) rlen_with_align = rlen; else { align_rec.align_str.length = ROUND_UP2(lcl_freeaddr, ((uint4)1 << jb->log2_of_alignsize)) - lcl_freeaddr - (uint4)MIN_ALIGN_RECLEN; align_rec_len = (int4)(MIN_ALIGN_RECLEN + align_rec.align_str.length); assert (0 == align_rec_len % JNL_REC_START_BNDRY); rlen_with_align = rlen + align_rec_len; } jnl_wrt_start_mask = JNL_WRT_START_MASK(jb); jnl_wrt_start_modulus = JNL_WRT_START_MODULUS(jb); cnl = csa->nl; /* If we are currently extending the journal file and writing the closing part of journal records, * it better be the records that we expect. This is because we will skip the padding check for these * records. The macro JNL_FILE_TAIL_PRESERVE already takes into account padding space for these. */ assert(!in_jnl_file_autoswitch || (JRT_PINI == rectype) || (JRT_PFIN == rectype) || (JRT_EPOCH == rectype) || (JRT_INCTN == rectype) || (JRT_EOF == rectype)); if (rlen_with_align != rlen) { DO_JNL_WRITE_ATTEMPT_IF_NEEDED(jpc, jb, lcl_dskaddr, lcl_freeaddr, lcl_size, jnl_wrt_start_mask, align_rec_len, jnl_wrt_start_modulus); DO_JNL_FILE_EXTEND_IF_NEEDED(align_rec_len, jb, lcl_freeaddr, csa, rectype, blk_ptr, jfb, reg, jpc, jnl_rec); align_rec.prefix.jrec_type = JRT_ALIGN; assert(align_rec_len <= jb->max_jrec_len); align_rec.prefix.forwptr = suffix.backptr = align_rec_len; align_rec.prefix.time = jnl_rec->prefix.time; align_rec.prefix.tn = jnl_rec->prefix.tn; /* we have to write an ALIGN record here before writing the PINI record but we do not have a non-zero * pini_addr for the ALIGN since we have not yet written the PINI. we use the pini_addr field of the * first PINI journal record in the journal file which is nothing but JNL_FILE_FIRST_RECORD. */ align_rec.prefix.pini_addr = (JRT_PINI == rectype) ? JNL_FILE_FIRST_RECORD : jnl_rec->prefix.pini_addr; align_rec.prefix.checksum = INIT_CHECKSUM_SEED; suffix.suffix_code = JNL_REC_SUFFIX_CODE; align_rec.prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&align_rec, SIZEOF(jrec_prefix)); ADJUST_CHECKSUM(align_rec.prefix.checksum, lcl_freeaddr, align_rec.prefix.checksum); ADJUST_CHECKSUM(align_rec.prefix.checksum, csd->jnl_checksum, align_rec.prefix.checksum); assert(lcl_free >= 0 && lcl_free < lcl_size); if (lcl_size >= (lcl_free + align_rec_len)) { /* before the string for zeroes */ memcpy(lcl_buff + lcl_free, (uchar_ptr_t)&align_rec, FIXED_ALIGN_RECLEN); lcl_free += (int4)(FIXED_ALIGN_RECLEN + align_rec.align_str.length); /* zeroing is not necessary */ } else { JNL_PUTSTR(lcl_free, lcl_buff, (uchar_ptr_t)&align_rec, (int4)FIXED_ALIGN_RECLEN, lcl_size); if (lcl_size >= (lcl_free + align_rec.align_str.length + SIZEOF(jrec_suffix))) lcl_free += align_rec.align_str.length; /* zeroing is not necessary */ else { if (lcl_size >= (lcl_free + align_rec.align_str.length)) { lcl_free += align_rec.align_str.length; /* zeroing is not necessary */ if (lcl_size == lcl_free) lcl_free = 0; } else lcl_free = lcl_free + align_rec.align_str.length - lcl_size; } } /* Now copy suffix */ assert(0 == (UINTPTR_T)(&lcl_buff[0] + lcl_free) % SIZEOF(jrec_suffix)); *(jrec_suffix *)(lcl_buff + lcl_free) = *(jrec_suffix *)&suffix; lcl_free += SIZEOF(jrec_suffix); if (lcl_size == lcl_free) lcl_free = 0; jpc->new_freeaddr = lcl_freeaddr + align_rec_len; INCR_GVSTATS_COUNTER(csa, cnl, n_jrec_other, 1); INCR_GVSTATS_COUNTER(csa, cnl, n_jbuff_bytes, align_rec_len); assert(jgbl.gbl_jrec_time >= align_rec.prefix.time); assert(align_rec.prefix.time >= jb->prev_jrec_time); jb->prev_jrec_time = align_rec.prefix.time; jpc->temp_free = lcl_free; /* set jpc->temp_free BEFORE setting free_update_pid (secshr_db_clnup relies on this) */ assert(lcl_free == jpc->new_freeaddr % lcl_size); /* Note that freeaddr should be updated ahead of free since jnl_output_sp.c does computation of wrtsize * based on free and asserts follow later there which use freeaddr. */ jb->free_update_pid = process_id; lcl_freeaddr = jpc->new_freeaddr; jb->freeaddr = lcl_freeaddr; /* Write memory barrier here to enforce the fact that freeaddr *must* be seen to be updated before free is updated. It is less important if free is stale so we do not require a 2nd barrier for that and will let the lock release (crit lock required since clustering not currently supported) do the 2nd memory barrier for us. This barrier takes care of this process's responsibility to broadcast cache changes. It is up to readers to also specify a read memory barrier if necessary to receive this broadcast. */ SHM_WRITE_MEMORY_BARRIER; jb->free = lcl_free; jb->free_update_pid = 0; DBG_CHECK_JNL_BUFF_FREEADDR(jb); if (JRT_PINI == rectype) { jnl_rec->prefix.pini_addr = lcl_freeaddr; /* Checksum needs to be recomputed since prefix.pini_addr is changed in above statement */ jnl_rec->prefix.checksum = INIT_CHECKSUM_SEED; jnl_rec->prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&jnl_rec->jrec_pini, SIZEOF(struct_jrec_pini)); } } checksum = jnl_rec->prefix.checksum; assert(checksum); # ifdef DEBUG /* Ensure that the checksum computed earlier in jnl_format or jnl_write_pblk or jnl_write_aimg_rec or fixed-sized records * matches with the block's content. */ if ((JRT_PBLK == rectype) || (JRT_AIMG == rectype)) { COMPUTE_COMMON_CHECKSUM(tmp_csum2, jnl_rec->prefix); tmp_csum1 = jnl_get_checksum((uint4 *)blk_ptr, NULL, jnl_rec->jrec_pblk.bsiz); COMPUTE_PBLK_CHECKSUM(tmp_csum1, &jnl_rec->jrec_pblk, tmp_csum2, tmp_csum1); assert(checksum == tmp_csum1); } else if (IS_SET_KILL_ZKILL_ZTRIG_ZTWORM(rectype)) { COMPUTE_COMMON_CHECKSUM(tmp_csum2, jnl_rec->prefix); mumps_node_ptr = jfb->buff + FIXED_UPD_RECLEN; mumps_node_sz = jfb->record_size - (FIXED_UPD_RECLEN + JREC_SUFFIX_SIZE); tmp_csum1 = jnl_get_checksum((uint4 *)mumps_node_ptr, NULL, mumps_node_sz); COMPUTE_LOGICAL_REC_CHECKSUM(tmp_csum1, &jnl_rec->jrec_set_kill, tmp_csum2, tmp_csum1); assert(checksum == tmp_csum1); }else if (jrt_fixed_size[rectype] || JRT_ALIGN == rectype) { jnl_rec->prefix.checksum = INIT_CHECKSUM_SEED; switch(rectype) { case JRT_ALIGN: tmp_csum1 = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&jnl_rec->jrec_align, SIZEOF(jrec_prefix)); break; default: if(JRT_TRIPLE != rectype && JRT_HISTREC != rectype) tmp_csum1 = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&jnl_rec->jrec_set_kill, jnl_rec->prefix.forwptr); break; } assert(checksum == tmp_csum1); jnl_rec->prefix.checksum = checksum; } # endif ADJUST_CHECKSUM(checksum, lcl_freeaddr, checksum); ADJUST_CHECKSUM(checksum, csd->jnl_checksum, checksum); jnl_rec->prefix.checksum = checksum; DO_JNL_WRITE_ATTEMPT_IF_NEEDED(jpc, jb, lcl_dskaddr, lcl_freeaddr, lcl_size, jnl_wrt_start_mask, rlen, jnl_wrt_start_modulus); DO_JNL_FILE_EXTEND_IF_NEEDED(rlen, jb, lcl_freeaddr, csa, rectype, blk_ptr, jfb, reg, jpc, jnl_rec); lcl_orig_free = lcl_free; nowrap = (lcl_size >= (lcl_free + rlen)); assert(jrt_fixed_size[JRT_EOF]); if (jrt_fixed_size[rectype]) { if (nowrap) { memcpy(lcl_buff + lcl_free, (uchar_ptr_t)jnl_rec, rlen); lcl_free += rlen; if (lcl_size == lcl_free) lcl_free = 0; } else JNL_PUTSTR(lcl_free, lcl_buff, (uchar_ptr_t)jnl_rec, rlen, lcl_size); /* As part of writing the EOF record into the journal buffer, add enough 0-padding needed to reach * a filesystem-block-size aligned boundary. This way later jnl_qio_start can safely do aligned * writes without having to write non-zero garbage after the EOF record. Note that this has to be * done BEFORE updating freeaddr. Otherwise, it is possible that a jnl qio timer pops after freeaddr * gets updated but before the 0-padding is done and flushes the eof record to disk without the 0-padding. */ if (JRT_EOF == rectype) { jnl_fs_block_size = jb->fs_block_size; aligned_lcl_free = ROUND_UP2(lcl_free, jnl_fs_block_size); padding_size = aligned_lcl_free - lcl_free; assert(0 <= (int4)padding_size); if (padding_size) memset(lcl_buff + lcl_free, 0, padding_size); } /* Note: Cannot easily use ? : syntax below as INCR_GVSTATS_COUNTER macro * is not an arithmetic expression but a sequence of statements. */ if (JRT_EPOCH != rectype) INCR_GVSTATS_COUNTER(csa, cnl, n_jrec_other, 1); /* else for EPOCH, the increment of JRE or JRI is done after "jnl_write_epoch_rec" in caller */ } else { if (NULL != blk_ptr) /* PBLK and AIMG */ { assert(FIXED_BLK_RECLEN == FIXED_PBLK_RECLEN); assert(FIXED_BLK_RECLEN == FIXED_AIMG_RECLEN); jrec_blk = (struct_jrec_blk *)jnl_rec; if (nowrap) { /* write fixed part of record before the actual gds block image */ memcpy(lcl_buff + lcl_free, (uchar_ptr_t)jnl_rec, FIXED_BLK_RECLEN); lcl_free += (int4)FIXED_BLK_RECLEN; /* write actual block */ memcpy(lcl_buff + lcl_free, (uchar_ptr_t)blk_ptr, jrec_blk->bsiz); lcl_free += jrec_blk->bsiz; /* Now write trailing characters for 8-bye alignment and then suffix */ memcpy(lcl_buff + lcl_free, (uchar_ptr_t)jfb->buff, jfb->record_size); lcl_free += jfb->record_size; assert(lcl_free <= lcl_size); if (lcl_size == lcl_free) lcl_free = 0; } else { /* write fixed part of record before the actual gds block image */ JNL_PUTSTR(lcl_free, lcl_buff, (uchar_ptr_t)jnl_rec, (int4)FIXED_BLK_RECLEN, lcl_size); /* write actual block */ JNL_PUTSTR(lcl_free, lcl_buff, (uchar_ptr_t)blk_ptr, jrec_blk->bsiz, lcl_size); /* Now write trailing characters for 8-bye alignment and then suffix */ JNL_PUTSTR(lcl_free, lcl_buff, (uchar_ptr_t)jfb->buff, jfb->record_size, lcl_size); } INCR_GVSTATS_COUNTER(csa, cnl, n_jrec_pblk, 1); } else { /* SET, KILL, ZKILL for TP, ZTP, non-TP */ assert(IS_TP(rectype) || IS_ZTP(rectype) || (0 == ((struct_jrec_upd *)jfb->buff)->update_num)); assert((!IS_TP(rectype) && !IS_ZTP(rectype)) || (0 != ((struct_jrec_upd *)jfb->buff)->update_num)); assert(((jrec_prefix *)jfb->buff)->forwptr == jfb->record_size); if (nowrap) { memcpy(lcl_buff + lcl_free, (uchar_ptr_t)jfb->buff, rlen); lcl_free += rlen; if (lcl_size == lcl_free) lcl_free = 0; } else JNL_PUTSTR(lcl_free, lcl_buff, (uchar_ptr_t)jfb->buff, rlen, lcl_size); INCR_GVSTATS_COUNTER(csa, cnl, n_jrec_logical, 1); } } assert((lcl_free - lcl_orig_free + lcl_size) % lcl_size == rlen); assert(lcl_buff[lcl_orig_free] == rectype); assert(lcl_orig_free < lcl_free || lcl_free < jb->dsk); assert((lcl_freeaddr >= jb->dskaddr) || (gtm_white_box_test_case_enabled && (WBTEST_JNL_FILE_LOST_DSKADDR == gtm_white_box_test_case_number))); jpc->new_freeaddr = lcl_freeaddr + rlen; INCR_GVSTATS_COUNTER(csa, cnl, n_jbuff_bytes, rlen); assert(lcl_free == jpc->new_freeaddr % lcl_size); if (REPL_ENABLED(csa) && is_replicated) { /* If the database is encrypted, then at this point jfb->buff will contain encrypted * data which we don't want to to push into the jnlpool. Instead, we make use of the * alternate alt_buff which is guaranteed to contain the original unencrypted data. */ if (jrt_fixed_size[rectype]) ptr = (char *)jnl_rec; else { # ifdef GTM_CRYPT if (csd->is_encrypted && IS_SET_KILL_ZKILL_ZTRIG_ZTWORM(rectype)) ptr = jfb->alt_buff; else # endif ptr = jfb->buff; } assert(NULL != jnlpool.jnlpool_ctl && NULL != jnlpool_ctl); /* ensure we haven't yet detached from the jnlpool */ assert((&FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs)->now_crit); /* ensure we have the jnl pool lock */ DEBUG_ONLY(jgbl.cu_jnl_index++;) jnlpool_size = temp_jnlpool_ctl->jnlpool_size; dstlen = jnlpool_size - temp_jnlpool_ctl->write; if (rlen <= dstlen) /* dstlen >= rlen (most frequent case) */ memcpy(jnldata_base + temp_jnlpool_ctl->write, ptr, rlen); else /* dstlen < rlen */ { memcpy(jnldata_base + temp_jnlpool_ctl->write, ptr, dstlen); memcpy(jnldata_base, ptr + dstlen, rlen - dstlen); } temp_jnlpool_ctl->write += rlen; if (temp_jnlpool_ctl->write >= jnlpool_size) temp_jnlpool_ctl->write -= jnlpool_size; } assert(jgbl.gbl_jrec_time >= jnl_rec->prefix.time); assert(jnl_rec->prefix.time >= jb->prev_jrec_time); jb->prev_jrec_time = jnl_rec->prefix.time; jpc->temp_free = lcl_free; /* set jpc->temp_free BEFORE setting free_update_pid (secshr_db_clnup relies on this) */ /* Note that freeaddr should be updated ahead of free since jnl_output_sp.c does computation of wrtsize * based on free and asserts follow later there which use freeaddr. */ jb->free_update_pid = process_id; lcl_freeaddr = jpc->new_freeaddr; jb->freeaddr = lcl_freeaddr; /* Write memory barrier here to enforce the fact that freeaddr *must* be seen to be updated before free is updated. It is less important if free is stale so we do not require a 2nd barrier for that and will let the lock release (crit lock required since clustering not currently supported) do the 2nd memory barrier for us. This barrier takes care of this process's responsibility to broadcast cache changes. It is up to readers to also specify a read memory barrier if necessary to receive this broadcast. */ SHM_WRITE_MEMORY_BARRIER; jb->free = lcl_free; jb->free_update_pid = 0; DBG_CHECK_JNL_BUFF_FREEADDR(jb); VMS_ONLY( if (((lcl_freeaddr - jb->dskaddr) > jb->min_write_size) && (SS_NORMAL != (status = jnl_qio_start(jpc))) && (ERR_JNLWRTNOWWRTR != status) && (ERR_JNLWRTDEFER != status)) { jb->blocked = 0; jnl_file_lost(jpc, status); DEBUG_ONLY(jnl_write_recursion_depth--); return; } ) DEBUG_ONLY(jnl_write_recursion_depth--); } fis-gtm-V6.0-003/sr_port/jnl_write.h0000644000032200000250000000135012201176160016173 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2003 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __JNL_WRITE_H__ #define __JNL_WRITE_H__ /* We do not put this in jnl.h, because it needs all including jnl.h must include gdsblk.h */ void jnl_write(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_record *jnl_rec, blk_hdr_ptr_t blk_ptr, jnl_format_buffer *jfb); #endif fis-gtm-V6.0-003/sr_port/jnl_write_aimg_rec.c0000644000032200000250000000716112201176160020022 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "gtm_string.h" #include "gtm_time.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "filestruct.h" #include "gdscc.h" #include "jnl.h" #include "jnl_write.h" #include "jnl_write_aimg_rec.h" #include "jnl_get_checksum.h" #include "min_max.h" #ifdef GTM_CRYPT #include "gtmcrypt.h" #endif GBLREF jnl_gbls_t jgbl; void jnl_write_aimg_rec(sgmnt_addrs *csa, cw_set_element *cse, uint4 com_csum) { struct_jrec_blk aimg_record; int tmp_jrec_size, jrec_size, zero_len; jnl_format_buffer blk_trailer; /* partial record after the aimg block */ char local_buff[JNL_REC_START_BNDRY + JREC_SUFFIX_SIZE]; jrec_suffix *suffix; blk_hdr_ptr_t buffer, save_buffer; jnl_private_control *jpc; sgmnt_data_ptr_t csd; uint4 cursum; # ifdef GTM_CRYPT char *in, *out; int in_len, gtmcrypt_errno; gd_segment *seg; # endif csd = csa->hdr; assert(csa->now_crit); jpc = csa->jnl; assert(0 != jpc->pini_addr); aimg_record.prefix.jrec_type = JRT_AIMG; aimg_record.prefix.pini_addr = (0 == jpc->pini_addr) ? JNL_HDR_LEN : jpc->pini_addr; aimg_record.prefix.tn = csa->ti->curr_tn; /* At this point jgbl.gbl_jrec_time should be set by the caller */ assert(jgbl.gbl_jrec_time); aimg_record.prefix.time = jgbl.gbl_jrec_time; aimg_record.prefix.checksum = INIT_CHECKSUM_SEED; aimg_record.blknum = cse->blk; /* in case we have a bad block-size, we dont want to write an AIMG larger than the GDS block size (maximum block size) */ buffer = (blk_hdr_ptr_t)cse->new_buff; assert(buffer->bsiz <= csd->blk_size); assert(buffer->bsiz >= SIZEOF(blk_hdr)); aimg_record.bsiz = MIN(csd->blk_size, buffer->bsiz); aimg_record.ondsk_blkver = cse->ondsk_blkver; tmp_jrec_size = (int)FIXED_AIMG_RECLEN + aimg_record.bsiz + JREC_SUFFIX_SIZE; jrec_size = ROUND_UP2(tmp_jrec_size, JNL_REC_START_BNDRY); zero_len = jrec_size - tmp_jrec_size; blk_trailer.buff = local_buff + (JNL_REC_START_BNDRY - zero_len); memset(blk_trailer.buff, 0, zero_len); blk_trailer.record_size = zero_len + JREC_SUFFIX_SIZE; suffix = (jrec_suffix *)&local_buff[JNL_REC_START_BNDRY]; aimg_record.prefix.forwptr = suffix->backptr = jrec_size; suffix->suffix_code = JNL_REC_SUFFIX_CODE; assert(SIZEOF(uint4) == SIZEOF(jrec_suffix)); save_buffer = buffer; # ifdef GTM_CRYPT in_len = aimg_record.bsiz - SIZEOF(*buffer); if (BLOCK_REQUIRE_ENCRYPTION(csd->is_encrypted, buffer->levl, in_len)) { ASSERT_ENCRYPTION_INITIALIZED; memcpy(csa->encrypted_blk_contents, buffer, SIZEOF(*buffer)); in = (char *)(buffer + 1); out = csa->encrypted_blk_contents + SIZEOF(blk_hdr); GTMCRYPT_ENCRYPT(csa, csa->encr_key_handle, in, in_len, out, gtmcrypt_errno); if (0 != gtmcrypt_errno) { seg = csa->region->dyn.addr; GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, rts_error, seg->fname_len, seg->fname); } buffer = (blk_hdr_ptr_t)csa->encrypted_blk_contents; } # endif cursum = jnl_get_checksum((uint4 *)buffer, NULL, aimg_record.bsiz); COMPUTE_AIMG_CHECKSUM(cursum, &aimg_record, com_csum, aimg_record.prefix.checksum); jnl_write(jpc, JRT_AIMG, (jnl_record *)&aimg_record, buffer, &blk_trailer); buffer = save_buffer; } fis-gtm-V6.0-003/sr_port/jnl_write_aimg_rec.h0000644000032200000250000000114012201176160020016 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __JNL_WRITE_AIMG_REC_H__ #define __JNL_WRITE_AIMG_REC_H__ void jnl_write_aimg_rec(sgmnt_addrs *csa, cw_set_element *cse, uint4 com_csum); #endif fis-gtm-V6.0-003/sr_port/jnl_write_attempt.c0000644000032200000250000003320512201176160017730 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "gdsbgtr.h" #include "filestruct.h" #include "iosp.h" #include "jnl.h" #include "lockconst.h" #include "interlock.h" #include "sleep_cnt.h" #include "send_msg.h" #include "wcs_sleep.h" #include "is_proc_alive.h" #include "compswap.h" #include "is_file_identical.h" #include "have_crit.h" #include "wbox_test_init.h" #include "anticipatory_freeze.h" #ifdef UNIX #include "repl_msg.h" /* needed for gtmsource.h */ #include "gtmsource.h" /* needed for jnlpool_addrs typedef */ #include "gtmmsg.h" #include "io.h" /* needed by gtmsecshr.h */ #include "gtmsecshr.h" /* for continue_proc */ #endif #include "gtm_c_stack_trace.h" #ifdef UNIX GBLREF jnlpool_addrs jnlpool; #endif GBLREF pid_t process_id; GBLREF uint4 image_count; error_def(ERR_JNLACCESS); error_def(ERR_JNLCNTRL); error_def(ERR_JNLFLUSH); error_def(ERR_JNLFLUSHNOPROG); error_def(ERR_JNLPROCSTUCK); error_def(ERR_JNLQIOSALVAGE); error_def(ERR_JNLWRTDEFER); error_def(ERR_JNLWRTNOWWRTR); error_def(ERR_TEXT); static uint4 jnl_sub_write_attempt(jnl_private_control *jpc, unsigned int *lcnt, uint4 threshold) { sgmnt_addrs *csa; jnl_buffer_ptr_t jb; unsigned int status; boolean_t was_crit, exact_check; /**** Note static/local */ static uint4 loop_image_count, writer; /* assumes calls from one loop at a time */ uint4 new_dskaddr, new_dsk; static uint4 stuck_cnt = 0; /* Some callers of jnl_sub_write_attempt (jnl_flush->jnl_write_attempt, jnl_write->jnl_write_attempt) are in * crit, and some other (jnl_wait->jnl_write_attempt) are not. Callers in crit do not need worry about journal * buffer fields (dskaddr, freeaddr) changing underneath them, but for those not in crit, jnl_sub_write_attempt * might incorrectly return an error status when journal file is switched. Such callers should check for * journal file switched condition and terminate any loops they are in. */ jb = jpc->jnl_buff; status = ERR_JNLWRTDEFER; csa = &FILE_INFO(jpc->region)->s_addrs; was_crit = csa->now_crit; exact_check = was_crit && (threshold == jb->freeaddr); /* see comment in jnl_write_attempt() for why this is needed */ while (exact_check ? (jb->dskaddr != threshold) : (jb->dskaddr < threshold)) { #ifdef UNIX if (jb->io_in_prog_latch.u.parts.latch_pid == process_id) { /* if error condition occurred while doing jnl_qio_start(), then release the lock before waiting */ /* note that this is done only in UNIX because Unix does synchronous I/O */ jb->image_count = 0; RELEASE_SWAPLOCK(&jb->io_in_prog_latch); } if (!jb->io_in_prog_latch.u.parts.latch_pid) status = jnl_qio_start(jpc); #elif defined VMS if (lib$ast_in_prog()) { if (!jb->io_in_prog) { assert(jb->blocked == process_id); jnl_start_ast(jpc); if (jb->now_writer == process_id) status = jb->iosb.cond; } break; /* no fancy stuff within an AST */ } else if (!jb->io_in_prog) { /* Note down jpc->new_dskaddr/new_dsk into local variables so we get a consistent copy of these two * variables for checking them later. */ new_dskaddr = jpc->new_dskaddr; new_dsk = jpc->new_dsk; status = jnl_qio_start(jpc); } #else #error UNSUPPORTED PLATFORM #endif if (SS_NORMAL == status) { # if defined VMS /* Check if JNLCNTRL error was signalled by jnl_qio_start(). Note that it does not explicitly * return this error since it in turn calls an AST routine jnl_start_ast that actually has the * qio lock (and hence can look at dskaddr/dsk without any concurrency issues). But jpc will * have two fields new_dskaddr/new_dsk set to what dskaddr/dsk were right after obtaining the * qio lock but before releasing it in case of a JNLCNTRL error. We use those two values to * recheck if this is a JNLCNTRL error situation and if so return that error from here. * Note that we cannot use fields from jpc since they could be set by an AST that pops right * after we check new_dskaddr below but before we fetch the value of new_dsk. So it is important * to use the local variables which we know are a consistent snapshot of jpc->new_dskaddr/new_dsk. * The only consequence of this approach is that in case there is a dskaddr/dsk inconsistency, * it will be detected by the local variables in the next iteration (not the first time around). */ if ((new_dskaddr % jb->size) != new_dsk) { assert(gtm_white_box_test_case_enabled && (WBTEST_JNL_FILE_LOST_DSKADDR == gtm_white_box_test_case_number)); status = ERR_JNLCNTRL; } # endif break; } UNIX_ONLY(assert(ERR_JNLWRTNOWWRTR != status);) /* dont have asynchronous jnl writes in Unix */ if ((ERR_JNLWRTNOWWRTR != status) && (ERR_JNLWRTDEFER != status)) return status; if ((writer != CURRENT_JNL_IO_WRITER(jb)) || (1 == *lcnt)) { writer = CURRENT_JNL_IO_WRITER(jb); loop_image_count = jb->image_count; *lcnt = 1; /* !!! this should be detected and limited by the caller !!! */ break; } if (*lcnt <= JNL_MAX_FLUSH_TRIES) { wcs_sleep(*lcnt); break; } VMS_ONLY( if ((CURRENT_JNL_IO_WRITER(jb) == process_id) && (jpc->qio_active == TRUE) && (jb->iosb.cond == -2)) { /* this an "impossible" condition where the private flag and the io have lost sync */ GTMASSERT; /* this should only occur in VMS; secshr_db_clnup should clear the problem */ } ) if (writer == CURRENT_JNL_IO_WRITER(jb)) { if (!was_crit) grab_crit(jpc->region); /* jnl_write_attempt has an assert about have_crit that this relies on */ if (VMS_ONLY(0 == writer ||) FALSE == is_proc_alive(writer, jb->image_count)) { /* no one home, clear the semaphore; */ BG_TRACE_PRO_ANY(csa, jnl_blocked_writer_lost); jnl_send_oper(jpc, ERR_JNLQIOSALVAGE); VMS_ONLY(jb->io_in_prog = 0); UNIX_ONLY(COMPSWAP_UNLOCK(&jb->io_in_prog_latch, writer, jb->image_count, LOCK_AVAILABLE, 0)); if (!was_crit) rel_crit(jpc->region); *lcnt = 1; continue; } if (!was_crit) rel_crit(jpc->region); /* this is the interesting case: a process is stuck */ BG_TRACE_PRO_ANY(csa, jnl_blocked_writer_stuck); jpc->status = status; jnl_send_oper(jpc, ERR_JNLFLUSH); send_msg_csa(CSA_ARG(csa) VARLSTCNT(3) ERR_JNLPROCSTUCK, 1, writer); stuck_cnt++; GET_C_STACK_FROM_SCRIPT("JNLPROCSTUCK", process_id, writer, stuck_cnt); *lcnt = 1; /* ??? is it necessary to limit this, and if so, how ??? */ status = ERR_JNLPROCSTUCK; UNIX_ONLY(continue_proc(writer)); break; } break; } if ((threshold > jb->freeaddr) || (csa->now_crit && ((jb->dskaddr > jb->freeaddr) || (jb->free != (jb->freeaddr % jb->size))))) { /* threshold > jb->freeaddr => somebody decremented jb->freeaddr after we computed threshold, or jnl was switched * jb->dsk != jb->freeaddr % jb->size => out of design condition * jb->dskaddr > jb->freeaddr => out of design condition, or jnl was switched */ status = ERR_JNLCNTRL; } return status; } uint4 jnl_write_attempt(jnl_private_control *jpc, uint4 threshold) { jnl_buffer_ptr_t jb; unsigned int lcnt, prev_lcnt, cnt; sgmnt_addrs *csa; unsigned int status; boolean_t was_crit, jnlfile_lost, exact_check; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; jb = jpc->jnl_buff; csa = &FILE_INFO(jpc->region)->s_addrs; was_crit = csa->now_crit; /* If holding crit and input threshold matches jb->freeaddr, then we need to wait in the loop as long as dskaddr * is not EQUAL to threshold. This is because if dskaddr is lesser than threshold we need to wait. If ever it * becomes greater than threshold, it is an out-of-design situation (since dskaddr has effectively become > freeaddr) * and so we need to trigger "jnl_file_lost" which is done in "jnl_sub_write_attempt" so it is important to invoke * that routine (in the for loop below). Hence the need to do an exact match instead of a < match. If not holding * crit or input threshold does not match jb->freeaddr, then dskaddr becoming GREATER than threshold is a valid * condition so we should do a (dskaddr < threshold), not a (dskaddr != threshold) check in that case. */ exact_check = was_crit && (threshold == jb->freeaddr); assert(!was_crit || threshold <= jb->freeaddr); /* Check that we either own crit on the current region or we DONT own crit on ANY region. This is relied upon by * the grab_crit calls (done in jnl_write_attempt and jnl_sub_write_attempt) to ensure no deadlocks are possible. */ assert(was_crit || (0 == have_crit(CRIT_HAVE_ANY_REG))); for (prev_lcnt = lcnt = cnt = 1; (was_crit || (NOJNL != jpc->channel)) && (exact_check ? jb->dskaddr != threshold : jb->dskaddr < threshold); lcnt++, prev_lcnt = lcnt, cnt++) { status = jnl_sub_write_attempt(jpc, &lcnt, threshold); if (JNL_FILE_SWITCHED(jpc)) { /* If we are holding crit, the journal file switch could happen in the form of journaling getting * turned OFF (due to disk space issues etc.) */ jpc->status = SS_NORMAL; return SS_NORMAL; } if (SS_NORMAL == status) { /* In VMS, jnl writes are asynchronous. The above call to "jnl_sub_write_attempt" has returned * SS_NORMAL status. This means the jnl qio lock is not in use by anyone else and is up for grabs. * We would have scheduled a jnl qio write through a sys$dclast call. We have no control of when * the AST routine "jnl_start_ast" will actually get control and start the write. Until then * we dont want to keep reinvoking "jnl_sub_write_attempt" in a hard spin loop. So sleep. * In Unix, writes are synchronous so SS_NORMAL status return implies we have completed a jnl * write and "jb->dskaddr" is closer to "threshold" than it was in the previous iteration. * A sleep at this point will only slow things down unnecessarily. Hence no sleep if Unix. */ VMS_ONLY(wcs_sleep(lcnt);) continue; } if ((ERR_JNLCNTRL == status) || (ERR_JNLACCESS == status) || (csa->now_crit && (ERR_JNLWRTDEFER != status) && (ERR_JNLWRTNOWWRTR != status) && (ERR_JNLPROCSTUCK != status))) { /* If JNLCNTRL or if holding crit and not waiting for some other writer (or self in VMS) * better turn off journaling and proceed with database update to avoid a database hang. */ if (was_crit) jb->blocked = 0; else { assertpro(0 == have_crit(CRIT_HAVE_ANY_REG)); grab_crit(jpc->region); /* jnl_write_attempt has an assert about have_crit that this relies on */ } jnlfile_lost = FALSE; if (jb->free_update_pid) { FIX_NONZERO_FREE_UPDATE_PID(csa, jb); } else { assert((gtm_white_box_test_case_enabled && (WBTEST_JNL_FILE_LOST_DSKADDR == gtm_white_box_test_case_number)) UNIX_ONLY(|| TREF(gtm_test_fake_enospc) || WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC))); if (JNL_ENABLED(csa->hdr)) { /* We ignore the return value of jnl_file_lost() since we always want to report the journal * error, whatever its error handling method is. Also, an operator log will be sent by some * callers (t_end()) only if an error is returned here, and the operator log is wanted in * those cases. */ jnl_file_lost(jpc, status); jnlfile_lost = TRUE; } /* Else journaling got closed concurrently by another process by invoking "jnl_file_lost" * just before we got crit. Do not invoke "jnl_file_lost" again on the same journal file. * Instead continue and next iteration will detect the journal file has switched and terminate. */ } if (!was_crit) rel_crit(jpc->region); if (!jnlfile_lost) continue; else return status; } # ifdef UNIX if ((ERR_JNLWRTDEFER == status) && IS_REPL_INST_FROZEN) { /* Check if the write was deferred because the instance is frozen. * In that case, wait until the freeze is lifted instead of wasting time spinning on the latch * in jnl_qio. */ WAIT_FOR_REPL_INST_UNFREEZE(csa); } # endif if ((ERR_JNLWRTDEFER != status) && (ERR_JNLWRTNOWWRTR != status) && (ERR_JNLPROCSTUCK != status)) { /* If holding crit, then jnl_sub_write_attempt would have invoked jnl_file_lost which would have * caused the JNL_FILE_SWITCHED check at the beginning of this for loop to succeed and return from * this function so we should never have gotten here. Assert accordingly. If not holding crit, * wait for some crit holder to invoke jnl_file_lost. Until then keep sleep looping indefinitely. * The sleep in this case is not time-limited because the callers of jnl_write_attempt (particularly * jnl_wait) do not check its return value so they assume success returns from this function. It is * non-trivial to change the interface and code of all callers to handle the error situation so we * instead choose to sleep indefinitely here until some crit process encounters the same error and * triggers jnl_file_lost processing which will terminate the loop due to the JNL_FILE_SWITCHED check. */ assert(!csa->now_crit); wcs_sleep(lcnt); } else if (prev_lcnt != lcnt) { assert(1 == lcnt); if ((ERR_JNLWRTDEFER == status) && (JNL_FLUSH_PROG_TRIES <= cnt)) { /* Change of writer */ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_JNLFLUSHNOPROG, 2, JNL_LEN_STR(csa->hdr), ERR_TEXT, 2, LEN_AND_LIT("No progress even with multiple writers")); cnt = 0; } } } return SS_NORMAL; } fis-gtm-V6.0-003/sr_port/jnl_write_eof_rec.c0000644000032200000250000000556712201176160017666 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_inet.h" #ifdef VMS #include /* Required for gtmsource.h */ #endif #include "gtm_time.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "jnl_write.h" #include "repl_msg.h" #include "gtmsource.h" #include "jnl_get_checksum.h" GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; GBLREF jnl_gbls_t jgbl; void jnl_write_eof_rec(sgmnt_addrs *csa, struct_jrec_eof *eof_record) { jnl_private_control *jpc; assert(csa->now_crit); jpc = csa->jnl; assert(0 != jpc->pini_addr); eof_record->prefix.jrec_type = JRT_EOF; eof_record->prefix.forwptr = eof_record->suffix.backptr = EOF_RECLEN; eof_record->suffix.suffix_code = JNL_REC_SUFFIX_CODE; eof_record->prefix.pini_addr = (0 == jpc->pini_addr) ? JNL_HDR_LEN : jpc->pini_addr; eof_record->prefix.tn = csa->hdr->trans_hist.curr_tn; eof_record->prefix.checksum = INIT_CHECKSUM_SEED; /* At this point jgbl.gbl_jrec_time should be set by the caller */ assert(jgbl.gbl_jrec_time); eof_record->prefix.time = jgbl.gbl_jrec_time; ASSERT_JNL_SEQNO_FILEHDR_JNLPOOL(csa->hdr, jnlpool_ctl); /* debug-only sanity check between seqno of filehdr and jnlpool */ UNIX_ONLY( /* In UNIX, mur_close_files, at the beginning sets both jgbl.mur_jrec_seqno and csa->hdr->reg_seqno to * murgbl.consist_jnl_seqno. Assert that this is indeed the case. However, csa->hdr->reg_seqno is NOT * maintained by rollback during forward phase of recovery and is set only at mur_close_files whereas * jgbl.mur_jrec_seqno is maintained all along. So, unless we are called from mur_close_files, we cannot * rely csa->hdr->reg_seqno and so we can do the equality check only if we are called from mur_close_files */ assert(!jgbl.forw_phase_recovery || !jgbl.mur_rollback || (jgbl.mur_jrec_seqno == csa->hdr->reg_seqno) || !process_exiting); ) if (!jgbl.forw_phase_recovery) { if (REPL_ALLOWED(csa)) eof_record->jnl_seqno = csa->hdr->reg_seqno;/* Note we cannot use jnlpool_ctl->jnl_seqno since * we might not presently hold the journal pool lock */ else eof_record->jnl_seqno = 0; } else QWASSIGN(eof_record->jnl_seqno, jgbl.mur_jrec_seqno); eof_record->filler = 0; eof_record->prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)eof_record, SIZEOF(struct_jrec_eof)); jnl_write(jpc, JRT_EOF, (jnl_record *)eof_record, NULL, NULL); } fis-gtm-V6.0-003/sr_port/jnl_write_epoch_rec.c0000644000032200000250000001535212201176160020204 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #if defined(UNIX) #include "gtm_fcntl.h" #include "gtm_unistd.h" #include "eintr_wrappers.h" #elif defined(VMS) #include /* Required for gtmsource.h */ #include #include #include #include "iosb_disk.h" #endif #include "gtm_inet.h" #include "gtm_time.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "jnl_write.h" #include "repl_msg.h" #include "gtmsource.h" #include "gtmio.h" #include "iosp.h" #include "jnl_get_checksum.h" #include "anticipatory_freeze.h" GBLREF jnl_gbls_t jgbl; GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; GBLREF seq_num seq_num_zero; #ifdef UNIX GBLREF int4 strm_index; #endif error_def (ERR_PREMATEOF); void jnl_write_epoch_rec(sgmnt_addrs *csa) { struct_jrec_epoch epoch_record; jnl_buffer_ptr_t jb; jnl_private_control *jpc; jnl_file_header *header; unsigned char hdr_base[REAL_JNL_HDR_LEN + MAX_IO_BLOCK_SIZE]; sgmnt_data_ptr_t csd; #if defined(VMS) io_status_block_disk iosb; #endif uint4 jnl_fs_block_size, read_write_size; int idx; assert(csa->now_crit); jpc = csa->jnl; jb = jpc->jnl_buff; assert((csa->ti->early_tn == csa->ti->curr_tn) || (csa->ti->early_tn == csa->ti->curr_tn + 1)); assert(0 != jpc->pini_addr); csd = csa->hdr; epoch_record.prefix.jrec_type = JRT_EPOCH; epoch_record.prefix.forwptr = epoch_record.suffix.backptr = EPOCH_RECLEN; epoch_record.blks_to_upgrd = csd->blks_to_upgrd; epoch_record.total_blks = csd->trans_hist.total_blks; epoch_record.free_blocks = csd->trans_hist.free_blocks; epoch_record.fully_upgraded = csd->fully_upgraded; epoch_record.suffix.suffix_code = JNL_REC_SUFFIX_CODE; /* in case jpc->pini_addr turns out to be zero (not clear how), we use the pini_addr field of the * first PINI journal record in the journal file which is nothing but JNL_HDR_LEN. */ epoch_record.prefix.pini_addr = (0 == jpc->pini_addr) ? JNL_HDR_LEN : jpc->pini_addr; jb->epoch_tn = epoch_record.prefix.tn = csa->ti->curr_tn; /* At this point jgbl.gbl_jrec_time should be set by the caller */ assert(jgbl.gbl_jrec_time); epoch_record.prefix.time = jgbl.gbl_jrec_time; /* we need to write epochs if jgbl.forw_phase_recovery so future recovers will have a closer turnaround point */ jb->next_epoch_time = epoch_record.prefix.time + jb->epoch_interval; epoch_record.prefix.checksum = INIT_CHECKSUM_SEED; ASSERT_JNL_SEQNO_FILEHDR_JNLPOOL(csd, jnlpool_ctl); /* debug-only sanity check between seqno of filehdr and jnlpool */ if (jgbl.forw_phase_recovery) { /* Set jnl-seqno of epoch record from the current seqno that rollback is playing. Note that in case of -recover * we dont actually care what seqnos get assigned to the epoch record so we go ahead and set it to the same * fields even though those might be 0 or not. */ epoch_record.jnl_seqno = jgbl.mur_jrec_seqno; for (idx = 0; idx < MAX_SUPPL_STRMS; idx++) epoch_record.strm_seqno[idx] = csd->strm_reg_seqno[idx]; /* If MUPIP JOURNAL -ROLLBACK, might need to do additional processing. See macro definition for comments */ MUR_ADJUST_STRM_REG_SEQNO_IF_NEEDED(csd, epoch_record.strm_seqno); # ifdef DEBUG if (jgbl.mur_rollback) { /* Assert that the unified jnl_seqno is always >= the individual stream seqnos. While this is not * guaranteed to be true if users play with the seqnos in the db file header, it is mostly true * and hence a good indicator to have particularly since it catches code issues right away. */ for (idx = 0; idx < MAX_SUPPL_STRMS; idx++) assert(epoch_record.strm_seqno[idx] <= epoch_record.jnl_seqno); } # endif } else if (REPL_ALLOWED(csd)) { epoch_record.jnl_seqno = csd->reg_seqno; /* Note we cannot use jnlpool_ctl->jnl_seqno since * we might not presently hold the journal pool lock */ for (idx = 0; idx < MAX_SUPPL_STRMS; idx++) epoch_record.strm_seqno[idx] = csd->strm_reg_seqno[idx]; } else { epoch_record.jnl_seqno = seq_num_zero; for (idx = 0; idx < MAX_SUPPL_STRMS; idx++) epoch_record.strm_seqno[idx] = 0; } if (jb->end_of_data) { jnl_fs_block_size = jb->fs_block_size; header = (jnl_file_header *)(ROUND_UP2((uintszofptr_t)hdr_base, jnl_fs_block_size)); read_write_size = ROUND_UP2(REAL_JNL_HDR_LEN, jnl_fs_block_size); assert((unsigned char *)header + read_write_size <= ARRAYTOP(hdr_base)); DO_FILE_READ(jpc->channel, 0, header, read_write_size, jpc->status, jpc->status2); assert(SS_NORMAL != jpc->status || SS_NORMAL == jpc->status2); if (SS_NORMAL == jpc->status) { header->end_of_data = jb->end_of_data; csa->hdr->jnl_eovtn = header->eov_tn; header->eov_tn = jb->eov_tn; header->eov_timestamp = jb->eov_timestamp; header->end_seqno = jb->end_seqno; # ifdef UNIX /* Keep header->strm_end_seqno[] uptodate as well if applicable */ if (INVALID_SUPPL_STRM != strm_index) { for (idx = 0; idx < MAX_SUPPL_STRMS; idx++) header->strm_end_seqno[idx] = jb->strm_end_seqno[idx]; } # endif JNL_DO_FILE_WRITE(csa, csd->jnl_file_name, jpc->channel, 0, header, read_write_size, jpc->status, jpc->status2); /* for abnormal status do not do anything. journal file header will have previous end_of_data */ } } jb->end_of_data = jb->freeaddr; jb->eov_tn = csa->ti->curr_tn; jb->eov_timestamp = jgbl.gbl_jrec_time; jb->end_seqno = epoch_record.jnl_seqno; # ifdef UNIX /* Keep header->strm_end_seqno[] uptodate as well if applicable */ if (INVALID_SUPPL_STRM != strm_index) { /* ROLLBACK turns off replication in mur_close_files and so we should never come here with csd->repl_state * indicating replication is allowed (for ROLLBACK). The only exception is if we are done with ROLLBACK, * but invoked gds_rundown (from mur_close_files) in which case repl_state will be turned back ON by * mur_close_files (process_exiting = TRUE). Assert accordingly */ assert(!jgbl.mur_rollback || !REPL_ALLOWED(csd) || process_exiting); assert(jgbl.mur_rollback || REPL_ALLOWED(csd)); for (idx = 0; idx < MAX_SUPPL_STRMS; idx++) jb->strm_end_seqno[idx] = csd->strm_reg_seqno[idx]; } # endif epoch_record.filler = 0; epoch_record.prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&epoch_record, SIZEOF(struct_jrec_epoch)); jnl_write(jpc, JRT_EPOCH, (jnl_record *)&epoch_record, NULL, NULL); } fis-gtm-V6.0-003/sr_port/jnl_write_inctn_rec.c0000644000032200000250000000645212201176160020222 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #ifdef VMS #include /* Required for gtmsource.h */ #endif #include "gtm_inet.h" #include "gtm_time.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "jnl_write.h" #include "repl_msg.h" #include "gtmsource.h" #include "jnl_get_checksum.h" GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; GBLREF jnl_gbls_t jgbl; GBLREF inctn_opcode_t inctn_opcode; GBLREF inctn_detail_t inctn_detail; /* holds detail to fill in to inctn jnl record */ void jnl_write_inctn_rec(sgmnt_addrs *csa) { struct_jrec_inctn inctn_record; jnl_private_control *jpc; DEBUG_ONLY(int inctn_detail_size;) assert(csa->now_crit); jpc = csa->jnl; assert(0 != jpc->pini_addr); assert((csa->ti->early_tn == csa->ti->curr_tn) || (csa->ti->early_tn == csa->ti->curr_tn + 1)); inctn_record.prefix.jrec_type = JRT_INCTN; inctn_record.prefix.forwptr = INCTN_RECLEN; assert(&inctn_detail.blknum_struct.suffix == &inctn_detail.blks2upgrd_struct.suffix); DEBUG_ONLY(inctn_detail_size = OFFSETOF(inctn_detail_blknum_t, suffix) + SIZEOF(inctn_detail.blknum_struct.suffix);) assert(0 == (inctn_detail_size % JNL_REC_START_BNDRY)); assert(SIZEOF(inctn_detail) == inctn_detail_size); inctn_detail.blknum_struct.suffix.backptr = INCTN_RECLEN; inctn_detail.blknum_struct.suffix.suffix_code = JNL_REC_SUFFIX_CODE; inctn_record.prefix.pini_addr = (0 == jpc->pini_addr) ? JNL_HDR_LEN : jpc->pini_addr; /* At this point jgbl.gbl_jrec_time should be set by the caller */ assert(jgbl.gbl_jrec_time); inctn_record.prefix.time = jgbl.gbl_jrec_time; inctn_record.prefix.tn = csa->ti->curr_tn; inctn_record.prefix.checksum = INIT_CHECKSUM_SEED; assert((inctn_opcode_total > inctn_opcode) && (inctn_invalid_op < inctn_opcode)); /* Assert that the maximum inctn opcode # will fit in the "opcode" field in the inctn jnl record. * But before that, assert opcode is at same offset in all the individual inctn_detail_* structure types. */ assert(&inctn_detail.blknum_struct.opcode == &inctn_detail.blks2upgrd_struct.opcode); assert(inctn_opcode_total < (1 << (8 * SIZEOF(inctn_detail.blknum_struct.opcode)))); inctn_detail.blknum_struct.opcode = inctn_opcode; /* fill in opcode from the global variable */ /* Instead of having a multi-line switch statement that copies exactly those fields which are necessary, we * copy the entire structure (16 bytes at this point). Pipeline breaks are considered more costly than a few * unnecessary memory-to-memory copies. */ inctn_detail.blknum_struct.filler_uint4 = 0; inctn_detail.blknum_struct.filler_short = 0; inctn_record.detail = inctn_detail; inctn_record.prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&inctn_record, SIZEOF(struct_jrec_inctn)); jnl_write(jpc, JRT_INCTN, (jnl_record *)&inctn_record, NULL, NULL); } fis-gtm-V6.0-003/sr_port/jnl_write_logical.c0000644000032200000250000000723512201176160017670 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_inet.h" #ifdef VMS #include /* Required for gtmsource.h */ #endif #include "gtm_time.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "jnl_write.h" #include "repl_msg.h" #include "gtmsource.h" #include "iosp.h" #include "jnl_get_checksum.h" #ifdef DEBUG #include "jnl_typedef.h" #endif GBLREF jnl_fence_control jnl_fence_ctl; GBLREF uint4 dollar_tlevel; GBLREF jnlpool_ctl_ptr_t temp_jnlpool_ctl; GBLREF jnl_gbls_t jgbl; GBLREF seq_num seq_num_zero; /* This called for TP and non-TP, but not for ZTP */ void jnl_write_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb, uint4 com_csum) { struct_jrec_upd *jrec; struct_jrec_null *jrec_null; GTMCRYPT_ONLY( struct_jrec_upd *jrec_alt; ) jnl_private_control *jpc; /* If REPL_WAS_ENABLED(csa) is TRUE, then we would not have gone through the code that initializes * jgbl.gbl_jrec_time or jpc->pini_addr. But in this case, we are not writing the journal record * to the journal buffer or journal file but write it only to the journal pool from where it gets * sent across to the update process that does not care about these fields so it is ok to leave them as is. */ jpc = csa->jnl; assert((0 != jpc->pini_addr) || REPL_WAS_ENABLED(csa)); assert(jgbl.gbl_jrec_time || REPL_WAS_ENABLED(csa)); assert(csa->now_crit); assert(IS_SET_KILL_ZKILL_ZTRIG_ZTWORM(jfb->rectype) || (JRT_NULL == jfb->rectype)); assert(!IS_ZTP(jfb->rectype)); jrec = (struct_jrec_upd *)jfb->buff; assert(OFFSETOF(struct_jrec_null, prefix) == OFFSETOF(struct_jrec_upd, prefix)); assert(SIZEOF(jrec_null->prefix) == SIZEOF(jrec->prefix)); jrec->prefix.pini_addr = (0 == jpc->pini_addr) ? JNL_HDR_LEN : jpc->pini_addr; jrec->prefix.tn = csa->ti->curr_tn; jrec->prefix.time = jgbl.gbl_jrec_time; /* t_end/tp_tend/mur_output_record has already set token/jnl_seqno into jnl_fence_ctl.token */ assert((0 != jnl_fence_ctl.token) || (!dollar_tlevel && !jgbl.forw_phase_recovery && !REPL_ENABLED(csa)) || (!dollar_tlevel && jgbl.forw_phase_recovery && (repl_open != csa->hdr->intrpt_recov_repl_state))); assert(OFFSETOF(struct_jrec_null, jnl_seqno) == OFFSETOF(struct_jrec_upd, token_seq)); assert(SIZEOF(jrec_null->jnl_seqno) == SIZEOF(jrec->token_seq)); jrec->token_seq.token = jnl_fence_ctl.token; assert(OFFSETOF(struct_jrec_null, strm_seqno) == OFFSETOF(struct_jrec_upd, strm_seqno)); assert(SIZEOF(jrec_null->strm_seqno) == SIZEOF(jrec->strm_seqno)); jrec->strm_seqno = jnl_fence_ctl.strm_seqno; /*update checksum below*/ if(JRT_NULL != jrec->prefix.jrec_type) { COMPUTE_LOGICAL_REC_CHECKSUM(jfb->checksum, jrec, com_csum, jrec->prefix.checksum); } else jrec->prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)jrec, SIZEOF(struct_jrec_null)); # ifdef GTM_CRYPT if (csa->hdr->is_encrypted && REPL_ALLOWED(csa)) { jrec_alt = (struct_jrec_upd *)jfb->alt_buff; jrec_alt->prefix = jrec->prefix; jrec_alt->token_seq = jrec->token_seq; jrec_alt->strm_seqno = jrec->strm_seqno; jrec_alt->num_participants = jrec->num_participants; } # endif JNL_WRITE_APPROPRIATE(csa, jpc, jfb->rectype, (jnl_record *)jrec, NULL, jfb); } fis-gtm-V6.0-003/sr_port/jnl_write_pblk.c0000644000032200000250000000560612201176160017206 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "gtm_string.h" #include "gtm_time.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "filestruct.h" #include "gdscc.h" #include "jnl.h" #include "jnl_write.h" #include "jnl_write_pblk.h" #include "min_max.h" #include "jnl_get_checksum.h" GBLREF jnl_gbls_t jgbl; GBLREF boolean_t dse_running; void jnl_write_pblk(sgmnt_addrs *csa, cw_set_element *cse, blk_hdr_ptr_t buffer, uint4 com_csum) { struct_jrec_blk pblk_record; int tmp_jrec_size, jrec_size, zero_len; jnl_format_buffer blk_trailer; char local_buff[JNL_REC_START_BNDRY + JREC_SUFFIX_SIZE]; jrec_suffix *suffix; jnl_private_control *jpc; assert(csa->now_crit); jpc = csa->jnl; assert(0 != jpc->pini_addr); pblk_record.prefix.jrec_type = JRT_PBLK; pblk_record.prefix.pini_addr = (0 == jpc->pini_addr) ? JNL_HDR_LEN : jpc->pini_addr; pblk_record.prefix.tn = csa->ti->curr_tn; /* At this point jgbl.gbl_jrec_time should be set by the caller */ assert(jgbl.gbl_jrec_time); pblk_record.prefix.time = jgbl.gbl_jrec_time; pblk_record.blknum = cse->blk; /* in case we have a bad block-size, we dont want to write a PBLK larger than the GDS block size (maximum block size). * in addition, check that checksum computed in t_end/tp_tend did take the adjusted bsiz into consideration. */ assert(buffer->bsiz <= csa->hdr->blk_size || dse_running); pblk_record.bsiz = MIN(csa->hdr->blk_size, buffer->bsiz); assert((pblk_record.bsiz == buffer->bsiz) || (cse->blk_checksum == jnl_get_checksum((uint4 *)buffer, NULL, pblk_record.bsiz))); assert(pblk_record.bsiz >= SIZEOF(blk_hdr) || dse_running); pblk_record.ondsk_blkver = cse->ondsk_blkver; tmp_jrec_size = (int)FIXED_PBLK_RECLEN + pblk_record.bsiz + JREC_SUFFIX_SIZE; jrec_size = ROUND_UP2(tmp_jrec_size, JNL_REC_START_BNDRY); zero_len = jrec_size - tmp_jrec_size; blk_trailer.buff = local_buff + (JNL_REC_START_BNDRY - zero_len); memset(blk_trailer.buff, 0, zero_len); blk_trailer.record_size = zero_len + JREC_SUFFIX_SIZE; suffix = (jrec_suffix *)&local_buff[JNL_REC_START_BNDRY]; pblk_record.prefix.forwptr = suffix->backptr = jrec_size; COMPUTE_PBLK_CHECKSUM(cse->blk_checksum, &pblk_record, com_csum, pblk_record.prefix.checksum); suffix->suffix_code = JNL_REC_SUFFIX_CODE; assert(SIZEOF(uint4) == SIZEOF(jrec_suffix)); jnl_write(jpc, JRT_PBLK, (jnl_record *)&pblk_record, buffer, &blk_trailer); } fis-gtm-V6.0-003/sr_port/jnl_write_pblk.h0000644000032200000250000000131112201176160017200 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __JNL_WRITE_PBLK_H__ #define __JNL_WRITE_PBLK_H__ /* We do not put this in jnl.h, because it needs all including jnl.h must include gdsblk.h */ void jnl_write_pblk(sgmnt_addrs *csa, cw_set_element *cse, blk_hdr_ptr_t buffer, uint4 com_csum); #endif fis-gtm-V6.0-003/sr_port/jnl_write_poolonly.c0000644000032200000250000000733012201176160020125 0ustar librarygtc/**************************************************************** * * * Copyright 2007, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_inet.h" #include /* for offsetof() macro */ #ifdef VMS #include /* Required for gtmsource.h */ #endif #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "filestruct.h" #include "ccp.h" #include "iosp.h" #include "jnl.h" #include "repl_msg.h" #include "gtmsource.h" #include "min_max.h" #include "sleep_cnt.h" #include "jnl_write.h" #include "copy.h" GBLREF jnlpool_ctl_ptr_t temp_jnlpool_ctl; GBLREF uint4 process_id; GBLREF sm_uc_ptr_t jnldata_base; GBLREF jnlpool_addrs jnlpool; GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; GBLREF jnl_gbls_t jgbl; /* This function does a subset of what "jnl_write" does. While "jnl_write" writes the journal record to the journal buffer, * journal file and journal pool, this function writes the journal records ONLY TO the journal pool. This function should * be invoked only if replication state is WAS_ON (repl_was_open) and journaling state is jnl_closed. * * jpc : Journal private control * rectype : Record type * jnl_rec : This contains fixed part of a variable size record or the complete fixed size records. * jfb : For SET/KILL/ZKILL records entire record is formatted in this. */ void jnl_write_poolonly(jnl_private_control *jpc, enum jnl_record_type rectype, jnl_record *jnl_rec, jnl_format_buffer *jfb) { int4 align_rec_len, rlen, rlen_with_align, srclen, dstlen; jnl_buffer_ptr_t jb; sgmnt_addrs *csa; struct_jrec_align align_rec; uint4 status; jrec_suffix suffix; boolean_t nowrap; struct_jrec_blk *jrec_blk; uint4 jnlpool_size; uchar_ptr_t jnlrecptr; DEBUG_ONLY(uint4 lcl_dskaddr;) uchar_ptr_t tmp_buff; error_def(ERR_JNLWRTNOWWRTR); error_def(ERR_JNLWRTDEFER); assert(NULL != jnl_rec); assert(rectype > JRT_BAD && rectype < JRT_RECTYPES && JRT_ALIGN != rectype); assert(jrt_is_replicated[rectype]); assert((NULL != jnlpool.jnlpool_ctl) && (NULL != jnlpool_ctl)); /* ensure we haven't yet detached from the jnlpool */ assert((&FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs)->now_crit); /* ensure we have the jnl pool lock */ csa = &FILE_INFO(jpc->region)->s_addrs; assert(!JNL_ENABLED(csa) && REPL_WAS_ENABLED(csa)); assert(csa->now_crit || (csa->hdr->clustered && csa->nl->ccp_state == CCST_CLOSED)); jb = jpc->jnl_buff; ++jb->reccnt[rectype]; rlen = jnl_rec->prefix.forwptr; assert(0 == rlen % JNL_REC_START_BNDRY); jb->bytcnt += rlen; DEBUG_ONLY(jgbl.cu_jnl_index++;) jnlpool_size = temp_jnlpool_ctl->jnlpool_size; dstlen = jnlpool_size - temp_jnlpool_ctl->write; if (jrt_fixed_size[rectype]) jnlrecptr = (uchar_ptr_t)jnl_rec; # ifdef GTM_CRYPT else if(csa->hdr->is_encrypted && IS_SET_KILL_ZKILL_ZTRIG_ZTWORM(rectype)) jnlrecptr = (uchar_ptr_t)jfb->alt_buff; # endif else jnlrecptr = (uchar_ptr_t)jfb->buff; if (rlen <= dstlen) /* dstlen & srclen >= rlen (most frequent case) */ memcpy(jnldata_base + temp_jnlpool_ctl->write, jnlrecptr, rlen); else /* dstlen < rlen <= srclen */ { memcpy(jnldata_base + temp_jnlpool_ctl->write, jnlrecptr, dstlen); memcpy(jnldata_base, jnlrecptr + dstlen, rlen - dstlen); } temp_jnlpool_ctl->write += rlen; if (temp_jnlpool_ctl->write >= jnlpool_size) temp_jnlpool_ctl->write -= jnlpool_size; } fis-gtm-V6.0-003/sr_port/jnl_write_trunc_rec.c0000644000032200000250000000354612201176160020243 0ustar librarygtc/**************************************************************** * * * Copyright 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #ifdef VMS #include /* Required for gtmsource.h */ #endif #include "gtm_inet.h" #include "gtm_time.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "jnl_write.h" #include "repl_msg.h" #include "gtmsource.h" #include "jnl_get_checksum.h" GBLREF jnl_gbls_t jgbl; GBLREF sgmnt_data_ptr_t cs_data; GBLREF gd_region *gv_cur_region; void jnl_write_trunc_rec(sgmnt_addrs *csa, uint4 orig_total_blks, uint4 orig_free_blocks, uint4 total_blks_after_trunc) { struct_jrec_trunc trunc_rec; jnl_private_control *jpc; assert(csa->now_crit); jpc = csa->jnl; trunc_rec.prefix.jrec_type = JRT_TRUNC; trunc_rec.prefix.forwptr = trunc_rec.suffix.backptr = TRUNC_RECLEN; trunc_rec.prefix.tn = csa->ti->curr_tn; trunc_rec.suffix.suffix_code = JNL_REC_SUFFIX_CODE; trunc_rec.prefix.time = jgbl.gbl_jrec_time; trunc_rec.prefix.checksum = INIT_CHECKSUM_SEED; trunc_rec.prefix.pini_addr = (0 == jpc->pini_addr) ? JNL_HDR_LEN : jpc->pini_addr; trunc_rec.orig_total_blks = orig_total_blks; trunc_rec.orig_free_blocks = orig_free_blocks; trunc_rec.total_blks_after_trunc = total_blks_after_trunc; trunc_rec.prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&trunc_rec, SIZEOF(struct_jrec_trunc)); jnl_write(jpc, JRT_TRUNC, (jnl_record *)&trunc_rec, NULL, NULL); } fis-gtm-V6.0-003/sr_port/jnl_write_ztp_logical.c0000644000032200000250000000565112201176160020565 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_inet.h" #ifdef VMS #include /* Required for gtmsource.h */ #endif #include "gtm_time.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsblk.h" #include "gdsfhead.h" #include "filestruct.h" #include "jnl.h" #include "jnl_write.h" #include "repl_msg.h" #include "gtmsource.h" #include "iosp.h" #include "jnl_get_checksum.h" #ifdef DEBUG #include "jnl_typedef.h" #endif GBLREF jnl_fence_control jnl_fence_ctl; GBLREF jnlpool_ctl_ptr_t temp_jnlpool_ctl; GBLREF jnl_gbls_t jgbl; GBLREF seq_num seq_num_zero; GBLREF trans_num local_tn; /* transaction number for THIS PROCESS */ GBLREF uint4 process_id; void jnl_write_ztp_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb, uint4 com_csum) { struct_jrec_upd *jrec; volatile seq_num temp_seqno; GTMCRYPT_ONLY( struct_jrec_upd *jrec_alt; ) jnl_private_control *jpc; /* If REPL_WAS_ENABLED(csa) is TRUE, then we would not have gone through the code that initializes * jgbl.gbl_jrec_time or jpc->pini_addr. But in this case, we are not writing the journal record * to the journal buffer or journal file but write it only to the journal pool from where it gets * sent across to the update process that does not care about these fields so it is ok to leave them as is. */ jpc = csa->jnl; assert((0 != jpc->pini_addr) || REPL_WAS_ENABLED(csa)); assert(jgbl.gbl_jrec_time || REPL_WAS_ENABLED(csa)); assert(csa->now_crit); assert(IS_SET_KILL_ZKILL_ZTRIG(jfb->rectype)); assert(IS_ZTP(jfb->rectype)); jrec = (struct_jrec_upd *)jfb->buff; jrec->prefix.pini_addr = (0 == jpc->pini_addr) ? JNL_HDR_LEN : jpc->pini_addr; jrec->prefix.tn = csa->ti->curr_tn; jrec->prefix.time = jgbl.gbl_jrec_time; temp_seqno = temp_jnlpool_ctl->jnl_seqno; if (QWEQ(jnl_fence_ctl.token, seq_num_zero)) { /* generate token once after op_ztstart and use for all its mini-transactions * jnl_fence_ctl.token is set to seq_num_zero in op_ztstart */ if (REPL_ALLOWED(csa)) QWASSIGN(jnl_fence_ctl.token, temp_seqno); else { TOKEN_SET(&jnl_fence_ctl.token, local_tn, process_id); } } assert(0 != jnl_fence_ctl.token); jrec->token_seq.token = jnl_fence_ctl.token; jrec->strm_seqno = 0; /* strm_seqno is only for replication & ZTCOM does not work with replic */ COMPUTE_LOGICAL_REC_CHECKSUM(jfb->checksum, jrec, com_csum, jrec->prefix.checksum); GTMCRYPT_ONLY(assert(!REPL_ALLOWED(csa));) JNL_WRITE_APPROPRIATE(csa, jpc, jfb->rectype, (jnl_record *)jrec, NULL, jfb); } fis-gtm-V6.0-003/sr_port/jnlpool_hasnt_overflowed.c0000644000032200000250000000362212201176160021303 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2004 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "memcoherency.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "repl_msg.h" #ifdef VMS #include #endif #include "gtmsource.h" boolean_t jnlpool_hasnt_overflowed(jnlpool_ctl_ptr_t jctl, uint4 jnlpool_size, qw_num read_addr) { /* the advantage of passing the three arguments is they are likely (on most platforms) to be scratch registers that can also * be used for computation. Also, besides all callers would have already loaded jctl and jnlpool_size */ /* For systems with UNORDERED memory access (example, ALPHA, POWER4, PA-RISC 2.0), on a multi processor system, it is * possible that the source server notices the change in jnlpool_ctl->write_addr before seeing the change to the content * to be read (including the jnl_data_header). To avoid such conditions, we should commit the order of shared memory * updates before and after the content is updated (see t_end.c, tp_tend.c). To ensure the source server reads content * that is correct, it should invalidate its cache before the read. After the read, to ensure that the content is correct * (not some that may have been overwritten), it has to invalidate its cache to fetch the latest value of early_write_addr. * */ SHM_READ_MEMORY_BARRIER; /* to fetch the latest early_write_addr */ return (jnlpool_size >= (jctl->early_write_addr - read_addr)); } fis-gtm-V6.0-003/sr_port/job.h0000644000032200000250000000105512201176160014752 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __JOB_H_ #define __JOB_H_ int4 ojchkfs(char *addr, int4 len, bool exist); #include "jobsp.h" #endif fis-gtm-V6.0-003/sr_port/job_addr.c0000644000032200000250000000331712201176177015752 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "cmd_qlf.h" #include #include "op.h" #include "job_addr.h" #include "zbreak.h" error_def(ERR_JOBLABOFF); boolean_t job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr) { rhdtyp *rt_hdr; int4 *lp; mval rt; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (NULL == (rt_hdr = find_rtn_hdr(rtn))) { rt.mvtype = MV_STR; rt.str = *rtn; op_zlink(&rt, NULL); assertpro(NULL != (rt_hdr = find_rtn_hdr(rtn))); } lp = NULL; if ((rt_hdr->compiler_qlf & CQ_LINE_ENTRY) || (0 == offset)) /* Label offset with routine compiled with NOLINE_ENTRY should cause error. */ lp = find_line_addr(rt_hdr, label, offset, NULL); if (!lp) return (FALSE); /* Set the pointer to address / offset for line number entry storage in lab_proxy. */ USHBIN_ONLY((TREF(lab_proxy)).lnr_adr = lp;) /* On non-shared-binary, calculcate the offset to the corresponding lnr_tabent record by subtracting * the base address (routine header) from line number entry's address, and save the result in * lab_ln_ptr field of lab_tabent structure. */ NON_USHBIN_ONLY((TREF(lab_proxy)).lab_ln_ptr = ((int4)lp - (int4)rt_hdr)); if (NULL != labaddr) *labaddr = (char *)LINE_NUMBER_ADDR(rt_hdr, lp); *hdr = (char *)rt_hdr; return (TRUE); } fis-gtm-V6.0-003/sr_port/job_addr.h0000644000032200000250000000111712201176160015743 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __JOB_ADDR_H_ #define __JOB_ADDR_H_ boolean_t job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr); #endif fis-gtm-V6.0-003/sr_port/jobexam_process.c0000644000032200000250000002232112201176177017365 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include #include "gtm_unistd.h" #include "gtm_string.h" #include "gtm_stdio.h" #include "error.h" #include "io_params.h" #include "op.h" #include "io.h" #include #include "stack_frame.h" #include "jobexam_process.h" #ifdef UNIX # include "jobexam_signal_handler.h" #endif #include "send_msg.h" #include "callg.h" #include "zshow.h" #include "util.h" #include "mv_stent.h" #define DEFAULT_DUMP_FILENAME "GTM_JOBEXAM.ZSHOW_DMP" #define NOCONCEAL_OPTION "NO_CONCEAL" static readonly mval empty_str_mval = DEFINE_MVAL_LITERAL(MV_STR, 0, 0, 0, 0, 0, 0); static readonly mval no_conceal_op = DEFINE_MVAL_LITERAL(MV_STR, 0, 0, SIZEOF(NOCONCEAL_OPTION) - 1, NOCONCEAL_OPTION, 0, 0); static unsigned char dumpable_error_dump_file_parms[2] = {iop_newversion, iop_eol}; static unsigned char dumpable_error_dump_file_noparms[1] = {iop_eol}; static unsigned int jobexam_counter; GBLREF uint4 process_id; GBLREF io_pair io_std_device, io_curr_device; GBLREF mv_stent *mv_chain; GBLREF unsigned char *msp, *stackwarn, *stacktop; GBLREF boolean_t created_core; UNIX_ONLY(GBLREF sigset_t blockalrm;) DEBUG_ONLY(GBLREF boolean_t ok_to_UNWIND_in_exit_handling;) error_def(ERR_GTMASSERT); error_def(ERR_GTMASSERT2); error_def(ERR_GTMCHECK); error_def(ERR_JOBEXAMDONE); error_def(ERR_JOBEXAMFAIL); error_def(ERR_MEMORY); error_def(ERR_OUTOFSPACE); error_def(ERR_STACKCRIT); error_def(ERR_STACKOFLOW); error_def(ERR_VMSMEMORY); void jobexam_process(mval *dump_file_name, mval *dump_file_spec) { mval *input_dump_file_name; io_pair dev_in_use; mv_stent *new_mv_stent; boolean_t saved_mv_stent; char saved_util_outbuff[OUT_BUFF_SIZE]; int saved_util_outbuff_len; # ifdef UNIX struct sigaction new_action, prev_action; sigset_t savemask; # endif DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; /* If the input file name is the result of an expression, it is likely being held in the * same temporary as the output file spec. We can tell if this is true by comparing the * address of the input and output mvals. If they are the same, make a copy of the input * filespec in a garbage collection safe mval prior to initializing the output mval * (which in this case would clear the input mval as well if it had not just been saved). */ if (dump_file_name == dump_file_spec) { /* Make saved copy of input mval */ PUSH_MV_STENT(MVST_MVAL); new_mv_stent = mv_chain; input_dump_file_name = &mv_chain->mv_st_cont.mvs_mval; *input_dump_file_name = *dump_file_name; saved_mv_stent = TRUE; } else { /* Just use input mval as-is */ input_dump_file_name = dump_file_name; saved_mv_stent = FALSE; } # ifdef UNIX /* Block out timer calls that might trigger processing that could fail. We especially want to prevent * nesting of signal handlers since the longjump() function used by the UNWIND macro is undefined on * Tru64 when signal handlers are nested. */ sigprocmask(SIG_BLOCK, &blockalrm, &savemask); /* Setup new signal handler to just drive condition handler which will do the right thing */ memset(&new_action, 0, SIZEOF(new_action)); sigemptyset(&new_action.sa_mask); new_action.sa_flags = SA_SIGINFO; # ifdef __sparc new_action.sa_handler = jobexam_signal_handler; # else new_action.sa_sigaction = jobexam_signal_handler; # endif sigaction(SIGBUS, &new_action, &prev_action); sigaction(SIGSEGV, &new_action, 0); # endif *dump_file_spec = empty_str_mval; dev_in_use = io_curr_device; /* Save current IO device */ /* Save text in util_outbuff which can be detrimentally overwritten by ZSHOW. * NOTE: The following code needs to be eventually moved to jobinterrupt_process.c and replaced with * SAVE/RESTORE_UTIL_OUT_BUFFER macros, as follows: * * char *save_util_outptr; * va_list save_last_va_list_ptr; * boolean_t util_copy_saved = FALSE; * DCL_THREADGBL_ACCESS; * * SETUP_THREADGBL_ACCESS; * ... * SAVE_UTIL_OUT_BUFFER(save_util_outptr, save_last_va_list_ptr, util_copy_saved); * ... * RESTORE_UTIL_OUT_BUFFER(save_util_outptr, save_last_va_list_ptr, util_copy_saved); */ saved_util_outbuff_len = 0; if (NULL == TREF(util_outptr)) TREF(util_outptr) = TREF(util_outbuff_ptr); if (0 != (saved_util_outbuff_len = (int)(TREF(util_outptr) - TREF(util_outbuff_ptr)))) /* Caution -- assignment */ { assert(0 <= saved_util_outbuff_len); assert(saved_util_outbuff_len <= SIZEOF(saved_util_outbuff)); memcpy(saved_util_outbuff, TREF(util_outbuff_ptr), saved_util_outbuff_len); } jobexam_dump(input_dump_file_name, dump_file_spec); /* If any errors occur in job_exam_dump, the condition handler will unwind the stack to this point and return. */ if (0 != saved_util_outbuff_len) { /* Restore util_outbuff values */ memcpy(TREF(util_outbuff_ptr), saved_util_outbuff, saved_util_outbuff_len); TREF(util_outptr) = TREF(util_outbuff_ptr) + saved_util_outbuff_len; } io_curr_device = dev_in_use; /* Restore IO device */ /* If we saved an mval on our stack, we need to pop it off. If there was an error while doing the * jobexam dump, zshow may have left some other mv_stent entries on the stack. Pop them all off with * just a regular POP_MV_STENT macro rather than unw_mv_ent() call because the mv_stent entries * created in zshow_output reference automatic storage that cannot be referenced at this stack * level without potential (C) stack corruption. */ if (saved_mv_stent) { assertpro(mv_chain <= new_mv_stent); /* This violates our assumptions that the mv_stent we pushed onto the * stack should still be there */ while (mv_chain <= new_mv_stent) { POP_MV_STENT(); } } # ifdef UNIX /* Restore the signal handlers how they were */ sigaction(SIGBUS, &prev_action, 0); sigaction(SIGSEGV, &prev_action, 0); /* Let the timers pop again.. */ sigprocmask(SIG_SETMASK, &savemask, NULL); # endif } /* This routine is broken out as another ep so we can do cleanup processing in jobexam_process if we trigger the condition handler and unwind. */ void jobexam_dump(mval *dump_filename_arg, mval *dump_file_spec) { unsigned char dump_file_name[50], *dump_file_name_ptr; mval def_file_name, parms, zshowall; ESTABLISH(jobexam_dump_ch); ++jobexam_counter; /* Setup default filename/type to use for the parse. Append processid and a counter. */ MEMCPY_LIT(dump_file_name, DEFAULT_DUMP_FILENAME); dump_file_name_ptr = dump_file_name + SIZEOF(DEFAULT_DUMP_FILENAME) - 1; *dump_file_name_ptr++ = '_'; dump_file_name_ptr = i2asc(dump_file_name_ptr, process_id); *dump_file_name_ptr++ = '_'; dump_file_name_ptr = i2asc(dump_file_name_ptr, jobexam_counter); def_file_name.mvtype = MV_STR; def_file_name.str.addr = (char *)dump_file_name; def_file_name.str.len = INTCAST(dump_file_name_ptr - dump_file_name); /* Call $ZPARSE processing to fill in any blanks, expand concealed logicals, etc. It is the callers * responsibility to make sure garbage collection knows about the value in the returned filespec. */ op_fnzparse(dump_filename_arg, &empty_str_mval, &def_file_name, &empty_str_mval, &no_conceal_op, dump_file_spec); /* Parms of file to be created (newversion) */ parms.mvtype = MV_STR; parms.str.addr = (char *)dumpable_error_dump_file_parms; parms.str.len = SIZEOF(dumpable_error_dump_file_parms); /* Open, use, and zshow into new file, then close and reset current io device */ op_open(dump_file_spec, &parms, 0, 0); op_use(dump_file_spec, &parms); zshowall.mvtype = MV_STR; zshowall.str.addr = "*"; zshowall.str.len = 1; op_zshow(&zshowall, ZSHOW_DEVICE, NULL); parms.str.addr = (char *)dumpable_error_dump_file_noparms; parms.str.len = SIZEOF(dumpable_error_dump_file_noparms); op_close(dump_file_spec, &parms); /* Notify operator dump was taken */ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_JOBEXAMDONE, 3, process_id, dump_file_spec->str.len, dump_file_spec->str.addr); REVERT; } CONDITION_HANDLER(jobexam_dump_ch) { boolean_t save_created_core; START_CH; /* Operation: * 1) Flush out message we came here because of to operator console * 2) Put out our message stating that we screwed up * 3) Unwind the errant frames so we can return to the user without screwing * up the task that got interrupted to do this examine. */ # if defined(DEBUG) && defined(UNIX) if (DUMPABLE) { /* For debug UNIX issues, let's make a core if we would have made one in open code */ save_created_core = created_core; gtm_fork_n_core(); created_core = save_created_core; } # endif UNIX_ONLY(util_out_print(0, OPER)); VMS_ONLY(sig->chf$l_sig_args -= 2); VMS_ONLY(callg(send_msg, &sig->chf$l_sig_args)); send_msg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_JOBEXAMFAIL, 1, process_id); /* Stop the errors here and return to caller */ UNIX_ONLY(util_out_print("", RESET)); /* Prevent rts_error from flushing this error later */ DEBUG_ONLY(ok_to_UNWIND_in_exit_handling = TRUE); UNWIND(NULL, NULL); } fis-gtm-V6.0-003/sr_port/jobexam_process.h0000644000032200000250000000122112201176160017356 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef JOBEXAM_PROCESS_INCLUDED #define JOBEXAM_PROCESS_INCLUDED void jobexam_process(mval *dump_file_name, mval *dump_file_spec); void jobexam_dump(mval *dump_file_name, mval *dump_file_spec); #endif fis-gtm-V6.0-003/sr_port/jobinterrupt_event.c0000644000032200000250000000474212201176160020131 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* job interrupt event - an interrupt has been requested. - Call xfer_set_handlers so next M instruction traps to interrupt routine - Other required housecleaning for VMS. */ #include "mdef.h" #ifdef UNIX # include #else # include # include "efn.h" #endif #ifdef GTM_PTHREAD # include #endif #include "gtm_stdio.h" #include "io.h" #include "op.h" #include "xfer_enum.h" #include "outofband.h" #include "deferred_events.h" #include "jobinterrupt_event.h" #include "fix_xfer_entry.h" GBLREF xfer_entry_t xfer_table[]; GBLREF volatile int4 outofband; GBLREF volatile boolean_t dollar_zininterrupt; /* Routine called when an interrupt event occurs (signaled by mupip intrpt or other future method * of signaling interrupts). This code is driven as a signal handler on Unix and from the START_CH * macro on VMS where it intercepts the posix signal. */ UNIX_ONLY(void jobinterrupt_event(int sig, siginfo_t *info, void *context)) VMS_ONLY(void jobinterrupt_event(void)) { FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(sig); /* Note the (presently unused) args are to match signature for signal handlers in Unix */ if (!dollar_zininterrupt) (void)xfer_set_handlers(outofband_event, &jobinterrupt_set, 0); } /* Call back routine from xfer_set_handlers to complete outofband setup */ void jobinterrupt_set(int4 dummy_val) { # ifdef VMS int4 status; status = sys$setef(efn_outofband); assert(SS$_WASCLR == status); if ((SS$_WASCLR != status) && (SS$_WASSET != status)) GTMASSERT; # endif if (jobinterrupt != outofband) { /* We need jobinterrupt out of band processing at our earliest convenience */ outofband = jobinterrupt; FIX_XFER_ENTRY(xf_linefetch, op_fetchintrrpt); FIX_XFER_ENTRY(xf_linestart, op_startintrrpt); FIX_XFER_ENTRY(xf_zbfetch, op_fetchintrrpt); FIX_XFER_ENTRY(xf_zbstart, op_startintrrpt); FIX_XFER_ENTRY(xf_forchk1, op_startintrrpt); FIX_XFER_ENTRY(xf_forloop, op_forintrrpt); } VMS_ONLY(sys$wake(0,0)); } fis-gtm-V6.0-003/sr_port/jobinterrupt_event.h0000644000032200000250000000124512201176160020131 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef JOBINTR_EVENT_INCLUDED #define JOBINTR_EVENT_INCLUDED UNIX_ONLY(void jobinterrupt_event(int sig, siginfo_t *info, void *context);) VMS_ONLY(void jobinterrupt_event(void);) void jobinterrupt_set(int4 dummy); #endif fis-gtm-V6.0-003/sr_port/jobinterrupt_init.c0000644000032200000250000000530012201176160017742 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* job interrupt initialization. Accomplish following setups: - Setup handler for SIGUSR1 signal to be handled by jobinterrupt_event() (UNIX only). - Provide initial setting for $ZINTERRUPT from default or logical or environment variable if present. */ #include "mdef.h" #include #include "gtm_string.h" #include "gtm_stdio.h" #include "gtm_logicals.h" #include "trans_log_name.h" #include "io.h" #include "iosp.h" #include "stringpool.h" #include "jobinterrupt_init.h" #include "jobinterrupt_event.h" GBLREF mval dollar_zinterrupt; #define DEF_ZINTERRUPT "IF $ZJOBEXAM()" void jobinterrupt_init(void) { mstr envvar_logical; char trans_bufr[MAX_TRANS_NAME_LEN]; DCL_THREADGBL_ACCESS; #ifdef UNIX struct sigaction new_action; SETUP_THREADGBL_ACCESS; /* Setup new signal handler to just drive condition handler which will do the right thing. Note that although we use send a posix-style signal with mupip intrpt on VMS, the signal that comes in is NOT handled by posix signal handler because the posix handler is implemented using native condition handlers which interfere with GT.M's use of native condition handlers. The VMS signal is instead intercepted via the START_CH macro on VMS which then drives the jobinterrupt_event routine. */ memset(&new_action, 0, SIZEOF(new_action)); sigemptyset(&new_action.sa_mask); new_action.sa_flags = SA_SIGINFO; #ifdef __sparc new_action.sa_handler = jobinterrupt_event; #else new_action.sa_sigaction = jobinterrupt_event; #endif sigaction(SIGUSR1, &new_action, NULL); #else SETUP_THREADGBL_ACCESS; /* Handler for VMS setup via function pointer called by START_CH macro */ RFPTR(gtm_sigusr1_handler) = jobinterrupt_event; #endif /* Provide initial setting for $ZINTERRUPT */ envvar_logical.addr = GTM_ZINTERRUPT; envvar_logical.len = SIZEOF(GTM_ZINTERRUPT) - 1; if (SS_NORMAL != TRANS_LOG_NAME(&envvar_logical, &dollar_zinterrupt.str, trans_bufr, SIZEOF(trans_bufr), do_sendmsg_on_log2long)) { /* Translation failed - use default */ dollar_zinterrupt.str.addr = DEF_ZINTERRUPT; dollar_zinterrupt.str.len = SIZEOF(DEF_ZINTERRUPT) - 1; } else /* put value in stringpool if translation succeeded */ s2pool(&dollar_zinterrupt.str); dollar_zinterrupt.mvtype = MV_STR; return; } fis-gtm-V6.0-003/sr_port/jobinterrupt_init.h0000644000032200000250000000105612201176160017753 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef JOBINTR_PROCESS_INCLUDED #define JOBINTR_PROCESS_INCLUDED void jobinterrupt_init(void); #endif fis-gtm-V6.0-003/sr_port/jobinterrupt_process.c0000644000032200000250000001116612201176177020474 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "error.h" #include "indir_enum.h" #include #include "op.h" #include "stack_frame.h" #include "error_trap.h" #include "mv_stent.h" #include "gtm_stdio.h" #include "stringpool.h" #include "jobinterrupt_process.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "hashtab_int4.h" #include "gdskill.h" #include "jnl.h" #include "gdscc.h" #include "buddy_list.h" #include "tp.h" #include "gvname_info.h" #include "op_merge.h" #include "zwrite.h" #include "zshow.h" GBLREF stack_frame *frame_pointer, *error_frame; GBLREF unsigned char *stackbase, *stacktop, *msp, *stackwarn; GBLREF spdesc stringpool; GBLREF mval dollar_zinterrupt; GBLREF boolean_t dollar_zininterrupt; GBLREF unsigned short proc_act_type; GBLREF mv_stent *mv_chain; GBLREF int dollar_truth; GBLREF mstr extnam_str; GBLREF unsigned char *restart_pc, *restart_ctxt; GBLREF dollar_ecode_type dollar_ecode; GBLREF dollar_stack_type dollar_stack; GBLREF int merge_args; GBLREF uint4 zwrtacindx; GBLREF merge_glvn_ptr mglvnp; GBLREF gvzwrite_datablk *gvzwrite_block; GBLREF lvzwrite_datablk *lvzwrite_block; GBLREF zshow_out *zwr_output; GBLREF zwr_hash_table *zwrhtab; error_def(ERR_STACKOFLOW); error_def(ERR_STACKCRIT); void jobinterrupt_process(void) { mv_stent *mv_st_ent; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(dollar_zininterrupt); /* Compile and push new (counted) frame onto the stack to drive the * $zinterrupt handler. */ assert((SFT_COUNT | SFT_ZINTR) == proc_act_type); op_commarg(&dollar_zinterrupt, indir_linetail); frame_pointer->type = proc_act_type; /* The mark of zorro.. */ proc_act_type = 0; /* Save restart_pc/ctxt so a resumed frame or ztrap can resume in the corrct place and * not and inappropriate resume point determined by the interrupting code. */ PUSH_MV_STENT(MVST_RSTRTPC); mv_st_ent = mv_chain; mv_st_ent->mv_st_cont.mvs_rstrtpc.restart_pc_save = restart_pc; mv_st_ent->mv_st_cont.mvs_rstrtpc.restart_ctxt_save = restart_ctxt; /* Now we need to preserve our current environment. This MVST_ZINTR mv_stent type will hold * the items deemed necessary to preserve. All other items are the user's responsibility. * * Initialize the mv_stent elements processed by stp_gcol which can be called for either the * op_gvsavtarg() or extnam items. This initialization keeps stp_gcol from attempting to * process unset fields with garbage in them as valid mstr address/length pairs. */ PUSH_MV_STENT(MVST_ZINTR); mv_st_ent = mv_chain; mv_st_ent->mv_st_cont.mvs_zintr.savtarg.str.len = 0; mv_st_ent->mv_st_cont.mvs_zintr.savextref.len = 0; mv_st_ent->mv_st_cont.mvs_zintr.saved_dollar_truth = dollar_truth; op_gvsavtarg(&mv_st_ent->mv_st_cont.mvs_zintr.savtarg); if (extnam_str.len) { ENSURE_STP_FREE_SPACE(extnam_str.len); mv_st_ent->mv_st_cont.mvs_zintr.savextref.addr = (char *)stringpool.free; memcpy(mv_st_ent->mv_st_cont.mvs_zintr.savextref.addr, extnam_str.addr, extnam_str.len); stringpool.free += extnam_str.len; assert(stringpool.free <= stringpool.top); } mv_st_ent->mv_st_cont.mvs_zintr.savextref.len = extnam_str.len; /* save/restore $ECODE/$STACK over this invocation */ mv_st_ent->mv_st_cont.mvs_zintr.error_frame_save = error_frame; memcpy(&mv_st_ent->mv_st_cont.mvs_zintr.dollar_ecode_save, &dollar_ecode, SIZEOF(dollar_ecode)); memcpy(&mv_st_ent->mv_st_cont.mvs_zintr.dollar_stack_save, &dollar_stack, SIZEOF(dollar_stack)); NULLIFY_ERROR_FRAME; ecode_init(); /* If we interrupted a Merge, ZWrite, or ZShow, save the state info in an mv_stent that will be restored when this * interrupt frame returns. Note that at this time, return from an interrupt does not "return" to the interrupt * point but rather restarts the line of M code we were running *OR* at the most recent save point (set by * op_restartpc or equivalent). In the future this is likely to change, at least for an interrupted Merge, ZWrite * or ZShow command, so this save/restore is appropriate both now (to let these nest at all) and especially in the future. */ if (TREF(in_zwrite) || (0 != merge_args)) PUSH_MVST_MRGZWRSV; return; } fis-gtm-V6.0-003/sr_port/jobinterrupt_process.h0000644000032200000250000000164412201176160020471 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2003 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef JOBINTR_PROCESS_INCLUDED #define JOBINTR_PROCESS_INCLUDED #define JOBINTR_TP_RETHROW \ { /* rethrow job interrupt($ZINT) if $ZTEXIT is true and not already in $ZINTR */ \ GBLREF boolean_t dollar_zininterrupt; \ GBLREF boolean_t dollar_ztexit_bool; \ error_def(ERR_JOBINTRRETHROW); \ \ if (dollar_ztexit_bool && !dollar_zininterrupt) \ rts_error(VARLSTCNT(1) ERR_JOBINTRRETHROW); \ } void jobinterrupt_process(void); #endif fis-gtm-V6.0-003/sr_port/jobinterrupt_process_cleanup.c0000644000032200000250000000556412201176177022210 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include #include "stack_frame.h" #include "stringpool.h" #include "objlabel.h" #include "cache.h" #include "dm_setup.h" #include "error.h" #include "error_trap.h" #include "util.h" #include "gtm_string.h" #include "gtmmsg.h" #include "jobinterrupt_process_cleanup.h" GBLREF stack_frame *frame_pointer; GBLREF spdesc stringpool; GBLREF spdesc rts_stringpool; GBLREF unsigned short proc_act_type; GBLREF volatile boolean_t dollar_zininterrupt; GBLREF mval dollar_zstatus; GBLREF dollar_ecode_type dollar_ecode; /* structure containing $ECODE related information */ error_def(ERR_ERRWZINTR); /* Counterpart to trans_code_cleanup for job interrupt errors */ void jobinterrupt_process_cleanup(void) { stack_frame *fp; unsigned char msgbuf[OUT_BUFF_SIZE], *mbptr; unsigned char *zstptr; mstr msgbuff; int zstlen; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert((SFT_COUNT | SFT_ZINTR) == proc_act_type); assert(dollar_zininterrupt); if (TREF(compile_time)) { /* Make sure we are using the right stringpool */ TREF(compile_time) = FALSE; if (stringpool.base != rts_stringpool.base) stringpool = rts_stringpool; } proc_act_type = 0; /* Note, no frames are unwound as in trans_code_cleanup() because we should be able to resume exactly where we left off since (1) it was not an error that caused us to drive the $zinterrupt handler and (2) we were already on a nice statement boundary when we were called to run $zinterrupt. */ TREF(transform) = TRUE; dollar_zininterrupt = FALSE; /* No longer in a $zinterrupt */ /* Now build message for operator log with the form ERRWZINTR, compiler-error */ util_out_print(NULL, RESET); msgbuff.addr = (char *)msgbuf; msgbuff.len = SIZEOF(msgbuf); gtm_getmsg(ERR_ERRWZINTR, &msgbuff); mbptr = msgbuf + strlen((char *)msgbuf); /* Find the beginning of the compiler error (look for "%") */ zstptr = (unsigned char *)dollar_zstatus.str.addr; for (zstlen = dollar_zstatus.str.len; zstlen; zstptr++, zstlen--) { if ('%' == *zstptr) break; } if (zstlen) { /* If found some message, add it to our operator missive */ *mbptr++ = ','; *mbptr++ = ' '; memcpy(mbptr, zstptr, zstlen); mbptr += zstlen; } *mbptr++ = 0; util_out_print((caddr_t)msgbuf, OPER); if (NULL == dollar_ecode.error_last_b_line) { /* Was a direct mode frame this message needs to go out to the console */ dec_err(VARLSTCNT(1) ERR_ERRWZINTR); } } fis-gtm-V6.0-003/sr_port/jobinterrupt_process_cleanup.h0000644000032200000250000000111112201176160022165 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2002 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef JOBINTR_PROCESS_CLEANUP_INCLUDED #define JOBINTR_PROCESS_CLEANUP_INCLUDED void jobinterrupt_process_cleanup(void); #endif fis-gtm-V6.0-003/sr_port/jobparameters.c0000644000032200000250000000373712201176160017042 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" /* #include "opcode.h" */ #include "toktyp.h" #include "job.h" #include "advancewindow.h" error_def (ERR_RPARENMISSING); int jobparameters (oprtype *c) { char *parptr; /* This is a workaround for the moment. The former maximum size of the * parameter string was completely incapable of handling the variety * of string parameters that may be passed. To further compound things, * no checks exist to enforce upper limits on parameter string lengths. * This new maximum was reached by calculating the maximum length of * the job parameter string (presuming each possible qualifier is represented * once and only once) and tacking on a safety net. This came to * 10 255 byte strings (plus length byte), 1 longword, and 17 single byte * identifiers for each of the job keywords. The maximum of 3000 leaves * a little room for expansion in the future */ char parastr[3000]; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; parptr = parastr; if (TK_LPAREN != TREF(window_token)) { if (TK_COLON != TREF(window_token)) { if (!one_job_param (&parptr)) return FALSE; } } else { advancewindow (); for (;;) { if (!one_job_param (&parptr)) return FALSE; if (TK_COLON == TREF(window_token)) advancewindow (); else if (TK_RPAREN == TREF(window_token)) { advancewindow (); break; } else { stx_error (ERR_RPARENMISSING); return FALSE; } } } *parptr++ = jp_eol; *c = put_str (parastr,(mstr_len_t)(parptr - parastr)); return TRUE; } fis-gtm-V6.0-003/sr_port/jobparams.h0000644000032200000250000000213712201176160016160 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ JPDEF (jp_eol, jpdt_nul), JPDEF (jp_account, jpdt_nul), #ifdef UNIX JPDEF (jp_cmdline, jpdt_str), #endif JPDEF (jp_default, jpdt_str), JPDEF (jp_detached, jpdt_nul), JPDEF (jp_error, jpdt_str), JPDEF (jp_gbldir, jpdt_str), JPDEF (jp_image, jpdt_str), JPDEF (jp_input, jpdt_str), JPDEF (jp_logfile, jpdt_str), JPDEF (jp_noaccount, jpdt_nul), JPDEF (jp_nodetached, jpdt_nul), JPDEF (jp_noswapping, jpdt_nul), JPDEF (jp_output, jpdt_str), JPDEF (jp_priority, jpdt_num), JPDEF (jp_process_name, jpdt_str), JPDEF (jp_schedule, jpdt_str), JPDEF (jp_startup, jpdt_str), JPDEF (jp_swapping, jpdt_nul), JPDEF (jp_nmvals, jpdt_nul) fis-gtm-V6.0-003/sr_port/jobparamstrs.h0000644000032200000250000000336612201176160016716 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ JPSDEF ( 3, "ACC", jp_account), JPSDEF ( 8, "ACCOUNTI*", jp_account), #ifdef UNIX JPSDEF ( 3, "CMD", jp_cmdline), JPSDEF ( 7, "CMDLINE", jp_cmdline), #endif JPSDEF ( 3, "DEF", jp_default), JPSDEF ( 7, "DEFAULT", jp_default), JPSDEF ( 3, "DET", jp_detached), JPSDEF ( 8, "DETACHED", jp_detached), JPSDEF ( 3, "ERR", jp_error), JPSDEF ( 5, "ERROR", jp_error), JPSDEF ( 3, "GBL", jp_gbldir), JPSDEF ( 6, "GBLDIR", jp_gbldir), JPSDEF ( 2, "IM", jp_image), JPSDEF ( 5, "IMAGE", jp_image), JPSDEF ( 2, "IN", jp_input), JPSDEF ( 5, "INPUT", jp_input), JPSDEF ( 3, "LOG", jp_logfile), JPSDEF ( 7, "LOGFILE", jp_logfile), JPSDEF ( 5, "NOACC", jp_noaccount), JPSDEF ( 8, "NOACCOUN*", jp_noaccount), JPSDEF ( 5, "NODET", jp_nodetached), JPSDEF ( 8, "NODETACH*", jp_nodetached), JPSDEF ( 5, "NOSWA", jp_noswapping), JPSDEF ( 8, "NOSWAPPI*", jp_noswapping), JPSDEF ( 3, "OUT", jp_output), JPSDEF ( 6, "OUTPUT", jp_output), JPSDEF ( 3, "PRI", jp_priority), JPSDEF ( 8, "PRIORITY", jp_priority), JPSDEF ( 3, "PRO", jp_process_name), JPSDEF ( 7, "PROCESS*", jp_process_name), JPSDEF ( 3, "SCH", jp_schedule), JPSDEF ( 8, "SCHEDULE", jp_schedule), JPSDEF ( 3, "STA", jp_startup), JPSDEF ( 7, "STARTUP", jp_startup), JPSDEF ( 3, "SWA", jp_swapping), JPSDEF ( 8, "SWAPPING", jp_swapping) fis-gtm-V6.0-003/sr_port/la_encrypt.c0000644000032200000250000000470112201176160016334 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* la_encrypt.c : for given encryption function number, and an input sequence of bytes, the program computes the checksum of the sequence. used in : la_create.c,lp_licensed.c,lm_verify */ #include "mdef.h" #include "la_encrypt.h" static void la_encrypt_table (uint4 poly, uint4 tbl[]); static uint4 la_encrypt_value ( uint4 tbl[], /* polynomial coefficients */ uint4 cs, /* checksum initial value */ unsigned char *c, /* string to compute the check sum for */ int len); /* string length */ bool la_encrypt ( short n , /* encryption function number */ char *q , /* input sequence */ int len, /* sequence length */ uint4 bcs[]) /* result, binary form */ { static uint4 poly0[10] = {0xEDB88320, 0xA001A001, 0x00008408, 0x00000000, 0xA001A001, 1, 1, 1, 1, 1}; static uint4 init0[10] = {0xFFFFFFFF, 0x00000000, 0x0000FFFF, 0xFFFFFFFF, 0x00000000, 0, 0, 0, 0, 0}; static uint4 poly1[10] = {0xA001A001, 0x00008408, 0xEDB88320, 0xEDB88320, 0x0000A001, 1, 1, 1, 1, 1}; static uint4 init1[10] = {0x00000000, 0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0, 0, 0, 0, 0}; uint4 crctbl[16]; if (n<5) { la_encrypt_table(poly0[n],crctbl) ; bcs[0] = la_encrypt_value(crctbl,init0[n],(uchar_ptr_t)q,len) ; la_encrypt_table(poly1[n],crctbl) ; bcs[1] = la_encrypt_value(crctbl,init1[n],(uchar_ptr_t)q,len) ; } return n<5 ; } static void la_encrypt_table (uint4 poly, uint4 tbl[]) { uint4 k, t, x; int i; for ( k= 0 ; k!=16 ; k++ ) { t= k ; for ( i= 0 ; i!=4 ; i++ ) { x= t & 1 ; t= t>>1 ; if (x==1) t ^= poly ; } tbl[k]= t ; } } static uint4 la_encrypt_value ( uint4 tbl[], /* polynomial coefficients */ uint4 cs, /* checksum initial value */ unsigned char *c, /* string to compute the check sum for */ int len) /* string length */ { while ( len!=0 ) { cs ^= (int4)*c ; /* least signif. byte of cs differred with *c */ cs = ( cs >> 4 ) ^ tbl[cs & 0xF] ; cs = ( cs >> 4 ) ^ tbl[cs & 0xF] ; c++ ; len-- ; } return cs ; } fis-gtm-V6.0-003/sr_port/la_encrypt.h0000644000032200000250000000126712201176160016345 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __LA_ENCRYPT_H__ #define __LA_ENCRYPT_H__ bool la_encrypt ( short n , /* encryption function number */ char *q , /* input sequence */ int len, /* sequence length */ uint4 bcs[]); /* result, binary form */ #endif fis-gtm-V6.0-003/sr_port/lastchance1.c0000644000032200000250000000240712201176160016363 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_unistd.h" #include "io.h" #include "iosp.h" #include "error.h" #include "gv_rundown.h" #include "util.h" GBLREF int4 exi_condition; GBLREF boolean_t created_core; GBLREF boolean_t dont_want_core; error_def(ERR_ASSERT); error_def(ERR_FORCEDHALT); error_def(ERR_GTMASSERT); error_def(ERR_GTMASSERT2); error_def(ERR_GTMCHECK); error_def(ERR_LKRUNDOWN); error_def(ERR_MEMORY); error_def(ERR_OUTOFSPACE); error_def(ERR_STACKOFLOW); error_def(ERR_VMSMEMORY); CONDITION_HANDLER(lastchance1) { int4 actual_exi_condition; actual_exi_condition = exi_condition; PRN_ERROR; dec_err(VARLSTCNT(1) ERR_LKRUNDOWN); ESTABLISH(lastchance2); gv_rundown(); REVERT; ESTABLISH(lastchance3); io_rundown(NORMAL_RUNDOWN); REVERT; if (DUMPABLE && !SUPPRESS_DUMP) DUMP_CORE; PROCDIE(actual_exi_condition); } fis-gtm-V6.0-003/sr_port/lastchance2.c0000644000032200000250000000275112201176160016366 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_unistd.h" #ifdef VMS #include #include #endif #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "error.h" #include "filestruct.h" #include "io.h" #include "iosp.h" #include "jnl.h" #include "util.h" GBLREF gd_region *gv_cur_region; GBLREF int4 exi_condition; GBLREF boolean_t created_core; GBLREF boolean_t dont_want_core; static const unsigned short zero_fid[3]; error_def(ERR_ASSERT); error_def(ERR_GTMASSERT); error_def(ERR_GTMASSERT2); error_def(ERR_GTMCHECK); error_def(ERR_GVRUNDOWN); error_def(ERR_MEMORY); error_def(ERR_OUTOFSPACE); error_def(ERR_STACKOFLOW); error_def(ERR_VMSMEMORY); CONDITION_HANDLER(lastchance2) { int4 actual_exi_condition; actual_exi_condition = (EXIT_NRM != exi_condition ? exi_condition : EXIT_ERR); PRN_ERROR; dec_err(VARLSTCNT(1) ERR_GVRUNDOWN); ESTABLISH(lastchance3); io_rundown(NORMAL_RUNDOWN); REVERT; if (DUMPABLE && !SUPPRESS_DUMP) DUMP_CORE; PROCDIE(actual_exi_condition); } fis-gtm-V6.0-003/sr_port/lastchance3.c0000644000032200000250000000216312201176160016364 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_unistd.h" #include "error.h" #include "io.h" #include "util.h" GBLREF int4 exi_condition; GBLREF boolean_t created_core; GBLREF boolean_t dont_want_core; error_def(ERR_ASSERT); error_def(ERR_FORCEDHALT); error_def(ERR_GTMASSERT); error_def(ERR_GTMASSERT2); error_def(ERR_GTMCHECK); error_def(ERR_IORUNDOWN); error_def(ERR_MEMORY); error_def(ERR_OUTOFSPACE); error_def(ERR_STACKOFLOW); error_def(ERR_VMSMEMORY); CONDITION_HANDLER(lastchance3) { START_CH; ESTABLISH(terminate_ch); if (DUMPABLE) { PRN_ERROR; dec_err(VARLSTCNT(1) ERR_IORUNDOWN); if (!SUPPRESS_DUMP) DUMP_CORE; PROCDIE(exi_condition); } REVERT; UNWIND(NULL, NULL); } fis-gtm-V6.0-003/sr_port/lb_init.c0000644000032200000250000000665512201176160015626 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "compiler.h" #include "toktyp.h" #include "comp_esc.h" #include "advancewindow.h" #include "lb_init.h" GBLREF unsigned char *source_buffer; GBLREF char *lexical_ptr; GBLREF struct ce_sentinel_desc *ce_def_list; error_def(ERR_CETOOMANY); LITREF char ctypetab[NUM_CHARS]; #define MAX_SUBSTITUTIONS 1024 void lb_init(void) { int num_subs, y; short int sav_last_src_col, source_col; int4 source_len, skip_count; unsigned char *cp, *cp1; bool possible_sentinel; struct ce_sentinel_desc *shp; # ifdef DEBUG unsigned char original_source[MAX_SRCLINE]; # endif DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (NULL != ce_def_list) { for (source_len = 0; '\0' != source_buffer[source_len]; source_len++); # ifdef DEBUG memcpy (original_source, source_buffer, source_len + 2); /* include terminating null characters */ # endif source_col = 1; num_subs = 0; cp = source_buffer; possible_sentinel = TRUE; while (possible_sentinel && source_buffer[source_col - 1]) { possible_sentinel = FALSE; cp = source_buffer + source_col - 1; if (DEL < *cp) break; if ('\"' == *cp) { for (cp1 = cp + 1; ; ) { if (SP > *cp1) break; if ('\"' == *cp1++) { if ('\"' == *cp1) cp1++; /* escaped quotation mark inside string */ else break; /* end of string */ } } source_col += (cp1 - cp); cp = cp1; if ('\0' == *cp) break; } else if ('?' == *cp) { for (cp1 = cp + 1; ; ) { if (NUM_ASCII_CHARS <= *cp1) break; y = ctypetab[*cp1]; if ((TK_UPPER == y) || (TK_LOWER == y) || (TK_DIGIT == y) || (TK_PERIOD == y) || (TK_ATSIGN == y)) cp1++; else if ('\"' == *cp1) /* quoted string in pattern */ { for (cp1++; ; ) { if (SP > *cp1) break; if ('\"' == *cp1) { cp1++; if ('\"' == *cp1) /* escaped quotation mark in string */ cp1++; else /* character following string */ break; } else cp1++; } } else break; } source_col += (cp1 - cp); cp = cp1; if ('\0' == *cp) break; } for (shp = ce_def_list; NULL != shp; shp = shp->next) { if (0 == memcmp(cp, shp->escape_sentinel, shp->escape_length)) { ce_substitute (shp, source_col, &skip_count); num_subs++; if (MAX_SUBSTITUTIONS >= num_subs) { if (0 < skip_count) /* a substitution occurred */ possible_sentinel = TRUE; } else { sav_last_src_col = TREF(last_source_column); TREF(last_source_column) = source_col; stx_error (ERR_CETOOMANY); TREF(last_source_column) = sav_last_src_col; } break; } } if (!possible_sentinel) { /* in this column */ source_col++; possible_sentinel = TRUE; /* next column may have sentinel */ } } } lexical_ptr = (char *)source_buffer; advancewindow(); advancewindow(); return; } fis-gtm-V6.0-003/sr_port/lb_init.h0000644000032200000250000000104412201176160015616 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef LB_INIT_INCLUDED #define LB_INIT_INCLUDED void lb_init(void); #endif /* LB_INIT_INCLUDED */ fis-gtm-V6.0-003/sr_port/lcase.mpt0000644000032200000250000000234712201176160015645 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 1989, 2006 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %LCASE ;GT.M %UCASE utility - convert a string to all lower case ;invoke with string in %S to return lower case string in %S ;invoke at INT to execute interactively ;invoke at FUNC as an extrinsic function ;if you make heavy use of this routine, consider $ZCALL ; s %S=$$FUNC(%S) q INT n %S r !,"String: ",%S w !,"Lower: ",$$FUNC(%S),! q FUNC(s) new returnM,returnUTF8,ret,index i ($zver["VMS")!($ZCHSET="M") do quit ret . s returnM="set ret=$tr(s,""ABCDEFGHIJKLMNOPQRSTUVWXYZ" . for index=192:1:207,209:1:221 s returnM=returnM_$char(index) . s returnM=returnM_"""," . s returnM=returnM_"""abcdefghijklmnopqrstuvwxyz" . for index=224:1:239,241:1:253 s returnM=returnM_$char(index) . s returnM=returnM_""")" . xecute returnM s returnUTF8="set ret=$zconvert(s,""L"")" xecute returnUTF8 q ret fis-gtm-V6.0-003/sr_port/lckclr.c0000644000032200000250000000131012201176160015437 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "mlkdef.h" #include "lckclr.h" GBLREF short lks_this_cmd; GBLREF mlk_pvtblk *mlk_pvt_root; void lckclr(void) { short i; mlk_pvtblk *p1; p1 = mlk_pvt_root; for (i = 0; i < lks_this_cmd; i++) { p1->trans = 0; p1 = p1->next; } } fis-gtm-V6.0-003/sr_port/lckclr.h0000644000032200000250000000104012201176160015444 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef LCKCLR_INCLUDED #define LCKCLR_INCLUDED void lckclr(void); #endif /* LCKCLR_INCLUDED */ fis-gtm-V6.0-003/sr_port/lcl_arg1_is_desc_of_arg2.c0000644000032200000250000000141412201176160020746 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "lv_val.h" boolean_t lcl_arg1_is_desc_of_arg2(lv_val *cur, lv_val *ref) { lv_val *lv; lvTree *lvt; if (cur == ref) return TRUE; lv = cur; while (!LV_IS_BASE_VAR(lv)) { lvt = LV_GET_PARENT_TREE(lv); lv = (lv_val *)LVT_PARENT(lvt); if (lv == ref) return TRUE; } return FALSE; } fis-gtm-V6.0-003/sr_port/lclcol.mpt0000644000032200000250000000143712201176160016025 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001, 2012 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; %lclcol ; ; ; Local Variable Collation Control ; get() q $v("YLCT") getncol() q $v("YLCT","ncol") ; return null collation order ; getnct() q $v("YLCT","nct") ; return numeric collation type ; set(lct,ncol,nct) n ok,$et s $et="s $ec="""" s ok=0",ok=1 s:'$data(lct) lct=-1 s:'$data(ncol) ncol=-1 s:'$data(nct) nct=-1 v:ok "YLCT":lct:ncol:nct q ok fis-gtm-V6.0-003/sr_port/line.c0000644000032200000250000001513212201176160015123 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "cmd_qlf.h" #include "toktyp.h" #include "opcode.h" #include "mdq.h" #include "mmemory.h" #include "advancewindow.h" GBLREF short int source_line; GBLREF int mlmax; GBLREF mline *mline_tail; GBLREF short int block_level; GBLREF mlabel *mlabtab; GBLREF command_qualifier cmd_qlf; error_def(ERR_BLKTOODEEP); error_def(ERR_COMMAORRPAREXP); error_def(ERR_FALLINTOFLST); error_def(ERR_LSEXPECTED); error_def(ERR_MULTFORMPARM); error_def(ERR_MULTLAB); error_def(ERR_NAMEEXPECTED); error_def(ERR_NESTFORMP); boolean_t line(uint4 *lnc) { boolean_t success, embed_error = FALSE; int parmcount, varnum; short int dot_count; mlabel *x; mline *curlin; triple *first_triple, *parmbase, *parmtail, *r, *e; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; first_triple = (TREF(curtchain))->exorder.bl; dot_count = 0; parmbase = NULL; success = TRUE; curlin = (mline *)mcalloc(SIZEOF(*curlin)); curlin->line_number = 0; curlin->table = FALSE; assert(0 == TREF(expr_depth)); (TREF(side_effect_base))[0] = FALSE; TREF(last_source_column) = 0; if (TK_INTLIT == TREF(window_token)) int_label(); if ((TK_IDENT == TREF(window_token)) || (cmd_qlf.qlf & CQ_LINE_ENTRY)) start_fetches(OC_LINEFETCH); else newtriple(OC_LINESTART); curlin->line_number = *lnc; *lnc = *lnc + 1; curlin->table = TRUE; CHKTCHAIN(TREF(curtchain)); TREF(pos_in_chain) = *(TREF(curtchain)); if (TK_IDENT == TREF(window_token)) { x = get_mladdr(&(TREF(window_ident))); if (x->ml) { stx_error(ERR_MULTLAB); success = FALSE; } else { assert(NO_FORMALLIST == x->formalcnt); x->ml = curlin; advancewindow(); if (TK_COLON != TREF(window_token)) mlmax++; else { x->gbl = FALSE; advancewindow(); } } if (success && (TK_LPAREN == TREF(window_token))) { advancewindow(); parmbase = parmtail = newtriple(OC_BINDPARM); /* To error out on fall-throughs to labels with a formallist, we are inserting an error immediately before * the LINESTART/LINEFETCH opcode. So, first we need to find the LINESTART/LINEFETCH preceding the * BINDPARM we just inserted. */ assert((OC_LINESTART == parmbase->exorder.bl->opcode) || (OC_LINEFETCH == parmbase->exorder.bl->opcode)); assert(0 != parmbase->exorder.bl->src.line); /* No error should be inserted before the first label of the routine. */ if ((mlabtab->rson != x) || TREF(code_generated)) { e = maketriple(OC_RTERROR); e->operand[0] = put_ilit(ERR_FALLINTOFLST); /* Not a subroutine/func reference. */ e->operand[1] = put_ilit(FALSE); r = parmbase->exorder.bl->exorder.bl; dqins(r, exorder, e); embed_error = TRUE; } if (success) { for (parmcount = 0; TK_RPAREN != TREF(window_token); parmcount++) { if (TK_IDENT != TREF(window_token)) { stx_error(ERR_NAMEEXPECTED); success = FALSE; break; } else { varnum = get_mvaddr(&(TREF(window_ident)))->mvidx; for (r = parmbase->operand[1].oprval.tref; r; r = r->operand[1].oprval.tref) { assert(TRIP_REF == r->operand[0].oprclass); assert(ILIT_REF == r->operand[0].oprval.tref->operand[0].oprclass); assert((TRIP_REF == r->operand[1].oprclass) || (NO_REF == r->operand[1].oprclass)); if (r->operand[0].oprval.tref->operand[0].oprval.ilit == varnum) { stx_error(ERR_MULTFORMPARM); success = FALSE; break; } } if (!success) break; r = newtriple(OC_PARAMETER); parmtail->operand[1] = put_tref(r); r->operand[0] = put_ilit(varnum); parmtail = r; advancewindow(); } if (TK_COMMA == TREF(window_token)) advancewindow(); else if (TK_RPAREN != TREF(window_token)) { stx_error(ERR_COMMAORRPAREXP); success = FALSE; break; } } } if (success) { advancewindow(); parmbase->operand[0] = put_ilit(parmcount); x->formalcnt = parmcount; assert(!mlabtab->lson); if ((mlabtab->rson == x) && !TREF(code_generated)) mlabtab->formalcnt = parmcount; } } } if (success && (TK_EOL != TREF(window_token))) { if (TK_SPACE != TREF(window_token)) { stx_error(ERR_LSEXPECTED); success = FALSE; } else { assert(0 == dot_count); for (;;) { if (TK_SPACE == TREF(window_token)) advancewindow(); else if (TK_PERIOD == TREF(window_token)) { dot_count++; advancewindow(); } else break; } } if ((block_level + 1) < dot_count) { dot_count = (block_level > 0) ? block_level : 0; stx_error(ERR_BLKTOODEEP); success = FALSE; } } if ((0 != parmbase) && (0 != dot_count)) { stx_error(ERR_NESTFORMP); /* Should be warning */ success = FALSE; dot_count = (block_level > 0 ? block_level : 0); } if ((block_level + 1) <= dot_count) { mline_tail->child = curlin; curlin->parent = mline_tail; block_level = dot_count; } else { for (; dot_count < block_level; block_level--) mline_tail = mline_tail->parent; mline_tail->sibling = curlin; curlin->parent = mline_tail->parent; } mline_tail = curlin; if (success) { assert(TREF(for_stack_ptr) == TADR(for_stack)); *(TREF(for_stack_ptr)) = NULL; success = linetail(); if (success) { assert(TREF(for_stack_ptr) == TADR(for_stack)); if (*(TREF(for_stack_ptr))) tnxtarg(*(TREF(for_stack_ptr))); } } assert(TREF(for_stack_ptr) == TADR(for_stack)); if (first_triple->exorder.fl == TREF(curtchain)) newtriple(OC_NOOP); /* empty line (comment, blank, etc) */ if (embed_error) { /* The entry point to the label should be LINESTART/LINEFETCH, not the RTERROR. */ curlin->externalentry = e->exorder.fl; TREF(code_generated) = TRUE; } else { curlin->externalentry = first_triple->exorder.fl; /* First_triple points to the last triple before this line was processed. Its forward link will point to a * LINEFETCH or a LINESTART, or possibly a NOOP. If the line was a comment, there is only a LINESTART, and * hence no "real" code yet. */ TREF(code_generated) = TREF(code_generated) | ((OC_NOOP != first_triple->exorder.fl->opcode) && (first_triple->exorder.fl->exorder.fl != TREF(curtchain))); } return success; } fis-gtm-V6.0-003/sr_port/linetail.c0000644000032200000250000000252612201176160016000 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "toktyp.h" #include "opcode.h" #include "advancewindow.h" #include "cmd.h" error_def(ERR_CMD); error_def(ERR_SPOREOL); int linetail(void) { DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; for (;;) { while (TK_SPACE == TREF(window_token)) advancewindow(); if (TK_EOL == TREF(window_token)) return TRUE; if (!cmd()) { if (OC_RTERROR != (TREF(curtchain))->exorder.bl->exorder.bl->exorder.bl->opcode) { /* If rterror is last triple generated (has two args), then error already raised */ TREF(source_error_found) ? stx_error(TREF(source_error_found)) : stx_error(ERR_CMD); } assert((TREF(curtchain))->exorder.bl->exorder.fl == TREF(curtchain)); assert(TREF(source_error_found)); return FALSE; } if ((TK_SPACE != TREF(window_token)) && (TK_EOL != TREF(window_token))) { stx_error(ERR_SPOREOL); return FALSE; } } } fis-gtm-V6.0-003/sr_port/list_file.h0000644000032200000250000000131312201176160016147 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef LIST_FILE_INCLUDED #define LIST_FILE_INCLUDED void open_list_file(void); void close_list_file(void); void list_chkpage(void); void list_cmd(void); void list_head(bool newpage); void list_line(char *c); void list_line_number(void); void list_tab(void); #endif fis-gtm-V6.0-003/sr_port/lk_check_own.c0000644000032200000250000000406212201176160016622 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifdef VMS #include #endif #include "mdef.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "mlkdef.h" #include "filestruct.h" #include "lockdefs.h" #include "lk_check_own.h" #include "is_proc_alive.h" GBLREF short crash_count; /* * ------------------------------------------------ * Check if owner process of the lock is still alive * If the process is not alive, clear the lock. * * Return: * TRUE - cleared the owner * FALSE - otherwise * ------------------------------------------------ */ boolean_t lk_check_own(mlk_pvtblk *x) { int4 status; int4 icount, time[2]; boolean_t ret_val, was_crit; sgmnt_addrs *csa; if (!x->blocked) return FALSE; csa = &FILE_INFO(x->region)->s_addrs; if (csa->critical) crash_count = csa->critical->crashcnt; was_crit = csa->now_crit; if (!was_crit) grab_crit(x->region); /* check on process that owns lock */ ret_val = FALSE; if (x->blocked->owner) { /* There is an owner for the blocking node */ if (x->blocked->sequence != x->blk_sequence) { /* The node we were blocking on has been reused for something else so we are no longer blocked on it and can pretend that the process holding the lock went away */ ret_val = TRUE; } else if (BLOCKING_PROC_ALIVE(x, time, icount, status)) { /* process that owned lock has died, free lock. */ x->blocked->owner = 0; csa->hdr->trans_hist.lock_sequence++; ret_val = TRUE; } } else ret_val = TRUE; /* There is no owner. Take credit for freeing it.. */ if (!was_crit) rel_crit(x->region); return ret_val; } fis-gtm-V6.0-003/sr_port/lk_check_own.h0000644000032200000250000000111512201176160016623 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef LK_CHECK_OWN_INCLUDED #define LK_CHECK_OWN_INCLUDED boolean_t lk_check_own(mlk_pvtblk *x); #endif /* LK_CHECK_OWN_INCLUDED */ fis-gtm-V6.0-003/sr_port/lke.h0000644000032200000250000000212512201176160014752 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __LKE_H__ #define __LKE_H__ #include "error.h" bool lke_get_answ(char *prompt); bool lke_showlock(struct CLB *lnk, mlk_shrblk_ptr_t tree, mstr *name, bool all, bool wait, bool interactive, int4 pid, mstr one_lock, boolean_t exact); bool lke_showtree(struct CLB *lnk, mlk_shrblk_ptr_t tree, bool all, bool wait, pid_t pid, mstr one_lock, bool memory, int *shr_sub_size); void lke_exit(void); void lke_clear(void); void lke_help(void); void lke_show(void); void lke_show_memory(mlk_shrblk_ptr_t bhead, char *prefix); #ifdef VMS void lke(void); #else CONDITION_HANDLER(lke_ctrlc_handler); #endif void lke_setgdr(void); #endif /* __LKE_H__ */ fis-gtm-V6.0-003/sr_port/lke.hlp0000644000032200000250000004560712201176160015322 0ustar librarygtc1 Introduction Introduction The M Lock Utility (LKE) is a tool for examining and changing the GT.M LOCK environment. For a description of M LOCKs, refer to the LOCKs section in the General Language Features of M chapter and the description of the LOCK command in the Commands chapter of the GT.M Programmer's Guide. The two primary functions of the M Lock Utility (LKE) are: o SHOW all or specified LOCKs currently active o CLEAR all or specified LOCKs currently active When debugging an M application, you may use LKE to identify a possible deadlock situation, that is, two or more processes have LOCKs and are waiting to add resource names LOCKed by the other(s). Process 1 Process 2 LOCK A LOCK B LOCK +A LOCK +B Process 1 has A LOCKed and attempts to LOCK B. Process 2 has B LOCKed and attempts to LOCK A. Because these processes do not release their current LOCKs before adding additional LOCKs, nor do they provide a timeout to detect the problem, they are deadlocked. Neither process can proceed normally. You can use LKE to release one of the LOCKs so both processes may execute. However, because releasing a LOCK may cause the process to violate its design assumptions, terminating one process is generally a safer way to break the deadlock. **Note** When a process leaves M, GT.M normally releases any LOCKs or ZALLOCATEs held by that process. If a GT.M process terminates abnormally, or if the system "crashes" while a GT.M process is active, GT.M cannot perform normal clean-up. However, as soon as any other process waits several seconds for a LOCK owned by a process that no longer exists, GT.M automatically clears the "orphaned" LOCK. 2 Invoke Invoke GT.M installation procedure places the LKE utility package in a directory specified by the environment variable gtm_dist. LKE requires that the environment variable gtmgbldir be defined. Invoke LKE using the following command at the shell prompt. If this does not work, consult your system manager to investigate setup and file access issues. $gtm_dist/lke LKE> **Important** Always run LKE on the node where the lock is held. When LKE is ready to accept commands, it displays the LKE> prompt. To leave LKE, enter the EXIT command at the LKE> prompt. When additional information is entered on the command line after the LKE command, LKE processes the additional information as its command. $gtm_dist/lke show -all This command displays all current LOCKs and then returns to the shell prompt. If your LKE argument contains quotes, precede each quote in the argument by a back-slash (\) or enclose the entire argument in a set of quotes (matching single or double). Apply this convention only for those LKE commands that you run from the shell. $gtm_dist/lke show -lock="^Account(\"Name\")" $gtm_dist/lke show -lock='^Account("Name")' Both these commands display the status of LOCK ^Account("Name") in the default region. 1 Commands Commands The format for the LKE commands is: command [-qualifier[=qualifier-value]] LKE accepts command and qualifier abbreviations. The section describing each command provides the minimal abbreviation that can be used for that command, and the command qualifiers, if any. FIS recommends the use of a minimum of four characters for key words in scripts to ensure new keywords do not conflict with older scripts. 2 Clear Clear Use the CLEAR command to remove active LOCKs. **Caution** FIS recommends restricting the use of the LKE CLEAR facility to debugging environments; removing LOCKs in a production environment typically violates application design assumptions and can cause aberrant process behavior. GT.M automatically removes abandoned LOCKs so it is typically safer to MUPIP STOP a process that is inappropriately hanging on to a LOCK. The format of the CLEAR command is: C[LEAR] [-qualifier...] The optional qualifiers are: -A[LL] -L[OCK] -[NO]C[RIT] -[NO]EXACT -[NO]I[NTERACTIVE] -O[UTPUT]="file-name" -P[ID]=pid -R[EGION]=region-name By default, CLEAR operates interactively (-INTERACTIVE). Qualifiers for CLEAR -A[LL] Specifies all current LOCKs. o -ALL removes all current LOCKs. o If used, CLEAR and -REGION qualifier, -ALL removes all LOCKs in that region. o Issue a CLEAR - ALL only when there are no active GT.M processes using LOCKs, or when you can predict the effect on the application. o By default, CLEAR -ALL operates interactively (-INTERACTIVE). -[NO]C[RIT] Allows LKE CLEAR to work even if another process is holding a critical section. **Caution** This can damage current LOCKs and the LOCK mechanism. It is intended for use only under the direction of FIS. By default LKE operates in CRIT mode and ensures a consistent view of LOCKs by using the database critical section(s). -[NO]EXACT Limits the CLEAR command to the exact resource name specified with -LOCK=resource_name. NOEXACT (the default) treats the specified resource name as a prefix and works not only on it, but also on any of its descendants, since their existence effectively LOCK their parent tree. -L[OCK]=""resource_name"" Unless used with -EXACT, specifies the leading prefix for an implicit wild card search of all locks that start with the resource_name. o The resource_name is enclosed in two double quotation marks ("" ""). Because M resource names are formatted the same as global nodes with punctuation characters, in this context they are usually enclosed in sets of double quotation marks with string subscripts enclosed in sets of two double quotations. o When used with CLEAR, -LOCK removes the locks that start with resource_name. o When used with SHOW,-LOCK provides a precise way to examine the specified lock. -[NO]I[NTERACTIVE] Interactively clears one LOCK at a time. LKE displays each current LOCK with the PID of the owner process and prompts for verification that the LOCK should be cleared. LKE retains the LOCK for any response other than Y[ES]. o By default, CLEAR operates interactively (-INTERACTIVE). o To avoid holding a lock resource too long, LKE skips to the next matching LOCK if there is no operator response for several seconds. o -NOINTERACTIVE forces the action to take place without user confirmation of each change. Using -NOINTERACTIVE prevents the LKE operator from controlling the LOCK subsystem for potentially long periods of time when many locks are held. To do this, it limits the amount of time it waits for each response. -O[UTPUT]="file-name" Directs the reporting of all specified LOCKs to a file. o If you specify an existing file, LKE creates a new version and overwrites that file. o If file-name has permission issues, OUTPUT reports the cause of the error. o The -OUTPUT qualifier is compatible with all other qualifiers. o By default, CLEAR sends output messages to stdout. -P[ID]=pid Specifies the process identification number that holds a LOCK on a resource name. o LKE interprets pid as a decimal number. o PID clears LOCKs held by the process with the specified process identification number. o Provides a means for directing CLEAR to LOCKs held by a process that is behaving abnormally. o The -PID qualifier is compatible with all other qualifiers. -R[EGION]=region-name region-namespecifies the region that holds the locked resource names. o REGION clears LOCKs mapped by the current global directory to a region specified by the region-name. o The -REGION qualifier is compatible with all other qualifiers. o By default, CLEAR -REGION= operates interactively (-INTERACTIVE). Example: LKE>CLEAR -ALL This command clears all current LOCKs. Example: LKE>clear -pid=2325 -interactive This command presents all LOCKs held by the process with PID equal to 2325. You can choose whether or not to clear each LOCK. LKE>clear -reg=areg -interactive This command produces an output like the following: AREG ^a Owned by PID= 2083 which is an existing process Clear lock ? Type Yes or Y in response to the prompt. LKE responds with an informational message: %GTM-S-LCKGONE, Lock removed : ^a Type Yes or N or No or N until all LOCKs are displayed and acted upon. LKE> clear -pid=4208 -nointeractive This command clears the lock held by a process with PID 4208. This command produces an output like the following: DEFAULT Lock removed : ^A Note that -NOINTERACTIVE forced the action without asking for a confirmation. Example: LKE>clear -lock="^a("b") Clear lock ? y Lock removed : ^a("b") LKE> This command clears lock ^a("b") in the default region. Example: LKE>clear -lock="^a" -nointeractive This command clears all the locks that start with "^a" in the default region. -NOINTERACTIVE qualifier instructs LKE to clear these locks without further user intervention. Example: LKE>clear -lock="^a" -exact -nointeractive This command clears lock ^a in the default region. -NOINTERACTIVE instructs LKE to clear lock ^a without further user intervention. Example: LKE>CLEAR -PID=4109 -LOCK=""^A"" Clear lock ? Y Lock removed : ^A LKE> This command clears LOCK ^A held by process with PID 4109. 2 SHow SHow Use the SHOW command to get status of the LOCK mechanism and the LOCK database. The format of the SHOW command is: SH[OW] [-qualifier...] The optional qualifiers are: -A[LL] -L[OCK] -[NO]C[RIT] -O[UTPUT]="file-name" -P[ID]=pid -R[EGION]=region-name -W[AIT] o By default, SHOW displays -A[LL]. o The SHOW command reports active LOCKs. Information includes the LOCK resource name and the process identification (PID) of the LOCK owner. o LKE SHOW displays lock space usage with a message in the form of: "%GTM-I-LOCKSPACEUSE, Estimated free lock space: xxx% of pppp pages." If the lock space is full, it also displays a LOCKSPACEFULL error. o A LOCK command which finds no room in LOCK_SPACE to queue a waiting LOCK, does a slow poll waiting for LOCK_SPACE to become available. If LOCK does not acquire the ownership of the named resource with the specified timeout, it returns control to the application with $TEST=0. If timeout is not specified, the LOCK command continues to do a slow poll till the space becomes available. o LOCK commands which find no available lock space send a LOCKSPACEFULL message to the operator log. To prevent flooding the operator log, GT.M suppresses further such messages until the lock space usage drops below 75% full. o The results of a SHOW may be immediately "outdated" by M LOCK activity. o If the LOCK is owned by a GT.CM server on behalf of a client GT.M process, then LKE SHOW displays the client NODENAME (limited to the first 15 characters) and clientPID. The client PID (CLNTPID) is a decimal value in UNIX. **Note** GT.CM is an RPC-like way of remotely accessing a GT.M database. -ALL Specifies all current LOCKs. o -ALL displays all current LOCKs in all regions and information about the state of processes owning these LOCKs. o The -ALL qualifier is compatible with all other qualifiers. o When -ALL is combined with -PID or -REGION, the most restrictive qualifier prevails. o SHOW -ALL and -WAIT displays both -ALL and -WAIT information. -L[OCK]=resource_name resource_name specifies a single lock. o The resource_name is enclosed in double quotation marks ("" ""). Because M resource names are formatted the same as global nodes with punctuation characters, in this context they are usually enclosed in sets of double quotation marks with string subscripts enclosed in sets of two double quotations. o When used with the CLEAR command, the LOCK qualifier removes the specified lock. o When used with the SHOW command, the LOCK qualifier provides a precise way to examine the specified lock and any descendant LOCKed resources. -[NO]C[RIT] Allows the SHOW command to work even if another process is holding a critical section. o By default LKE operates in CRIT mode and ensures a consistent view of LOCKs by using the database critical section(s). o Use NOCRIT with SHOW only when normal operation is unsuccessful, as NOCRIT may cause LKE to report incomplete or inconsistent information. -O[UTPUT]="file-name" Directs the reporting of all specified LOCKs to a file. o If you specify an existing file, LKE creates a new version and overwrites that file. o The -OUTPUT qualifier is compatible with all other qualifiers. o By default, the SHOW command send output messages to stdout. -P[ID]=pid Specifies the process identification number that holds a LOCK on a resource name. o LKE interprets pid as a decimal number. o PID displays all LOCKs owned by the specified process identification number. o The -PID qualifier is compatible with all other qualifiers; the most restrictive of the qualifiers prevails. o By default, SHOW displays the LOCKs for all PIDs. -R[EGION]=region-name Specifies the region that holds the locked resource names. o The REGION qualifier displays LOCKs of that specified region. o The REGION qualifier is compatible with all other qualifiers; the most restrictive of the qualifiers prevails. o By default, SHOW displays the LOCKs for all regions. -W[AIT] Displays the LOCK resource name and the process state information of all processes waiting for the LOCK to be granted. o SHOW -WAIT does not display the owner of the LOCK. o SHOW -ALL -WAIT displays both -ALL and -WAIT information. o When a process abandons a "wait" request, that request may continue to appear in LKE SHOW -WAIT displays. This appearance is harmless, and is automatically eliminated if the GT.M lock management requires the space which it occupies. Use the following procedure to display all LOCKs active in the database(s) defined by the current global directory. LKE> SHOW -ALL -WAIT This produces an output like the following: No locks were found in DEFAULT AREG ^a Owned by PID=2080 which is an existing process BREG ^b(2) Owned by PID= 2089 which is a nonexistent process No locks were found in CREG Example: LKE>SHOW -ALL This command displays all LOCKs mapped to all regions of the current global directory. It produces an output like the following: DEFAULT ^A Owned by PID= 5052 which is an existing process ^B Owned by PID= 5052 which is an existing process %GTM-I-LOCKSPACEUSE, Estimated free lock space: 99% of 40 pages Example: LKE>show -lock="^a"(""b"")" This command shows lock ^a("b") in the default region. Example: LKE>SHOW -CRIT This command displays all the applicable locks held by a process that is holding a critical section. Example: LKE>show -all -output="abc.lk" This command create a new file called abc.lk that contains the output of the SHOW -ALL command. Example: LKE>show -pid=4109 This command displays all locks held by process with PID 4109 and the total lock space usage. Example: LKE>show -region=DEFAULT -lock=""^A"" This command displays the lock on ^A in the region DEFAULT. It produces an output like the following: DEFAULT ^A Owned by PID= 5052 which is an existing process %GTM-I-LOCKSPACEUSE, Estimated free lock space: 99% of 40 pages 2 Exit Exit The EXIT command ends an LKE session. The format of the EXIT command is: E[XIT] 2 Help Help The HELP command explains LKE commands. The format of the HELP command is: H[ELP] [options...] Enter the LKE command for which you want information at the Topic prompt(s) and then press RETURN or CTRL-Z to return to the LKE prompt. Example: LKE> HELP SHOW This command displays help for the SHOW command. 2 SPawn SPawn Use the SPAWN command to create a sub-process for access to the shell without terminating the current LKE environment. Use the SPAWN command to suspend a session and issue shell commands such as ls or printenv. The format of the SPAWN command is: SP[AWN] The SPAWN command has no qualifiers. Example: LKE>spawn This command creates a sub-process for access to the current shell without terminating the current LKE environment. Type exit to return to LKE. 1 Summary Summary +-------------------------------------------------------------------+ | COMMAND | QUALIFIER | COMMENTS | |---------+---------------------+-----------------------------------| | | -ALL | | | | -L[OCK] | | | | -[NO]CRIT | | | | -[NO]EXACT | | | C[LEAR] | | Use CLEAR with care and planning. | | | -[NO]I[NTERACTIVE] | | | | -O[UTPUT]=file-name | | | | -P[ID]=pid | | | | -R[EGION]=name | | |---------+---------------------+-----------------------------------| | E[XIT] | none | - | |---------+---------------------+-----------------------------------| | H[ELP] | [option] | - | |---------+---------------------+-----------------------------------| | | -ALL | | | | -L[OCK] | | | | -[NO]CRIT | | | | -N[OINTERACTIVE] | | | SH[OW] | | - | | | -O[UTPUT]=file-name | | | | -P[ID]=pid | | | | -R[EGION]=name | | | | -W[AIT] | | |---------+---------------------+-----------------------------------| | SP[AWN] | none | shellcommand | +-------------------------------------------------------------------+ fis-gtm-V6.0-003/sr_port/lke_clear.c0000644000032200000250000001016412201176160016115 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* * ------------------------------------------------- * lke_clear.c : removes locks for qualified regions * used in : lke.c * ------------------------------------------------- */ #include "mdef.h" #include "gtm_string.h" #include "mlkdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "cmidef.h" /* for cmmdef.h */ #include "hashtab_mname.h" /* needed for cmmdef.h */ #include "cmmdef.h" /* for gtcmtr_protos.h */ #include "util.h" #include "gtcmtr_protos.h" #include "lke.h" #include "lke_getcli.h" #include "lke_cleartree.h" #include "gtmmsg.h" #define NOFLUSH 0 #define FLUSH 1 #define RESET 2 GBLREF gd_region *gv_cur_region; GBLREF gd_addr *gd_header; GBLREF sgmnt_addrs *cs_addrs; GBLREF short crash_count; error_def(ERR_NOREGION); error_def(ERR_UNIMPLOP); error_def(ERR_TEXT); error_def(ERR_BADREGION); error_def(ERR_NOLOCKMATCH); void lke_clear(void) { bool locks, all = TRUE, wait = FALSE, interactive = TRUE, match = FALSE, memory = FALSE, nocrit = FALSE; boolean_t exact = TRUE, was_crit; int4 pid; int n; char regbuf[MAX_RN_LEN], nodebuf[32], one_lockbuf[MAX_KEY_SZ]; mlk_ctldata_ptr_t ctl; mstr reg, node, one_lock; /* Get all command parameters */ reg.addr = regbuf; reg.len = SIZEOF(regbuf); node.addr = nodebuf; node.len = SIZEOF(nodebuf); one_lock.addr = one_lockbuf; one_lock.len = SIZEOF(one_lockbuf); if (lke_getcli(&all, &wait, &interactive, &pid, ®, &node, &one_lock, &memory, &nocrit, &exact) == 0) return; /* Search all regions specified on the command line */ for (gv_cur_region = gd_header->regions, n = 0; n != gd_header->n_regions; ++gv_cur_region, ++n) { /* If region matches and is open */ if ((reg.len == 0 || gv_cur_region->rname_len == reg.len && memcmp(gv_cur_region->rname, reg.addr, reg.len) == 0) && gv_cur_region->open) { match = TRUE; util_out_print("!/!AD!/", NOFLUSH, REG_LEN_STR(gv_cur_region)); /* If distributed database, the region is located on another node */ if (gv_cur_region->dyn.addr->acc_meth == dba_cm) { # if defined(LKE_WORKS_OK_WITH_CM) /* Remote lock clears are not supported, so LKE CLEAR -EXACT qualifier * will not be supported on GT.CM.*/ locks = gtcmtr_lke_clearreq(gv_cur_region->dyn.addr->cm_blk, gv_cur_region->cmx_regnum, all, interactive, pid, &node); # else gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_UNIMPLOP, 0, ERR_TEXT, 2, LEN_AND_LIT("GT.CM region - locks must be cleared on the local node"), ERR_TEXT, 2, REG_LEN_STR(gv_cur_region)); continue; # endif } else if ((dba_bg == gv_cur_region->dyn.addr->acc_meth) || (dba_mm == gv_cur_region->dyn.addr->acc_meth)) { /* Local region */ cs_addrs = &FILE_INFO(gv_cur_region)->s_addrs; ctl = (mlk_ctldata_ptr_t)cs_addrs->lock_addrs[0]; /* Prevent any modifications of locks while we are clearing */ if (cs_addrs->critical != NULL) crash_count = cs_addrs->critical->crashcnt; was_crit = cs_addrs->now_crit; if (!was_crit) grab_crit(gv_cur_region); locks = ctl->blkroot == 0 ? FALSE : lke_cleartree(gv_cur_region, NULL, ctl, (mlk_shrblk_ptr_t)R2A(ctl->blkroot), all, interactive, pid, one_lock, exact); if (!was_crit) rel_crit(gv_cur_region); } else { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(2) ERR_BADREGION, 0); locks = TRUE; } if (!locks) { gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_NOLOCKMATCH, 2, REG_LEN_STR(gv_cur_region)); } } } if (!match && reg.len != 0) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_NOREGION, 2, reg.len, reg.addr); } fis-gtm-V6.0-003/sr_port/lke_clearlock.c0000644000032200000250000000526112201176160016770 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2004 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* * ----------------------------------------------- * lke_clearlock : removes the qualified lock node * used in : lke_cleartree.c * ----------------------------------------------- */ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "mlkdef.h" #include "cmidef.h" #include "hashtab_mname.h" /* needed for cmmdef.h */ #include "cmmdef.h" #include "util.h" #include "lke.h" #include "cmi.h" #include "gvcmz.h" #include "lke_clearlock.h" #define FLUSH 1 error_def(ERR_LCKGONE); bool lke_clearlock( gd_region *region, struct CLB *lnk, mlk_ctldata_ptr_t ctl, mlk_shrblk_ptr_t node, mstr *name, bool all, bool interactive, int4 pid) { clear_confirm confirm; clear_reply reply; uint4 status; int len; bool unlock = FALSE; sgmnt_addrs *csa; if (node->owner != 0 && (pid == node->owner || pid == 0)) { if (interactive) if (lnk == NULL) unlock = lke_get_answ("Clear lock ? "); else { lnk->mbl = sizeof confirm; lnk->mbf = (unsigned char *)&confirm; lnk->ast = NULL; status = cmi_read(lnk); if ((status & 1) == 0) { ((link_info *)(lnk->usr))->neterr = TRUE; gvcmz_error(CMMS_U_LKEDELETE, status); return FALSE; } unlock = confirm.clear; } else unlock = TRUE; if (unlock) { csa = &FILE_INFO(region)->s_addrs; node->owner = 0; node->sequence = csa->hdr->trans_hist.lock_sequence++; len = name->len - 1; if (name->addr[len] != '(') ++len; if (lnk == NULL) util_out_print("Lock removed : !AD", FLUSH, len, name->addr); else if (!interactive) { reply.code = CMMS_V_LKESHOW; reply.status = ERR_LCKGONE; reply.locknamelength = len; memcpy(reply.lockname, name->addr, len); lnk->cbl = sizeof reply - (sizeof reply.lockname - len); lnk->mbf = (unsigned char *)&reply; lnk->ast = NULL; status = cmi_write(lnk); if ((status & 1) == 0) { ((link_info *)(lnk->usr))->neterr = TRUE; gvcmz_error(CMMS_V_LKESHOW, status); return FALSE; } } } } return unlock; } fis-gtm-V6.0-003/sr_port/lke_clearlock.h0000644000032200000250000000123012201176160016765 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __LKE_CLEARLOCK_H__ #define __LKE_CLEARLOCK_H__ bool lke_clearlock(gd_region *region, struct CLB *lnk, mlk_ctldata_ptr_t ctl, mlk_shrblk_ptr_t node, mstr *name, bool all, bool interactive, int4 pid); #endif fis-gtm-V6.0-003/sr_port/lke_cleartree.c0000644000032200000250000000621112201176160016773 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2008 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* * ---------------------------------- * lke_cleartree : clears a lock tree * used in : lke_clear.c * ---------------------------------- */ #include "mdef.h" #include #include "mlkdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "mlk_shrblk_delete_if_empty.h" #include "mlk_wake_pending.h" #include "lke.h" #include "lke_cleartree.h" #include "lke_clearlock.h" #define KDIM 64 /* max number of subscripts */ GBLREF VSIG_ATOMIC_T util_interrupt; bool lke_cleartree( gd_region *region, struct CLB *lnk, mlk_ctldata_ptr_t ctl, mlk_shrblk_ptr_t tree, bool all, bool interactive, int4 pid, mstr one_lock, boolean_t exact) { mlk_shrblk_ptr_t node, oldnode, start[KDIM]; unsigned char subscript_offset[KDIM]; static char name_buffer[MAX_ZWR_KEY_SZ + 1]; static MSTR_DEF(name, 0, name_buffer); int depth = 0; bool locks = FALSE, locked, deleted; error_def(ERR_CTRLC); node = start[0] = tree; subscript_offset[0] = 0; for (;;) { name.len = subscript_offset[depth]; /* Display the lock node */ locked = lke_showlock(lnk, node, &name, all, FALSE, interactive, pid, one_lock, exact); locks |= locked; /* If it was locked, clear it and wake up any processes waiting for it */ if (locked && lke_clearlock(region, lnk, ctl, node, &name, all, interactive, pid) && node->pending != 0) mlk_wake_pending(ctl, node, region); /* if a specific lock was requested (-EXACT and -LOCK=), then we are done */ if (exact && (0 != one_lock.len) && locked) return locks; /* Move to the next node */ if (node->children == 0) { /* This node has no children, so move to the right */ oldnode = node; node = (mlk_shrblk_ptr_t)R2A(node->rsib); while (node == start[depth]) { /* There are no more siblings to the right at this depth, so move up and then right */ if (node->parent == 0) { /* We're already at the top, so we're done */ assert(depth == 0); (void)mlk_shrblk_delete_if_empty(ctl, node); return locks; } --depth; node = (mlk_shrblk_ptr_t)R2A(node->parent); (void)mlk_shrblk_delete_if_empty(ctl, oldnode); oldnode = node; node = (mlk_shrblk_ptr_t)R2A(node->rsib); } deleted = mlk_shrblk_delete_if_empty(ctl, oldnode); if (deleted && start[depth] == oldnode) start[depth] = node; } else { /* This node has children, so move down */ ++depth; node = start[depth] = (mlk_shrblk_ptr_t)R2A(node->children); subscript_offset[depth] = name.len; } if (util_interrupt) rts_error(VARLSTCNT(1) ERR_CTRLC); } } fis-gtm-V6.0-003/sr_port/lke_cleartree.h0000644000032200000250000000126312201176160017002 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2008 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __LKE_CLEARTREE_H__ #define __LKE_CLEARTREE_H__ bool lke_cleartree(gd_region *region, struct CLB *lnk, mlk_ctldata_ptr_t ctl, mlk_shrblk_ptr_t tree, bool all, bool interactive, int4 pid, mstr one_lock, boolean_t exact); #endif fis-gtm-V6.0-003/sr_port/lke_exit.c0000644000032200000250000000133712201176160016002 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdlib.h" /* for exit() */ #include "error.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "iosp.h" #include "mlkdef.h" #include "lke.h" void lke_exit(void) { EXIT(SS_NORMAL); } fis-gtm-V6.0-003/sr_port/lke_getcli.c0000644000032200000250000000572212201176160016302 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* lke_getcli.c : obtains CLI qualifiers, validates their values used in : lke_clear.c, lke_show.c */ #include "mdef.h" #include "gtm_string.h" #include "cli.h" #include "lke_getcli.h" #include "util.h" /* * ------------------------------------------------------ * Get command line parameters * ------------------------------------------------------ */ int4 lke_getcli(bool *all, bool *wait, bool *inta, int4 *pid, mstr *region, mstr *node, mstr *one_lock, bool *memory, bool *nocrit, boolean_t *exact) { int4 status; unsigned short len; int keylen; char one_lockbuf[MAX_ZWR_KEY_SZ + 1]; status = TRUE; /* * ----------------------------------------------------------- * -INTERACTIVE overrides any defaults -NOINTERACTIVE overrides any defaults * otherwise: default is nointeractive when -ALL is set default is original value of inta without -ALL * ----------------------------------------------------------- */ *all = (*all && cli_present("ALL") == CLI_PRESENT); *inta = *inta && (cli_present("INTERACTIVE") != CLI_NEGATED); *wait = (*wait && cli_present("WAIT") == CLI_PRESENT); *memory = (*memory && cli_present("MEMORY") == CLI_PRESENT); *nocrit = (*nocrit && cli_present("CRIT") == CLI_NEGATED); *exact = (*exact && cli_present("EXACT") == CLI_PRESENT); if (cli_present("PID") == CLI_PRESENT) { #ifdef HEXPID if (!cli_get_hex("PID", pid)) #else assert(SIZEOF(*pid) == SIZEOF(int)); if (!cli_get_int("PID", (int4 *)pid)) #endif { *pid = 0; status = FALSE; } } else *pid = 0 ; if (cli_present("REGION") == CLI_PRESENT) { len = region->len; if (!cli_get_str("REGION", region->addr, &len)) { util_out_print("Error getting REGION parameter",TRUE); region->len = 0; status = FALSE; } else region->len = len; } else region->len = 0; if (cli_present("LOCK") == CLI_PRESENT) { len = one_lock->len; if (!cli_get_str("LOCK", one_lock->addr, &len) || -1 == (keylen = lke_getki(one_lock->addr, len, one_lockbuf))) { util_out_print("Error getting LOCK parameter",TRUE); one_lock->len = 0; status = FALSE; } else { one_lock->len = keylen; memcpy(one_lock->addr, one_lockbuf, keylen); } } else { one_lock->len = 0; one_lock->addr = 0; } if (cli_present("NODE") == CLI_PRESENT) { len = node->len; if (!cli_get_str("NODE", node->addr, &len)) { util_out_print("Error getting NODE parameter",TRUE); node->len = 0; status = FALSE; } else node->len = len; } else node->len = 0; return status ; } fis-gtm-V6.0-003/sr_port/lke_getcli.h0000644000032200000250000000134612201176160016305 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2008 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef LKE_GETCLI_H #define LKE_GETCLI_H int4 lke_getcli(bool *all, bool *wait, bool *inta, int4 *pid, mstr *region, mstr *node, mstr *one_lock, bool *memory, bool *nocrit, boolean_t *exact); int lke_getki(char* src, int srclen, char* outptr); #ifdef VMS #define HEXPID #endif #endif fis-gtm-V6.0-003/sr_port/lke_getki.c0000644000032200000250000001146012201176160016132 0ustar librarygtc/**************************************************************** * * * Copyright 2006, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "lke_getcli.h" #include "gtm_ctype.h" /* Needed for TOUPPER() */ /* This routine performs the necessary transformation of the LOCK keys passed in * from the CLI layer and produces a canonical formatted key. This routine * * validates if the key is indeed in the correct syntax. * * adds quotes to the string subscripts (which were removed by the CLI * layer on UNIX) * * removes the redundant quotes in the key (which were passed intact by * CLI layer on VMS). * */ int lke_getki(char* src, int srclen, char* outbuff) { char *inptr, *nextptr, *intop, *outptr, *tmpptr; mval subsc = DEFINE_MVAL_STRING(MV_STR, 0, 0, 0, NULL, 0, 0); char one_lockbuf[MAX_ZWR_KEY_SZ + 1], *one_char; char *valid_char = "HAR"; /* This is used for validating characters following $ZCH and $C */ if (srclen > 1 && '"' == src[0] && '"' == src[srclen - 1]) { outptr = one_lockbuf; for (inptr = ++src, intop = src + srclen - 2; inptr < intop; *outptr++ = *inptr++) { if ('"' == *inptr && (++inptr >= intop || *inptr != '"')) return -1; /* invalid (unescaped) quote within a quoted key */ } src = one_lockbuf; srclen = (int)(outptr - one_lockbuf); } inptr = memchr(src, '(', srclen); if (NULL == inptr) { memcpy(outbuff, src, srclen); return srclen; } ++inptr; outptr = outbuff; memcpy(outptr, src, inptr - src); outptr += inptr - src; for (intop = src + srclen; inptr < intop; inptr = nextptr) { if (')' == *inptr) /* Catches incomplete lists or string concatenations */ return -1; else if ('$' == *inptr) { /* the entire subscript is within $C() or $ZCH */ *outptr++ = '$'; inptr++; if (('z' == *inptr) || ('Z' == *inptr)) { /* Very likely $ZCHAR() */ *outptr++ = 'Z'; inptr++; } if (('c' == *inptr) || ('C' == *inptr)) { *outptr++ = 'C'; inptr++; if (('Z' == *(outptr - 2)) && (('h' == *inptr) || ('H' == *inptr))) { *outptr++ ='H'; inptr++; one_char = valid_char + 1; } else one_char = valid_char; /* Validate/skip letters following C so that we allow C, CH, CHA, CHAR */ while (('\0' != *one_char) && ('(' != *inptr)) if (TOUPPER(*inptr++) != *one_char++) return -1; if ('(' != *inptr) return -1; } else /* We don't support anything other than $C() or $ZCH in locks */ return -1; nextptr = memchr(inptr, ')', intop - inptr); if (NULL == nextptr) return -1; ++nextptr; memcpy(outptr, inptr, nextptr - inptr); outptr += nextptr - inptr; } else { if ('"' == *inptr) /* Is this a quoted string? */ { /*Process character by character because '_' or ',' can be used within the quotes. */ for (nextptr = inptr + 1; nextptr < intop; nextptr++) if ('"' == *nextptr && (nextptr + 1 < intop)) { nextptr++; if ('"' != *nextptr) /* This is not a two double-quote so terminate. */ break; } } else { /* Fast-forward to the next separator */ nextptr = memchr(inptr, '_', intop - inptr); if (NULL == nextptr) { /* Not a string concatineated with $C() or $ZCH() */ nextptr = memchr(inptr, ',', intop - inptr); if (NULL == nextptr) nextptr = intop - 1; } } if (intop - 1 == nextptr) { /* If it reached to the end, it had better closed the paran */ if (')' != *nextptr) return -1; } else if ((',' != *nextptr) && ('_' != *nextptr)) /* If we are not at the end, it must be a separator*/ return -1; subsc.str.len = INTCAST(nextptr - inptr); subsc.str.addr = inptr; if (val_iscan(&subsc)) { memcpy(outptr, subsc.str.addr, subsc.str.len); outptr += subsc.str.len; } else { if (nextptr - 1 > inptr && '"' == *inptr && '"' == *(nextptr - 1)) { /* The string is already enclosed by a pair of quotes */ memcpy(outptr, inptr, nextptr - inptr); outptr += nextptr - inptr; inptr += nextptr - inptr; } else { /* unquoted string: add quotes */ *outptr++ = '"'; for (tmpptr = inptr; tmpptr < nextptr; ++tmpptr) { *outptr++ = *tmpptr; if ('"' == *tmpptr) *outptr++ = '"'; if ('_' == *tmpptr) { *--outptr; nextptr = tmpptr; } } *outptr++ = '"'; } } } if ((',' != *nextptr) && (')' != *nextptr) && ('_' != *nextptr)) return -1; *outptr++ = *nextptr++; } return (int)(outptr - outbuff); } fis-gtm-V6.0-003/sr_port/lke_show.c0000644000032200000250000001340012201176160016003 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* * ------------------------------------------------- * lke_show.c : displays locks for qualified regions * used in : lke.c * ------------------------------------------------- */ #include "mdef.h" #include "gtm_string.h" #include "mlkdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "filestruct.h" #include "cmidef.h" /* for cmmdef.h */ #include "hashtab_mname.h" /* needed for cmmdef.h */ #include "cmmdef.h" /* for gtcmtr_protos.h */ #include "util.h" #include "longcpy.h" #include "gtcmtr_protos.h" #include "lke.h" #include "lke_getcli.h" #include "gtmmsg.h" #include "min_max.h" #define NOFLUSH 0 #define FLUSH 1 #define RESET 2 GBLREF gd_region *gv_cur_region; GBLREF gd_addr *gd_header; GBLREF sgmnt_addrs *cs_addrs; GBLREF short crash_count; error_def(ERR_UNIMPLOP); error_def(ERR_TEXT); error_def(ERR_NOREGION); error_def(ERR_BADREGION); error_def(ERR_NOLOCKMATCH); error_def(ERR_LOCKSPACEUSE); error_def(ERR_LOCKSPACEFULL); error_def(ERR_LOCKSPACEINFO); void lke_show(void) { bool locks, all = TRUE, wait = TRUE, interactive = FALSE, match = FALSE, memory = TRUE, nocrit = TRUE; boolean_t exact = FALSE, was_crit; int4 pid; size_t ls_len; int n; char regbuf[MAX_RN_LEN], nodebuf[32], one_lockbuf[MAX_KEY_SZ]; mlk_ctldata_ptr_t ctl; mstr reg, node, one_lock; int shr_sub_len = 0; float ls_free = 0; /* Free space in bottleneck subspace */ /* Get all command parameters */ reg.addr = regbuf; reg.len = SIZEOF(regbuf); node.addr = nodebuf; node.len = SIZEOF(nodebuf); one_lock.addr = one_lockbuf; one_lock.len = SIZEOF(one_lockbuf); if (lke_getcli(&all, &wait, &interactive, &pid, ®, &node, &one_lock, &memory, &nocrit, &exact) == 0) return; /* Search all regions specified on the command line */ for (gv_cur_region = gd_header->regions, n = 0; n != gd_header->n_regions; ++gv_cur_region, ++n) { /* If region matches and is open */ if ((reg.len == 0 || gv_cur_region->rname_len == reg.len && memcmp(gv_cur_region->rname, reg.addr, reg.len) == 0) && gv_cur_region->open) { match = TRUE; util_out_print("!/!AD!/", NOFLUSH, REG_LEN_STR(gv_cur_region)); /* If distributed database, the region is located on another node */ if (gv_cur_region->dyn.addr->acc_meth == dba_cm) { # if defined(LKE_WORKS_OK_WITH_CM) /* Obtain lock info from the remote node */ locks = gtcmtr_lke_showreq(gv_cur_region->dyn.addr->cm_blk, gv_cur_region->cmx_regnum, all, wait, pid, &node); # else gtm_putmsg(VARLSTCNT(10) ERR_UNIMPLOP, 0, ERR_TEXT, 2, LEN_AND_LIT("GT.CM region - locks must be displayed on the local node"), ERR_TEXT, 2, REG_LEN_STR(gv_cur_region)); continue; # endif } else if (gv_cur_region->dyn.addr->acc_meth == dba_bg || gv_cur_region->dyn.addr->acc_meth == dba_mm) { /* Local region */ cs_addrs = &FILE_INFO(gv_cur_region)->s_addrs; ls_len = (size_t)(cs_addrs->lock_addrs[1] - cs_addrs->lock_addrs[0]); ctl = (mlk_ctldata_ptr_t)malloc(ls_len); /* Prevent any modification of the lock space while we make a local copy of it */ if (cs_addrs->critical != NULL) crash_count = cs_addrs->critical->crashcnt; was_crit = cs_addrs->now_crit; if (!nocrit && !was_crit) grab_crit(gv_cur_region); longcpy((uchar_ptr_t)ctl, (uchar_ptr_t)cs_addrs->lock_addrs[0], ls_len); assert((ctl->max_blkcnt > 0) && (ctl->max_prccnt > 0) && ((ctl->subtop - ctl->subbase) > 0)); if (!nocrit && !was_crit) rel_crit(gv_cur_region); shr_sub_len = 0; locks = ctl->blkroot == 0 ? FALSE: lke_showtree(NULL, (mlk_shrblk_ptr_t)R2A(ctl->blkroot), all, wait, pid, one_lock, memory, &shr_sub_len); /* lock space usage consists of: control_block + nodes(locks) + processes + substrings */ /* any of those subspaces can be bottleneck. * Therefore we will report the subspace which is running out. */ ls_free = MIN(((float)ctl->blkcnt) / ctl->max_blkcnt, ((float)ctl->prccnt) / ctl->max_prccnt); ls_free = MIN(1-(((float)shr_sub_len) / (ctl->subtop - ctl->subbase)), ls_free); ls_free *= 100; /* Scale to [0-100] range. (couldn't do this inside util_out_print) */ if (ls_free < 1) /* No memory? Notify user. */ gtm_putmsg(VARLSTCNT(4) ERR_LOCKSPACEFULL, 2, DB_LEN_STR(gv_cur_region)); if (ls_free < 1 || memory) { if (ctl->subtop > ctl->subfree) gtm_putmsg(VARLSTCNT(10) ERR_LOCKSPACEINFO, 8, REG_LEN_STR(gv_cur_region), (ctl->max_prccnt - ctl->prccnt), ctl->max_prccnt, (ctl->max_blkcnt - ctl->blkcnt), ctl->max_blkcnt, LEN_AND_LIT(" not ")); else gtm_putmsg(VARLSTCNT(10) ERR_LOCKSPACEINFO, 8, REG_LEN_STR(gv_cur_region), (ctl->max_prccnt - ctl->prccnt), ctl->max_prccnt, (ctl->max_blkcnt - ctl->blkcnt), ctl->max_blkcnt, LEN_AND_LIT(" ")); } free(ctl); } else { gtm_putmsg(VARLSTCNT(2) ERR_BADREGION, 0); locks = TRUE; } if (!locks) { gtm_putmsg(VARLSTCNT(4) ERR_NOLOCKMATCH, 2, REG_LEN_STR(gv_cur_region)); } assert((ls_free <= 100) && (ls_free >= 0)); gtm_putmsg(VARLSTCNT(4) ERR_LOCKSPACEUSE, 2, ((int)ls_free), cs_addrs->hdr->lock_space_size/OS_PAGELET_SIZE); } } if (!match && reg.len != 0) rts_error(VARLSTCNT(4) ERR_NOREGION, 2, reg.len, reg.addr); } fis-gtm-V6.0-003/sr_port/lke_showlock.c0000644000032200000250000001523512201176160016664 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* * ---------------------------------------------------------------- * lke_showlock : displays the lock data for a given lock tree node * used in : lke_showtree.c * ---------------------------------------------------------------- */ #include "mdef.h" #include "gtm_string.h" #include "gtm_stdio.h" /* for SPRINTF */ #ifdef VMS #include #include #include #include #endif #include "mlkdef.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "cmidef.h" #include "hashtab_mname.h" /* needed for cmmdef.h */ #include "cmmdef.h" #include "util.h" #include "lke.h" #include "is_proc_alive.h" #include "real_len.h" /* for real_len() prototype */ #include "zshow.h" #define LNAM 24 #define NDIM 32 /* max node name size */ #define CLNTNODE_LIT " : CLNTNODE = " #define CLNTPID_LIT " : CLNTPID = " #if defined(UNIX) # define PID_FMT_STR "!UL" # define PIDPRINT_LIT "%d" # define GNAM_FMT_STR "!AD " #elif defined(VMS) # define PID_FMT_STR "!XL" # define PIDPRINT_LIT "%08X" # define GNAM_FMT_STR "!24 " #endif GBLREF int4 process_id; static char gnam[] = GNAM_FMT_STR, gnaml[] = "!AD!/!24* ", ownedby[] = "Owned by PID= " PID_FMT_STR " which is !AD!AD", request[] = "Request PID= " PID_FMT_STR " which is !AD!AD", nonexpr[] = "a nonexistent process", existpr[] = "an existing process", nonexam[] = "an inexaminable process", nopriv[] = "no privilege"; bool lke_showlock( struct CLB *lnk, mlk_shrblk_ptr_t tree, mstr *name, bool all, bool wait, bool interactive, int4 pid, mstr one_lock, boolean_t exact) { mlk_prcblk pblk; mlk_prcblk_ptr_t r; mlk_shrsub_ptr_t value; short len1; int len2; boolean_t lock = FALSE, owned; UINTPTR_T f[7]; int4 gtcmbufidx, item, ret; uint4 status; char *msg, save_ch, format[64], gtcmbuf[64]; /* gtcmbuf[] is to hold ": CLNTNODE = %s : CLNTPID = %s" */ static mval subsc = DEFINE_MVAL_STRING(MV_STR, 0, 0, 0, NULL, 0, 0); VMS_ONLY( char sysinfo[NDIM]; $DESCRIPTOR (sysinfo_dsc, sysinfo); ) value = (mlk_shrsub_ptr_t)R2A(tree->value); if (0 == name->len) { /* unsubscripted lock name can never have control characters, so no ZWR translation needed */ memcpy(name->addr, value->data, value->length); f[0] = name->len = value->length; name->addr[name->len++] = '('; } else { /* perform ZWR translation on the subscript */ len1 = name->len - 1; if (')' == name->addr[len1]) name->addr[len1] = ','; subsc.str.len = value->length; subsc.str.addr = (char *)value->data; if (val_iscan(&subsc)) { /* avoid printing enclosed quotes for canonical numbers */ save_ch = name->addr[len1]; format2zwr((sm_uc_ptr_t)value->data, value->length, (unsigned char*)&name->addr[len1], &len2); assert(name->addr[len1 + len2 - 1] == '"'); name->addr[len1] = save_ch; len2 -= 2; /* exclude the enclosing quotes */ } else format2zwr((sm_uc_ptr_t)value->data, value->length, (unsigned char*)&name->addr[name->len], &len2); name->len += len2; name->addr[name->len++] = ')'; f[0] = name->len; } f[1] = (UINTPTR_T)name->addr; if (tree->owner || (tree->pending && wait)) { pblk.process_id = tree->owner; pblk.next = (wait && tree->pending) ? (ptroff_t)((uchar_ptr_t)&tree->pending - (uchar_ptr_t)&pblk.next + tree->pending) : 0; owned = (all || !wait) && tree->owner; r = owned ? &pblk : ((0 == tree->pending) ? NULL : (mlk_prcblk_ptr_t)R2A(tree->pending)); while (NULL != r) { if ((0 == pid) || (pid == r->process_id)) { f[2] = r->process_id; VMS_ONLY( item = JPI$_STATE; status = lib$getjpi(&item, &r->process_id, 0, &ret, &sysinfo_dsc, &len1); switch (status) { case SS$_NORMAL: f[3] = len1; f[4] = sysinfo; break; case SS$_NOPRIV: f[3] = STR_LIT_LEN(nopriv); f[4] = nopriv; break; case SS$_NONEXPR: f[3] = STR_LIT_LEN(nonexpr); f[4] = nonexpr; break; default: f[3] = STR_LIT_LEN(nonexam); f[4] = nonexam; break; } ) UNIX_ONLY( if (is_proc_alive((int4)r->process_id, 0)) { f[3] = STR_LIT_LEN(existpr); f[4] = (INTPTR_T)existpr; } else { f[3] = STR_LIT_LEN(nonexpr); f[4] = (UINTPTR_T)nonexpr; } ) if (tree->auxowner) { gtcmbufidx = 0; memcpy(>cmbuf[gtcmbufidx], CLNTNODE_LIT, STR_LIT_LEN(CLNTNODE_LIT)); gtcmbufidx += STR_LIT_LEN(CLNTNODE_LIT); memcpy(>cmbuf[gtcmbufidx], tree->auxnode, SIZEOF(tree->auxnode)); gtcmbufidx += real_len(SIZEOF(tree->auxnode), (uchar_ptr_t)tree->auxnode); memcpy(>cmbuf[gtcmbufidx], CLNTPID_LIT, STR_LIT_LEN(CLNTPID_LIT)); gtcmbufidx += STR_LIT_LEN(CLNTPID_LIT); SPRINTF(>cmbuf[gtcmbufidx], PIDPRINT_LIT, tree->auxpid); f[5] = strlen(gtcmbuf); f[6] = (UINTPTR_T)>cmbuf[0]; assert(f[5] > gtcmbufidx); assert(gtcmbufidx < SIZEOF(gtcmbuf)); } else f[5] = f[6] = 0; if (interactive) { if (LNAM >= f[0]) { msg = gnam; len1 = STR_LIT_LEN(gnam); } else { msg = gnaml; len1 = STR_LIT_LEN(gnaml); } memcpy(format, msg, len1); if (owned && !lock) { msg = ownedby; len2 = STR_LIT_LEN(ownedby); } else { msg = request; len2 = STR_LIT_LEN(request); } memcpy(format + len1, msg, len2); format[len1 + len2] = '\0'; assert((len1 + len2) < SIZEOF(format)); if (NULL == lnk) { if ((NULL == one_lock.addr) || (!memcmp(name->addr, one_lock.addr, one_lock.len) && (!exact || (one_lock.len == f[0])))) util_out_print(format, FLUSH, f[0], f[1], f[2], f[3], f[4], f[5], f[6]); } else util_cm_print(lnk, CMMS_V_LKESHOW, format, FLUSH, f[0], f[1], f[2], f[3], f[4], f[5], f[6]); } if ((NULL != one_lock.addr) && (memcmp(name->addr, one_lock.addr, one_lock.len) || (exact && (one_lock.len != f[0])))) { lock = FALSE; return lock; } lock = TRUE; } f[0] = 0; r = (0 == r->next) ? (mlk_prcblk_ptr_t)NULL : (mlk_prcblk_ptr_t)R2A(r->next); } } return lock; } fis-gtm-V6.0-003/sr_port/lke_showtree.c0000644000032200000250000000660712201176160016676 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* * ----------------------------------- * lke_showtree : displays a lock tree * used in : lke_show.c * ----------------------------------- */ #include "mdef.h" #include #include #include "gtm_string.h" #include "gtm_stdio.h" #include "mlkdef.h" #include "cmidef.h" #include "lke.h" #define KDIM 64 /* max number of subscripts */ GBLREF VSIG_ATOMIC_T util_interrupt; error_def(ERR_CTRLC); void lke_show_memory(mlk_shrblk_ptr_t bhead, char *prefix) { mlk_shrblk_ptr_t b, bnext; mlk_shrsub_ptr_t dsub; char temp[MAX_ZWR_KEY_SZ + 1]; char new_prefix[KDIM+2]; SPRINTF(new_prefix, " %s", prefix); for (b = bhead, bnext = 0; bnext != bhead; b = bnext) { dsub = (mlk_shrsub_ptr_t)R2A(b->value); memcpy(temp, dsub->data, dsub->length); temp[dsub->length] = '\0'; PRINTF("%s%s : [shrblk] %lx : [shrsub] %lx\n", prefix, temp, (long unsigned int) b, (long unsigned int) dsub); if (b->children) lke_show_memory((mlk_shrblk_ptr_t)R2A(b->children), new_prefix); bnext = (mlk_shrblk_ptr_t)R2A(b->rsib); } } /* Note:*shr_sub_size keeps track of total subscript area in lock space. Initialize *shr_sub_size to 0 before calling this. * lke_showtree() will keep adding on previous value of shr_sub_size. If such info is not needed simply pass NULL to shr_sub_size */ bool lke_showtree(struct CLB *lnk, mlk_shrblk_ptr_t tree, bool all, bool wait, pid_t pid, mstr one_lock, bool memory, int *shr_sub_size) { mlk_shrblk_ptr_t node, start[KDIM]; unsigned char subscript_offset[KDIM]; static char name_buffer[MAX_ZWR_KEY_SZ + 1]; static MSTR_DEF(name, 0, name_buffer); int depth = 0; bool locks = FALSE; int string_size = 0; if (memory) { lke_show_memory(tree, " "); if (shr_sub_size) (*shr_sub_size) = string_size; return TRUE; } node = start[0] = tree; subscript_offset[0] = 0; for (;;) { name.len = subscript_offset[depth]; string_size += MLK_SHRSUB_SIZE((mlk_shrsub_ptr_t)R2A(node->value)); /* Display the lock node */ locks = lke_showlock(lnk, node, &name, all, wait, TRUE, pid, one_lock, FALSE) || locks; /* Move to the next node */ if (node->children == 0) { /* This node has no children, so move to the right */ node = (mlk_shrblk_ptr_t)R2A(node->rsib); while (node == start[depth]) { /* There are no more siblings to the right at this depth, so move up and then right */ if (node->parent == 0) { /* We're already at the top, so we're done */ assert(depth == 0); if (shr_sub_size) (*shr_sub_size) = string_size; return locks; } --depth; node = (mlk_shrblk_ptr_t)R2A(((mlk_shrblk_ptr_t)R2A(node->parent))->rsib); } } else { /* This node has children, so move down */ ++depth; node = start[depth] = (mlk_shrblk_ptr_t)R2A(node->children); subscript_offset[depth] = name.len; } if (util_interrupt) rts_error(VARLSTCNT(1) ERR_CTRLC); } } fis-gtm-V6.0-003/sr_port/lkglvn.c0000644000032200000250000000517312201176160015475 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "subscript.h" #include "advancewindow.h" error_def(ERR_COMMA); error_def(ERR_EXTGBLDEL); error_def(ERR_LKNAMEXPECTED); error_def(ERR_MAXNRSUBSCRIPTS); int lkglvn(boolean_t gblvn) { boolean_t vbar; char *lknam, lkname_buf[MAX_MIDENT_LEN + 1], x; opctype ox; oprtype *sb1, *sb2, subscripts[MAX_LVSUBSCRIPTS]; triple *ref, *t1; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; ox = OC_LKNAME; sb1 = sb2 = subscripts; lknam = lkname_buf; if (gblvn) *lknam++ = '^'; if ((TK_LBRACKET == TREF(window_token)) || (TK_VBAR == TREF(window_token))) { vbar = (TK_VBAR == TREF(window_token)); advancewindow(); if (EXPR_FAIL == (vbar ? expr(sb1++, MUMPS_EXPR) : expratom(sb1++))) return FALSE; if (TK_COMMA == TREF(window_token)) { advancewindow(); if (EXPR_FAIL == (vbar ? expr(sb1++, MUMPS_EXPR) : expratom(sb1++))) return FALSE; } else *sb1++ = put_str(0, 0); if ((!vbar && (TK_RBRACKET != TREF(window_token))) || (vbar && (TK_VBAR != TREF(window_token)))) { stx_error(ERR_EXTGBLDEL); return FALSE; } advancewindow(); ox = OC_LKEXTNAME; } else *sb1++ = put_ilit(0); if (TK_IDENT != TREF(window_token)) { stx_error(ERR_LKNAMEXPECTED); return FALSE; } assert(MAX_MIDENT_LEN >= (TREF(window_ident)).len); memcpy(lknam, (TREF(window_ident)).addr, (TREF(window_ident)).len); lknam += (TREF(window_ident)).len; *sb1++ = put_str(lkname_buf,(mstr_len_t)(lknam - lkname_buf)); advancewindow(); if (TK_LPAREN == TREF(window_token)) { for (;;) { if (ARRAYTOP(subscripts) <= sb1) { stx_error(ERR_MAXNRSUBSCRIPTS); return FALSE; } advancewindow(); if (EXPR_FAIL == expr(sb1, MUMPS_EXPR)) return FALSE; sb1++; if (TK_RPAREN == (x = TREF(window_token))) /* NOTE assignment */ { advancewindow(); break; } if (TK_COMMA != x) { stx_error(ERR_COMMA); return FALSE; } } } ref = newtriple(ox); ref->operand[0] = put_ilit((mint)(sb1 - sb2)); for ( ; sb2 < sb1 ; sb2++) { t1 = newtriple(OC_PARAMETER); ref->operand[1] = put_tref(t1); ref = t1; ref->operand[0] = *sb2; } return TRUE; } fis-gtm-V6.0-003/sr_port/lkinit.c0000644000032200000250000000115212201176160015463 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "mlkdef.h" GBLDEF bool remlkreq=FALSE; GBLDEF mlk_pvtblk *mlk_pvt_root = 0; GBLDEF unsigned short lks_this_cmd; GBLDEF unsigned char cm_action; fis-gtm-V6.0-003/sr_port/loadop.m0000644000032200000250000000146712201176160015472 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001, 2008 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; loadop ;load op codes n (opc,opx,opcdcnt,loadh) k opc,opx,opcdcnt s opcdcnt=0 s file=loadh("opcode_def.h") o file:read u file loop r x i $zeof g fini i x?1"OPCODE_DEF"1.E s rec=x,opcdcnt=opcdcnt+1 i d proc g loop fini c file q proc s val=opcdcnt-1,cd=$p($p(rec,"(",2),",",1) s opc(cd)=val,opx(val)=cd q err u "" w rec,!,"error code=",ec," line=",opcdcnt,! u file q fis-gtm-V6.0-003/sr_port/loadvx.m0000644000032200000250000000233612201176160015505 0ustar librarygtc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Copyright 2001, 2010 Fidelity Information Services, Inc ; ; ; ; This source code contains the intellectual property ; ; of its copyright holder(s), and is made available ; ; under a license. If you do not know the terms of ; ; the license, please stop and do not read further. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; loadvx ;load op codes n (vxi,vxx,loadh) k vxi,vxx s lnr=0 s file=loadh("vxi.h") o file:read u file loop r x i $zeof g fini s rec=x,lnr=lnr+1 d proc g loop fini c file q proc i $e(x,"1")'="#" q pr0 s x=$tr(x,$c(9)," ") i x'?1"#define"1." "1"VXI_"1.AN1." "1"(0x"1.3AN1")".E s ec=1 g err s y=$f(x,"VXI_"),x=$e(x,y,999) s cd=$p(x," ",1),cdx="VXI_"_cd f i=1:1:$l(cd) i $e(cd,i)?1U s cd=$e(cd,1,i-1)_$c($a(cd,i)+32)_$e(cd,i+1,999) s val=$p($p($p(x,"(",2),")",1),"0x",2) d hex2dec i $d(vxx(val)) s ec=2 g err i $d(vxi(cd)) s ec=3 g err s vxi(cd)=val,vxi(cd,1)=cdx,vxx(val)=cd q err u "" w rec,!,"error code=",ec," line=",lnr,! u file q hex2dec n n,x,i s n=0,i=1 h2d1 s x=$e(val,i) i x="" s val=n q i x?1U s x=$a(x)-55 e i x?1L s x=$a(x)-87 e i x'?1N b s n=n*16+x,i=i+1 g h2d1 fis-gtm-V6.0-003/sr_port/lock_str_to_buff.c0000644000032200000250000000227012201176160017517 0ustar librarygtc/**************************************************************** * * * Copyright 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "error.h" #include "mlkdef.h" #include "lock_str_to_buff.h" #include "gtm_string.h" #include "zshow.h" /* Takes a lock as input and outputs lock name to string to buff (terminated with NULL). This is called from op_lock2. * This function consolidates "output" variable initialization and name string formatting into one function. */ void lock_str_to_buff(mlk_pvtblk *pvt_ptr, char *outbuff, int outbuff_len) { mval v; zshow_out output; memset(&output, 0, SIZEOF(output)); output.type = ZSHOW_BUFF_ONLY; /* This setting only changes out->ptr the other fileds are ignored */ output.buff = &outbuff[0]; output.size = outbuff_len; output.ptr = output.buff; zshow_format_lock(&output,pvt_ptr); *output.ptr = '\0'; return; } fis-gtm-V6.0-003/sr_port/lock_str_to_buff.h0000644000032200000250000000111412201176160017520 0ustar librarygtc/**************************************************************** * * * Copyright 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef LOCK_STR_TO_BUFF_H #define LOCK_STR_TO_BUFF_H void lock_str_to_buff(mlk_pvtblk *pvt_ptr1, char *outbuff, int outbuff_len); #endif fis-gtm-V6.0-003/sr_port/lockconst.h0000644000032200000250000000760512201176160016206 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2007 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* lockconst.h - define values used for interlocks */ #define LOCK_AVAILABLE 0 #define LOCK_IN_USE 1 #define REC_UNDER_PROG 2 /* CAUTION: the following two values are not currently optional on HPUX, but rather chosen for HP-PA arthitectural reasons */ #define GLOBAL_LOCK_AVAILABLE -1 #define GLOBAL_LOCK_IN_USE 0 /* Global latch note for platforms with a micro latch (currently Solaris and HPUX). The SET_LATCH_GLOBAL macro initializes both the compswap lock (major latch) and the micro latch used by compswap. The order this is done in is first the micro latch, then the major latch. The order is important so that secshr_db_clnup can (re)initialize the entire latch and not run into problems with concurrent users attempting to get the lock. The compswap routines in these modules will check the value of the major latch first before even attempting to obtain the micro latch. */ #ifdef __hppa # define alignedaddr(x) (volatile int *)((UINTPTR_T)(x) + 15 & ~0xf) /* 32-bit */ /* Given a pointer into memory, round up to the nearest 16-byte boundary by adding 15, then masking off the last four bits. Assumption: the input address is already int (4-byte) aligned. The VOLATILE keyword is essential in this macro: it ensures that the compiler does not perform certain optimizations which would compromise the integrity the spinlock logic. */ # define release_spinlock(lockarea) {if (1) { \ _flush_globals(); \ (*alignedaddr(&(lockarea)->hp_latch_space) = GLOBAL_LOCK_AVAILABLE); } else ;} /* HP white paper sets latch to 1 for available while we set it to -1 */ /* For performance, release_spinlock is a macro, rather than a function. To release or initialize a spinlock, we simply set its value to one. We must call the psuedo function "_flush_globals()" to ensure that the compiler doesn't hold any externally-visible values in registers across the lock release */ int4 load_and_clear(sm_int_ptr_t); # define GET_LATCH_GLOBAL(a) (GLOBAL_LOCK_AVAILABLE == *alignedaddr(&(a)->hp_latch_space) ? \ load_and_clear((sm_int_ptr_t)&(a)->hp_latch_space) : GLOBAL_LOCK_IN_USE) /* above tries a fast pretest before calling load_and_clear to actually get the latch */ # define RELEASE_LATCH_GLOBAL(a) release_spinlock(a) # define SET_LATCH_GLOBAL(a, b) {RELEASE_LATCH_GLOBAL(a); assert(LOCK_AVAILABLE == b); SET_LATCH(a, b);} #elif defined(__sparc) && defined(SPARCV8_NO_CAS) /* For Sun sparc, we use the extra word of the latch for a micro lock for compswap. Future iterations of this should make use of the CAS (compare and swap) instruction newly available in the Sparc Version 9 instruction set. These *_GLOBAL macros are used only from compswap.c (currently) */ # define GET_LATCH_GLOBAL(a) aswp(&(a)->u.parts.latch_word, GLOBAL_LOCK_IN_USE) # define RELEASE_LATCH_GLOBAL(a) aswp(&(a)->u.parts.latch_word, GLOBAL_LOCK_AVAILABLE) # define SET_LATCH_GLOBAL(a, b) {SET_LATCH(&(a)->u.parts.latch_word, GLOBAL_LOCK_AVAILABLE); SET_LATCH(a, b);} #elif defined(VMS) # define SET_LATCH_GLOBAL(a, b) {(a)->u.parts.latch_image_count = 0; SET_LATCH(a, b);} #else # define SET_LATCH_GLOBAL(a, b) SET_LATCH(a, b) #endif /* perhaps this should include flush so other CPUs see the change now */ #define SET_LATCH(a,b) (*((sm_int_ptr_t)a) = b) fis-gtm-V6.0-003/sr_port/locklits.h0000644000032200000250000000134012201176160016021 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #define MAX_LCKARG 253 #define LOCKED 1 #define ZALLOCATED 2 #define LCK_REQUEST 4 #define ZAL_REQUEST 8 #define PENDING 16 #define COMPLETE 32 #define INCREMENTAL 0x40 #define NEW 0x80 #define DEAD 2 #define PART_DEAD 1 #define NOT_DEAD 0 #define NOT_THERE -1 #define LOCK_SELF_WAKE 100 fis-gtm-V6.0-003/sr_port/logical_truth_value.c0000644000032200000250000000515212201176160020231 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_ctype.h" #include "min_max.h" #include "gtm_string.h" #include "gtm_strings.h" /* for STRNCASECMP */ #include "trans_log_name.h" #include "iosp.h" #include "logical_truth_value.h" /* returns the truth value based on the sense indicated by 'negate'. * If negate is FALSE (i.e. in regular mode), * returns TRUE if the env variable/logical log is defined and evaluates to "TRUE" (or part thereof), * or "YES" (or part thereof), or a non zero integer * returns FALSE otherwise * If negate is TRUE(i.e. in negative mode), * returns TRUE if the env variable/logical log is defined and evaluates to "FALSE" (or part thereof), * or "NO" (or part thereof), or a zero integer * returns FALSE otherwise */ boolean_t logical_truth_value(mstr *log, boolean_t negate, boolean_t *is_defined) { int4 status; mstr tn; char buf[1024]; boolean_t zero, is_num; int index; error_def(ERR_LOGTOOLONG); error_def(ERR_TRNLOGFAIL); tn.addr = buf; if (NULL != is_defined) *is_defined = FALSE; if (SS_NORMAL == (status = TRANS_LOG_NAME(log, &tn, buf, SIZEOF(buf), dont_sendmsg_on_log2long))) { if (NULL != is_defined) *is_defined = TRUE; if (tn.len <= 0) return FALSE; for (is_num = TRUE, zero = TRUE, index = 0; index < tn.len; index++) { if (!ISDIGIT_ASCII(buf[index])) { is_num = FALSE; break; } zero = (zero && ('0' == buf[index])); } if (!negate) { /* regular mode */ return (!is_num ? (0 == STRNCASECMP(buf, LOGICAL_TRUE, MIN(STR_LIT_LEN(LOGICAL_TRUE), tn.len)) || 0 == STRNCASECMP(buf, LOGICAL_YES, MIN(STR_LIT_LEN(LOGICAL_YES), tn.len))) : !zero); } else { /* negative mode */ return (!is_num ? (0 == STRNCASECMP(buf, LOGICAL_FALSE, MIN(STR_LIT_LEN(LOGICAL_FALSE), tn.len)) || 0 == STRNCASECMP(buf, LOGICAL_NO, MIN(STR_LIT_LEN(LOGICAL_NO), tn.len))) : zero); } } else if (SS_NOLOGNAM == status) return (FALSE); # ifdef UNIX else if (SS_LOG2LONG == status) { rts_error(VARLSTCNT(5) ERR_LOGTOOLONG, 3, log->len, log->addr, SIZEOF(buf) - 1); return (FALSE); } # endif else { rts_error(VARLSTCNT(5) ERR_TRNLOGFAIL, 2, log->len, log->addr, status); return (FALSE); } } fis-gtm-V6.0-003/sr_port/logical_truth_value.h0000644000032200000250000000140612201176160020234 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2006 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef LOGICAL_TRUTH_VALUE_H_INCLUDED #define LOGICAL_TRUTH_VALUE_H_INCLUDED #define LOGICAL_TRUE "TRUE" #define LOGICAL_YES "YES" #define LOGICAL_FALSE "FALSE" #define LOGICAL_NO "NO" boolean_t logical_truth_value(mstr *logical, boolean_t negate, boolean_t *is_defined); #endif /* LOGICAL_TRUTH_VALUE_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/longcpy.h0000644000032200000250000000156312201176160015657 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2003 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef LONGCPY_INCLUDED #define LONGCPY_INCLUDED /* To be one day eliminated when usage is totally replaced by the memcpy calls it should be calling now instead. Since this is a stop-gap measure, it is ok that this include pulls in gtm_string.h if necessary. void longcpy(uchar_ptr_t a, uchar_ptr_t b, int4 len); */ #include "gtm_string.h" #define longcpy(dst, src, len) memcpy(dst, src, len) #endif /* LONGCPY_INCLUDED */ fis-gtm-V6.0-003/sr_port/longset.h0000644000032200000250000000157212201176160015657 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2003 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef LONGSET_INCLUDED #define LONGSET_INCLUDED /* To be one day eliminated when usage is totally replaced by the memset calls it should be calling now instead. Since this is a stop-gap measure, it is ok that this include pulls in gtm_string.h if necessary. void longset(uchar_ptr_t ptr, int len, unsigned char fill); */ #include "gtm_string.h" #define longset(dst, len, fill) memset(dst, fill, len) #endif /* LONGSET_INCLUDED */ fis-gtm-V6.0-003/sr_port/lookup_variable_htent.c0000644000032200000250000000303412201176177020562 0ustar librarygtc/**************************************************************** * * * Copyright 2009, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "lv_val.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include #include "stack_frame.h" #include "lookup_variable_htent.h" #include "alias.h" GBLREF symval *curr_symval; GBLREF stack_frame *frame_pointer; ht_ent_mname *lookup_variable_htent(unsigned int x) { ht_ent_mname *tabent; mident_fixed varname; boolean_t added; assert(x < frame_pointer->vartab_len); added = add_hashtab_mname_symval(&curr_symval->h_symtab, ((var_tabent *)frame_pointer->vartab_ptr + x), NULL, &tabent); assert(tabent); if (NULL == tabent->value) { assert(added); /* Should never be a valid name without an lv */ #ifdef DEBUG_REFCNT memset(varname.c, '\0', SIZEOF(varname)); memcpy(varname.c, tabent->key.var_name.addr, tabent->key.var_name.len); DBGRFCT((stderr, "lookup_variable_htent: Allocating lv_val for variable '%s'\n", varname.c)); #endif lv_newname(tabent, curr_symval); } assert(NULL != LV_GET_SYMVAL((lv_val *)tabent->value)); return tabent; } fis-gtm-V6.0-003/sr_port/lookup_variable_htent.h0000644000032200000250000000110512201176160020554 0ustar librarygtc/**************************************************************** * * * Copyright 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __LOOKUP_VARIABLE_HTENT_H__ #define __LOOKUP_VARIABLE_HTENT_H__ ht_ent_mname *lookup_variable_htent(unsigned int x); #endif fis-gtm-V6.0-003/sr_port/lower_to_upper.c0000644000032200000250000000127712201176160017246 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_caseconv.h" LITREF unsigned char lower_to_upper_table[]; void lower_to_upper(uchar_ptr_t d, uchar_ptr_t s, int4 len) { uchar_ptr_t d_top; d_top = d + len; for ( ; d < d_top; ) { *d++ = lower_to_upper_table[*s++]; } } fis-gtm-V6.0-003/sr_port/lref.c0000644000032200000250000000376312201176160015133 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "cmd_qlf.h" #include "advancewindow.h" #include "gtm_caseconv.h" GBLREF command_qualifier cmd_qlf; LITREF mident zero_ident; error_def(ERR_LABELEXPECTED); int lref(oprtype *label, oprtype *offset, boolean_t no_lab_ok, mint commarg_code, boolean_t commarg_ok, boolean_t *got_some) { char c; triple *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; switch (TREF(window_token)) { case TK_INTLIT: int_label(); /* caution: fall through */ case TK_IDENT: *got_some = TRUE; if (!(cmd_qlf.qlf & CQ_LOWER_LABELS)) lower_to_upper((uchar_ptr_t)(TREF(window_ident)).addr, (uchar_ptr_t)(TREF(window_ident)).addr, (TREF(window_ident)).len); *label = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); advancewindow(); break; case TK_ATSIGN: *got_some = TRUE; if (!indirection(label)) return FALSE; if (commarg_ok && (TK_COLON != (c = TREF(window_token))) && (TK_CIRCUMFLEX != c) && (TK_PLUS != c)) /* NOTE assignment */ { ref = newtriple(OC_COMMARG); ref->operand[0] = *label; ref->operand[1] = put_ilit(commarg_code); *label = put_tref(ref); return TRUE; } break; case TK_COLON: case TK_CIRCUMFLEX: return TRUE; case TK_PLUS: *label = put_str(zero_ident.addr, zero_ident.len); if (no_lab_ok) break; /* caution: fall through */ default: stx_error(ERR_LABELEXPECTED); return FALSE; } if (TK_PLUS != TREF(window_token)) return TRUE; *got_some = TRUE; advancewindow(); return expr(offset, MUMPS_INT); } fis-gtm-V6.0-003/sr_port/lv_getslot.c0000644000032200000250000000733312201176160016362 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "lv_val.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "caller_id.h" #include "alias.h" lv_val *lv_getslot(symval *sym) { lv_blk *p,*q; lv_val *lv; unsigned int numElems, numUsed; numElems = MAXUINT4; /* maximum value */ if (lv = sym->lv_flist) { assert(NULL == LV_PARENT(lv)); /* stp_gcol relies on this for correct garbage collection */ sym->lv_flist = (lv_val *)lv->ptrs.free_ent.next_free; } else { for (p = sym->lv_first_block; ; p = p->next) { if (NULL == p) { if (NULL != (p = sym->lv_first_block)) numElems = p->numAlloc; else { assert(FALSE); numElems = LV_NEWBLOCK_INIT_ALLOC; /* be safe in pro */ } lv_newblock(sym, numElems > 64 ? 128 : numElems * 2); p = sym->lv_first_block; assert(NULL != p); } if ((numUsed = p->numUsed) < p->numAlloc) { lv = (lv_val *)LV_BLK_GET_BASE(p); lv = &lv[numUsed]; p->numUsed++; break; } assert(numElems >= p->numAlloc); DEBUG_ONLY(numElems = p->numAlloc); } } assert(lv); DBGRFCT((stderr, ">> lv_getslot(): Allocating new lv_val at 0x"lvaddr" by routine 0x"lvaddr"\n", lv, caller_id())); return lv; } lvTree *lvtree_getslot(symval *sym) { lv_blk *p,*q; lvTree *lvt; unsigned int numElems, numUsed; numElems = MAXUINT4; /* maximum value */ if (lvt = sym->lvtree_flist) { assert(NULL == LVT_GET_PARENT(lvt)); sym->lvtree_flist = (lvTree *)lvt->avl_root; } else { for (p = sym->lvtree_first_block; ; p = p->next) { if (NULL == p) { if (NULL != (p = sym->lvtree_first_block)) numElems = p->numAlloc; else numElems = LV_NEWBLOCK_INIT_ALLOC; lvtree_newblock(sym, numElems > 64 ? 128 : numElems * 2); p = sym->lvtree_first_block; assert(NULL != p); } if ((numUsed = p->numUsed) < p->numAlloc) { lvt = (lvTree *)LV_BLK_GET_BASE(p); lvt = &lvt[numUsed]; p->numUsed++; break; } assert(numElems >= p->numAlloc); DEBUG_ONLY(numElems = p->numAlloc); } } assert(lvt); DBGRFCT((stderr, ">> lvtree_getslot(): Allocating new lvTree at 0x"lvaddr" by routine 0x"lvaddr"\n", lvt, caller_id())); return lvt; } lvTreeNode *lvtreenode_getslot(symval *sym) { lv_blk *p,*q; lvTreeNode *lv; unsigned int numElems, numUsed; numElems = MAXUINT4; /* maximum value */ if (lv = sym->lvtreenode_flist) { assert(NULL == LV_PARENT(lv)); /* stp_gcol relies on this for correct garbage collection */ sym->lvtreenode_flist = (lvTreeNode *)lv->sbs_child; } else { for (p = sym->lvtreenode_first_block; ; p = p->next) { if (NULL == p) { if (NULL != (p = sym->lvtreenode_first_block)) numElems = p->numAlloc; else numElems = LV_NEWBLOCK_INIT_ALLOC; lvtreenode_newblock(sym, numElems > 64 ? 128 : numElems * 2); p = sym->lvtreenode_first_block; assert(NULL != p); } if ((numUsed = p->numUsed) < p->numAlloc) { lv = (lvTreeNode *)LV_BLK_GET_BASE(p); lv = &lv[numUsed]; p->numUsed++; break; } assert(numElems >= p->numAlloc); DEBUG_ONLY(numElems = p->numAlloc); } } assert(lv); DBGRFCT((stderr, ">> lvtreenode_getslot(): Allocating new lvTreeNode at 0x"lvaddr" by routine 0x"lvaddr"\n", lv, caller_id())); return lv; } fis-gtm-V6.0-003/sr_port/lv_kill.c0000644000032200000250000000500512201176160015626 0ustar librarygtc/**************************************************************** * * * Copyright 2009, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "lv_val.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "alias.h" GBLREF lv_val *active_lv; GBLREF uint4 dollar_tlevel; void lv_kill(lv_val *lv, boolean_t dotpsave, boolean_t do_subtree) { lv_val *base_lv; lvTree *lvt_child, *lvt; boolean_t is_base_var; symval *sym; active_lv = (lv_val *)NULL; /* if we get here, subscript set was successful. clear active_lv to avoid later cleanup problems */ if (lv) { is_base_var = LV_IS_BASE_VAR(lv); base_lv = !is_base_var ? LV_GET_BASE_VAR(lv) : lv; if (dotpsave && dollar_tlevel && (NULL != base_lv->tp_var) && !base_lv->tp_var->var_cloned) TP_VAR_CLONE(base_lv); /* clone the tree */ lvt_child = LV_GET_CHILD(lv); if (do_subtree && (NULL != lvt_child)) { LV_CHILD(lv) = NULL; lv_killarray(lvt_child, dotpsave); } DECR_AC_REF(lv, dotpsave); /* Decrement alias container refs and cleanup if necessary */ if (!is_base_var && (do_subtree || (NULL == lvt_child))) { sym = LV_GET_SYMVAL(base_lv); for ( ; ; ) { lvt = LV_GET_PARENT_TREE(lv); LV_VAL_CLEAR_MVTYPE(lv); /* see comment in macro definition for why this is necessary */ LV_TREE_NODE_DELETE(lvt, (lvTreeNode *)lv); /* if there is at least one other sibling node to the deleted "lv" the zap stops here */ if (lvt->avl_height) break; assert(NULL == lvt->avl_root); lv = (lv_val *)LVT_PARENT(lvt); assert(NULL != lv); LV_CHILD(lv) = NULL; LVTREE_FREESLOT(lvt); assert(LV_IS_VAL_DEFINED(lv) == (0 != lv->v.mvtype)); if (LV_IS_VAL_DEFINED(lv)) break; if (lv == base_lv) { /* Base node. Do not invoke LV_FREESLOT/LV_FLIST_ENQUEUE as we will still keep the * lv_val for the non-existing base local variable pointed to by the curr_symval * hash table entry. Just clear mvtype to mark the lv_val undefined. */ lv->v.mvtype = 0; /* Base node */ break; } } } else lv->v.mvtype = 0; /* Base node */ } } fis-gtm-V6.0-003/sr_port/lv_killarray.c0000644000032200000250000000465212201176160016674 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #include "lv_val.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "alias.h" /* Note it is important that callers of this routine make sure that the pointer that is passed as * an argument is removed from the lv_val it came from prior to the call. This prevents arrays * that have alias containers pointing that form a loop back to the originating lv_val from causing * processing loops, in effect over-processing arrays that have already been processed or lv_vals * that have been deleted. */ void lv_killarray(lvTree *lvt, boolean_t dotpsave) { lvTreeNode *node, *nextnode; lvTree *tmplvt; DEBUG_ONLY( lv_val *lv; assert(NULL != lvt); lv = (lv_val *)LVT_PARENT(lvt); assert(NULL == LV_CHILD(lv)); /* Owner lv's children pointer MUST be NULL! */ ) /* Iterate through the tree in post-order fashion. Doing it in-order or pre-order has issues since we would have * freed up nodes in the tree but would need to access links in them to get at the NEXT node. */ for (node = lvAvlTreeFirstPostOrder(lvt); NULL != node; node = nextnode) { nextnode = lvAvlTreeNextPostOrder(node); /* determine "nextnode" before freeing "node" */ assert(NULL != node); tmplvt = LV_CHILD(node); if (NULL != tmplvt) { LV_CHILD(node) = NULL; lv_killarray(tmplvt, dotpsave); } DECR_AC_REF(((lv_val *)node), dotpsave); /* Decrement alias contain ref and cleanup if necessary */ /* If node points to an "lv_val", we need to do a heavyweight LV_FREESLOT call to free up the lv_val. * But we instead do a simple "LVTREENODE_FREESLOT" call because we are guaranteed node points to a "lvTreeNode" * (i.e. it is a subscripted lv and never the base lv). Assert that. */ assert(!LV_IS_BASE_VAR(node)); LV_VAL_CLEAR_MVTYPE(node); /* see comment in macro definition for why this is necessary */ LVTREENODE_FREESLOT(node); } LVTREE_FREESLOT(lvt); } fis-gtm-V6.0-003/sr_port/lv_newblock.c0000644000032200000250000000537112201176160016505 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_stdio.h" #include "gtm_malloc.h" #include "lv_val.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "alias.h" void lv_newblock(symval *sym, int numElems) { register lv_blk *ptr; register int n; lv_val *lv_base; n = numElems * SIZEOF(lv_val) + SIZEOF(lv_blk); n = INTCAST(gtm_bestfitsize(n)); /* Maximize use of storage block we are going to get */ assert(DIVIDE_ROUND_DOWN(n - SIZEOF(lv_blk), SIZEOF(lv_val)) >= numElems); numElems = DIVIDE_ROUND_DOWN(n - SIZEOF(lv_blk), SIZEOF(lv_val)); ptr = (lv_blk *)malloc(n); lv_base = (lv_val *)LV_BLK_GET_BASE(ptr); memset(lv_base, 0, numElems * SIZEOF(lv_val)); ptr->next = sym->lv_first_block; sym->lv_first_block = ptr; ptr->numAlloc = numElems; ptr->numUsed = 0; DBGRFCT((stderr, "lv_newblock: New lv_blk allocated ******************\n")); } void lvtree_newblock(symval *sym, int numElems) { register lv_blk *ptr; register int n; lvTree *lvt_base; n = numElems * SIZEOF(lvTree) + SIZEOF(lv_blk); n = INTCAST(gtm_bestfitsize(n)); /* Maximize use of storage block we are going to get */ assert(DIVIDE_ROUND_DOWN(n - SIZEOF(lv_blk), SIZEOF(lvTree)) >= numElems); numElems = DIVIDE_ROUND_DOWN(n - SIZEOF(lv_blk), SIZEOF(lvTree)); ptr = (lv_blk *)malloc(n); lvt_base = (lvTree *)LV_BLK_GET_BASE(ptr); ptr->next = sym->lvtree_first_block; sym->lvtree_first_block = ptr; ptr->numAlloc = numElems; ptr->numUsed = 0; DBGRFCT((stderr, "lvtree_newblock: New lv_blk allocated ******************\n")); } void lvtreenode_newblock(symval *sym, int numElems) { register lv_blk *ptr; register int n; lvTreeNode *lv_base; n = numElems * SIZEOF(lvTreeNode) + SIZEOF(lv_blk); n = INTCAST(gtm_bestfitsize(n)); /* Maximize use of storage block we are going to get */ assert(DIVIDE_ROUND_DOWN(n - SIZEOF(lv_blk), SIZEOF(lvTreeNode)) >= numElems); numElems = DIVIDE_ROUND_DOWN(n - SIZEOF(lv_blk), SIZEOF(lvTreeNode)); ptr = (lv_blk *)malloc(n); lv_base = (lvTreeNode *)LV_BLK_GET_BASE(ptr); memset(lv_base, 0, numElems * SIZEOF(lvTreeNode)); ptr->next = sym->lvtreenode_first_block; sym->lvtreenode_first_block = ptr; ptr->numAlloc = numElems; ptr->numUsed = 0; DBGRFCT((stderr, "lvtreenode_newblock: New lv_blk allocated ******************\n")); } fis-gtm-V6.0-003/sr_port/lv_newname.c0000644000032200000250000000533512201176177016343 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "gtm_string.h" #include #include "stack_frame.h" #include "mv_stent.h" #include "lv_val.h" #include "tp_frame.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "caller_id.h" #include "alias.h" GBLREF tp_frame *tp_pointer; GBLREF stack_frame *frame_pointer; GBLREF symval *curr_symval; GBLREF mv_stent *mv_chain; void lv_newname(ht_ent_mname *hte, symval *sym) { lv_val *lv, *var; tp_frame *tf, *first_tf_saveall; tp_var *restore_ent; DBGRFCT_ONLY(mident_fixed vname;) assert(hte); assert(sym); lv = lv_getslot(sym); LVVAL_INIT(lv, sym); DBGRFCT_ONLY( memcpy(vname.c, hte->key.var_name.addr, hte->key.var_name.len); vname.c[hte->key.var_name.len] = '\0'; ); DBGRFCT((stderr, "lv_newname: Varname '%s' in sym 0x"lvaddr" resetting hte 0x"lvaddr" from 0x"lvaddr" to 0x"lvaddr " -- called from 0x"lvaddr"\n\n", &vname.c, sym, hte, hte->value, lv, caller_id())); hte->value = lv; assert(0 < lv->stats.trefcnt); if (!sym->tp_save_all) return; /* Newly encountered variables need to be saved if there is restore all TP frame in effect as they need to be restored to an undefined state but we only know about them when we encounter them hence this code where new vars are created. We locate the earliest TP frame that has the same symval in its tp_frame and save the entry there. This is so var set in later TP frame levels still get restored even if the TSTART frame they were created in gets committed. */ DEBUG_ONLY(first_tf_saveall = NULL); for (tf = tp_pointer; (NULL != tf) && (tf->sym == sym); tf = tf->old_tp_frame) { if (tf->tp_save_all_flg) first_tf_saveall = tf; } assert(first_tf_saveall); assert(sym == LV_SYMVAL(lv)); var = lv_getslot(sym); restore_ent = (tp_var *)malloc(SIZEOF(*restore_ent)); restore_ent->current_value = lv; restore_ent->save_value = var; restore_ent->key = hte->key; restore_ent->var_cloned = TRUE; restore_ent->next = first_tf_saveall->vars; first_tf_saveall->vars = restore_ent; assert(NULL == lv->tp_var); lv->tp_var = restore_ent; *var = *lv; INCR_CREFCNT(lv); /* With a copy made, bump the refcnt to keep lvval from being deleted */ INCR_TREFCNT(lv); assert(1 < lv->stats.trefcnt); } fis-gtm-V6.0-003/sr_port/lv_tree.c0000644000032200000250000023667512201176160015655 0ustar librarygtc/**************************************************************** * * * Copyright 2011, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include /* for OFFSETOF macro used in the IS_OFFSET_AND_SIZE_MATCH macro */ #include "collseq.h" #include "subscript.h" #include "lv_tree.h" #include "gtm_stdio.h" #include "min_max.h" #include "lv_val.h" #include "numcmp.h" #include "arit.h" #include "promodemo.h" /* for "promote" & "demote" prototype */ #include "gtmio.h" #include "have_crit.h" #define LV_TREE_INIT_ALLOC 4 #define LV_TREENODE_INIT_ALLOC 16 #define LV_TREESUBSCR_INIT_ALLOC 16 /* the below assumes TREE_LEFT_HEAVY is 0, TREE_RIGHT_HEAVY is 1 and TREE_BALANCED is 2 */ LITDEF int tree_balance_invert[] = {TREE_RIGHT_HEAVY, TREE_LEFT_HEAVY, TREE_BALANCED}; LITREF mval literal_null; LITREF int4 ten_pwr[NUM_DEC_DG_1L+1]; STATICFNDCL void lvAvlTreeNodeFltConv(lvTreeNodeNum *fltNode); STATICFNDCL lvTreeNode *lvAvlTreeSingleRotation(lvTreeNode *rebalanceNode, lvTreeNode *anchorNode, int4 balanceFactor); STATICFNDCL lvTreeNode *lvAvlTreeDoubleRotation(lvTreeNode *rebalanceNode, lvTreeNode *anchorNode, int4 balanceFactor); STATICFNDCL boolean_t lvAvlTreeLookupKeyCheck(treeKeySubscr *key); STATICFNDCL int lvAvlTreeNodeHeight(lvTreeNode *node); STATICFNDCL boolean_t lvAvlTreeNodeIsWellFormed(lvTree *lvt, lvTreeNode *node); STATICFNDEF void lvAvlTreeNodeFltConv(lvTreeNodeNum *fltNode) { int int_m1, int_exp; const int4 *pwr; DEBUG_ONLY(int key_mvtype;) DEBUG_ONLY(key_mvtype = fltNode->key_mvtype;) assert(MV_INT & key_mvtype); assert(!fltNode->key_flags.key_bits.key_iconv); int_m1 = fltNode->key_m0; if (int_m1) { /* The following logic is very similar to that in promodemo.c (promote function). * That operates on mvals whereas this does not hence the duplication inspite of similar logic. */ if (0 < int_m1) fltNode->key_flags.key_bits.key_sgn = 0; else { fltNode->key_flags.key_bits.key_sgn = 1; int_m1 = -int_m1; } int_exp = 0; pwr = &ten_pwr[0]; while (int_m1 >= *pwr) { int_exp++; pwr++; assert(pwr < ARRAYTOP(ten_pwr)); } fltNode->key_m1 = int_m1 * ten_pwr[NUM_DEC_DG_1L - int_exp] ; int_exp += EXP_INT_UNDERF; fltNode->key_flags.key_bits.key_e = int_exp; } else fltNode->key_flags.key_bits.key_e = 0; /* integer 0 will have exponent 0 even after float promotion */ fltNode->key_flags.key_bits.key_iconv = TRUE; return; } /* All the below comparison macros & functions return * = 0 if equal; * < 0 if key of aSUBSCR < key of bNODE; * > 0 if key of aSUBSCR > key of bNODE * The 3 LV_AVL_TREE_*KEY_CMP macros below have very similar (yet not completely identical) code. * They are kept separate because this is frequently used code and we want to avoid if checks as much as possible. * Having separate macros for each keytype lets us reduce the # of if checks we need inside the macro. */ #define LV_AVL_TREE_INTKEY_CMP(aSUBSCR, aSUBSCR_M1, bNODE, retVAL) \ { \ int a_m1, b_mvtype, a_sgn, b_sgn, exp_diff, m1_diff, m0_diff, b_m0; \ lvTreeNodeNum *bNodeFlt; \ treeKeySubscr fltSubscr, *tmpASubscr; \ \ /* aSUBSCR is a number */ \ assert(TREE_KEY_SUBSCR_IS_CANONICAL((aSUBSCR)->mvtype)); \ assert(MVTYPE_IS_INT((aSUBSCR)->mvtype)); \ b_mvtype = (bNODE)->key_mvtype; \ assert(!TREE_KEY_SUBSCR_IS_CANONICAL(b_mvtype) \ || (MVTYPE_IS_NUMERIC(b_mvtype) && !MVTYPE_IS_NUM_APPROX(b_mvtype))); \ assert(MVTYPE_IS_NUMERIC((aSUBSCR)->mvtype) && !MVTYPE_IS_NUM_APPROX((aSUBSCR)->mvtype)); \ assert((aSUBSCR_M1) == (aSUBSCR)->m[1]); \ if (MV_INT & b_mvtype) \ { \ bNodeFlt = (lvTreeNodeNum *)(bNODE); \ (retVAL) = (aSUBSCR_M1) - bNodeFlt->key_m0; \ } else if (TREE_KEY_SUBSCR_IS_CANONICAL(b_mvtype)) \ { /* Both aSUBSCR and bNODE are numbers */ \ b_mvtype &= MV_INT; \ /* aSUBSCR is MV_INT but bNODE is not. Promote aSubscr to float representation before comparing \ * it with bNODE. Cannot touch input mval since non-lv code expects MV_INT value to be stored in \ * integer format only (and not float format). So use a temporary mval for comparison. \ */ \ fltSubscr.m[1] = (aSUBSCR_M1); \ tmpASubscr = &fltSubscr; \ promote(tmpASubscr); /* Note this modifies tmpASubscr->m[1] so no longer can use aSUBSCR_M1 below */ \ assert(tmpASubscr->e || !tmpASubscr->m[1]); \ bNodeFlt = (lvTreeNodeNum *)(bNODE); \ if (b_mvtype && !bNodeFlt->key_flags.key_bits.key_iconv) \ { \ lvAvlTreeNodeFltConv(bNodeFlt); \ assert(bNodeFlt->key_flags.key_bits.key_iconv); \ } \ a_sgn = (0 == tmpASubscr->sgn) ? 1 : -1; /* 1 if positive, -1 if negative */ \ b_sgn = (0 == bNodeFlt->key_flags.key_bits.key_sgn) ? 1 : -1; \ /* Check sign. If different we are done right there */ \ if (a_sgn != b_sgn) \ (retVAL) = a_sgn; \ else \ { /* Signs equal; compare exponents for magnitude and adjust sense depending on sign. */ \ exp_diff = tmpASubscr->e - bNodeFlt->key_flags.key_bits.key_e; \ if (exp_diff) \ (retVAL) = (exp_diff * a_sgn); \ else \ { /* Signs and exponents equal; compare magnitudes. */ \ /* First, compare high-order 9 digits of magnitude. */ \ a_m1 = tmpASubscr->m[1]; \ m1_diff = a_m1 - bNodeFlt->key_m1; \ if (m1_diff) \ (retVAL) = (m1_diff * a_sgn); \ else \ { /* High-order 9 digits equal; if not zero, compare low-order 9 digits. */ \ if (0 == a_m1) /* zero special case */ \ (retVAL) = 0; \ else \ { \ b_m0 = (b_mvtype ? 0 : bNodeFlt->key_m0); \ m0_diff = tmpASubscr->m[0] - b_m0; \ if (m0_diff) \ (retVAL) = (m0_diff * a_sgn); \ else \ { /* Signs, exponents, high-order & low-order magnitudes equal */ \ (retVAL) = 0; \ } \ } \ } \ } \ } \ } else \ (retVAL) = -1; /* aSubscr is a number, but bNODE is a string */ \ } #define LV_AVL_TREE_NUMKEY_CMP(aSUBSCR, bNODE, retVAL) \ { \ int b_mvtype, a_sgn, b_sgn, exp_diff, m1_diff, m0_diff, a_m1, b_m0; \ lvTreeNodeNum *bNodeFlt; \ \ /* aSUBSCR is a number */ \ assert(TREE_KEY_SUBSCR_IS_CANONICAL((aSUBSCR)->mvtype)); \ assert(!MVTYPE_IS_INT((aSUBSCR)->mvtype)); \ b_mvtype = (bNODE)->key_mvtype; \ assert(!TREE_KEY_SUBSCR_IS_CANONICAL(b_mvtype) \ || (MVTYPE_IS_NUMERIC(b_mvtype) && !MVTYPE_IS_NUM_APPROX(b_mvtype))); \ assert(MVTYPE_IS_NUMERIC((aSUBSCR)->mvtype) && !MVTYPE_IS_NUM_APPROX((aSUBSCR)->mvtype)); \ if (TREE_KEY_SUBSCR_IS_CANONICAL(b_mvtype)) \ { /* Both aSUBSCR and bNODE are numbers */ \ b_mvtype &= MV_INT; \ bNodeFlt = (lvTreeNodeNum *)(bNODE); \ if (b_mvtype && !bNodeFlt->key_flags.key_bits.key_iconv) \ { \ lvAvlTreeNodeFltConv(bNodeFlt); \ assert(bNodeFlt->key_flags.key_bits.key_iconv); \ } \ a_sgn = (0 == (aSUBSCR)->sgn) ? 1 : -1; /* 1 if positive, -1 if negative */ \ b_sgn = (0 == bNodeFlt->key_flags.key_bits.key_sgn) ? 1 : -1; \ /* Check sign. If different we are done right there */ \ if (a_sgn != b_sgn) \ (retVAL) = a_sgn; \ else \ { /* Signs equal; compare exponents for magnitude and adjust sense depending on sign. */ \ exp_diff = (aSUBSCR)->e - bNodeFlt->key_flags.key_bits.key_e; \ if (exp_diff) \ (retVAL) = (exp_diff * a_sgn); \ else \ { /* Signs and exponents equal; compare magnitudes. */ \ /* First, compare high-order 9 digits of magnitude. */ \ a_m1 = (aSUBSCR)->m[1]; \ m1_diff = a_m1 - bNodeFlt->key_m1; \ if (m1_diff) \ (retVAL) = (m1_diff * a_sgn); \ else \ { /* High-order 9 digits equal; if not zero, compare low-order 9 digits. */ \ if (0 == a_m1) /* zero special case */ \ (retVAL) = 0; \ else \ { \ b_m0 = (b_mvtype ? 0 : bNodeFlt->key_m0); \ m0_diff = (aSUBSCR)->m[0] - b_m0; \ if (m0_diff) \ (retVAL) = (m0_diff * a_sgn); \ else \ { /* Signs, exponents, high-order & low-order magnitudes equal */ \ (retVAL) = 0; \ } \ } \ } \ } \ } \ } else \ (retVAL) = -1; /* aSUBSCR is a number, but bNODE is a string */ \ } #define LV_AVL_TREE_STRKEY_CMP(aSUBSCR, aSUBSCR_ADDR, aSUBSCR_LEN, bNODE, retVAL) \ { \ /* aSUBSCR is a string */ \ assert(!TREE_KEY_SUBSCR_IS_CANONICAL((aSUBSCR)->mvtype)); \ assert(MVTYPE_IS_STRING((aSUBSCR)->mvtype)); \ if (TREE_KEY_SUBSCR_IS_CANONICAL((bNODE)->key_mvtype)) \ (retVAL) = 1; /* aSUBSCR is a string, but bNODE is a number */ \ else /* aSUBSCR and bNODE are both strings */ \ MEMVCMP(aSUBSCR_ADDR, aSUBSCR_LEN, (bNODE)->key_addr, (bNODE)->key_len, (retVAL)); \ } #ifdef DEBUG /* This function is currently DEBUG-only because no one is supposed to be calling it. * Callers are usually performance sensitive and should therefore use the LV_AVL_TREE_NUMKEY_CMP * or LV_AVL_TREE_STRKEY_CMP macros that this function in turn invokes. */ int lvAvlTreeKeySubscrCmp(treeKeySubscr *aSubscr, lvTreeNode *bNode) { int retVal, a_mvtype; a_mvtype = aSubscr->mvtype; if (TREE_KEY_SUBSCR_IS_CANONICAL(a_mvtype)) { if (MVTYPE_IS_INT(a_mvtype)) { LV_AVL_TREE_INTKEY_CMP(aSubscr, aSubscr->m[1], bNode, retVal); } else LV_AVL_TREE_NUMKEY_CMP(aSubscr, bNode, retVal); } else LV_AVL_TREE_STRKEY_CMP(aSubscr, aSubscr->str.addr, aSubscr->str.len, bNode, retVal); return retVal; } /* This function is currently coded not as efficiently as it needs to be because it is only invoked by dbg code. * Hence the definition inside a #ifdef DEBUG. If this change and pro code needs it, the below code needs to be revisited. */ int lvAvlTreeNodeSubscrCmp(lvTreeNode *aNode, lvTreeNode *bNode) { int a_mvtype, b_mvtype, retVal; int a_sgn, b_sgn, exp_diff, m1_diff, m0_diff, a_m1, b_m1, a_m0, b_m0; lvTreeNodeNum *aNodeFlt, *bNodeFlt; a_mvtype = aNode->key_mvtype; b_mvtype = bNode->key_mvtype; if (TREE_KEY_SUBSCR_IS_CANONICAL(a_mvtype)) { /* aSubscr is a number */ assert(!MVTYPE_IS_STRING(a_mvtype)); if (TREE_KEY_SUBSCR_IS_CANONICAL(b_mvtype)) { /* Both aNode and bNode are numbers */ assert(!MVTYPE_IS_STRING(b_mvtype)); aNodeFlt = (lvTreeNodeNum *)aNode; bNodeFlt = (lvTreeNodeNum *)bNode; a_mvtype = a_mvtype & MV_INT; if (a_mvtype & b_mvtype) { /* Both aNode & bNode are integers */ a_m1 = aNodeFlt->key_m0; b_m1 = bNodeFlt->key_m0; return (a_m1 - b_m1); } if (a_mvtype) { if (!aNodeFlt->key_flags.key_bits.key_iconv) lvAvlTreeNodeFltConv(aNodeFlt); assert(aNodeFlt->key_flags.key_bits.key_iconv); } else if (b_mvtype = (MV_INT & b_mvtype)) { if (!bNodeFlt->key_flags.key_bits.key_iconv) lvAvlTreeNodeFltConv(bNodeFlt); assert(bNodeFlt->key_flags.key_bits.key_iconv); } a_sgn = (0 == aNodeFlt->key_flags.key_bits.key_sgn) ? 1 : -1; /* 1 if positive, -1 if negative */ b_sgn = (0 == bNodeFlt->key_flags.key_bits.key_sgn) ? 1 : -1; /* Check sign. If different we are done right there */ if (a_sgn != b_sgn) return a_sgn; /* Signs equal; compare exponents for magnitude and adjust sense depending on sign. */ exp_diff = aNodeFlt->key_flags.key_bits.key_e - bNodeFlt->key_flags.key_bits.key_e; if (exp_diff) return (exp_diff * a_sgn); /* Signs and exponents equal; compare magnitudes. */ /* First, compare high-order 9 digits of magnitude. */ a_m1 = aNodeFlt->key_m1; m1_diff = a_m1 - bNodeFlt->key_m1; if (m1_diff) return (m1_diff * a_sgn); /* High-order 9 digits equal; if not zero, compare low-order 9 digits. */ if (0 == a_m1) /* zero special case */ return 0; /* If key_iconv is TRUE, key_m0 is not lower-order 9 digits but instead is MV_INT representation */ a_m0 = (a_mvtype && aNodeFlt->key_flags.key_bits.key_iconv) ? 0 : aNodeFlt->key_m0; b_m0 = (b_mvtype && bNodeFlt->key_flags.key_bits.key_iconv) ? 0 : bNodeFlt->key_m0; m0_diff = a_m0 - b_m0; if (m0_diff) return (m0_diff * a_sgn); /* Signs, exponents, high-order magnitudes, and low-order magnitudes equal. */ return 0; } /* aNode is a number, but bNode is a string */ return(-1); } /* aNode is a string */ assert(MVTYPE_IS_STRING(a_mvtype)); if (TREE_KEY_SUBSCR_IS_CANONICAL(b_mvtype)) { assert(!MVTYPE_IS_STRING(b_mvtype)); return(1); /* aNode is a string, but bNode is a number */ } /* aNode and bNode are both strings */ assert(MVTYPE_IS_STRING(b_mvtype)); MEMVCMP(aNode->key_addr, aNode->key_len, bNode->key_addr, bNode->key_len, retVal); return retVal; } #endif /* Return first in-order traversal node (also smallest collating key) in avl tree. Returns NULL if NO key in tree */ lvTreeNode *lvAvlTreeFirst(lvTree *lvt) { lvTreeNode *avl_first, *next; next = lvt->avl_root; if (NULL == next) return NULL; do { avl_first = next; next = next->avl_left; } while (NULL != next); return avl_first; } /* Return last (highest collating) key in avl tree. Returns NULL if NO key in tree */ lvTreeNode *lvAvlTreeLast(lvTree *lvt) { lvTreeNode *avl_last, *next; next = lvt->avl_root; if (NULL == next) return NULL; do { avl_last = next; next = next->avl_right; } while (NULL != next); return avl_last; } /* Returns the in-order predecessor of the input "node". * Assumes input is in the avl tree and operates within the avl tree only. */ lvTreeNode *lvAvlTreePrev(lvTreeNode *node) { lvTreeNode *prev, *tmp, *parent; assert(NULL != node); prev = node->avl_left; if (NULL != prev) { /* in-order predecessor is BELOW "node" */ tmp = prev->avl_right; while (NULL != tmp) { prev = tmp; tmp = prev->avl_right; } } else { /* in-order predecessor is an ancestor of "node" or could be "" (because "node" is the BIGGEST key in tree) */ parent = node->avl_parent; tmp = node; while (NULL != parent) { if (parent->avl_right == tmp) { prev = parent; break; } assert(parent->avl_left == tmp); tmp = parent; parent = tmp->avl_parent; } } return prev; } /* Return "node" in AVL tree IMMEDIATELY BEFORE input "key" */ lvTreeNode *lvAvlTreeKeyPrev(lvTree *lvt, treeKeySubscr *key) { lvTreeNode *node, *tmp, *prev, *parent; node = lvAvlTreeLookup(lvt, key, &parent); if (NULL != node) /* most common case */ { prev = lvAvlTreePrev(node); assert((NULL == prev) || (0 < lvAvlTreeKeySubscrCmp(key, prev))); } else { assert(NULL != parent); /* lvAvlTreeLookup should have initialized this */ if (TREE_DESCEND_LEFT == parent->descent_dir) { assert(NULL == parent->avl_left); assert(0 > lvAvlTreeKeySubscrCmp(key, parent)); prev = lvAvlTreePrev(parent); assert((NULL == prev) || (0 < lvAvlTreeKeySubscrCmp(key, prev))); } else { assert(NULL == parent->avl_right); assert(0 < lvAvlTreeKeySubscrCmp(key, parent)); DEBUG_ONLY(tmp = lvAvlTreeNext(parent);) assert((NULL == tmp) || (0 > lvAvlTreeKeySubscrCmp(key, tmp))); prev = parent; } } return prev; } /* Returns the in-order successor of the input "node". * Assumes input is in the avl tree and operates within the avl tree. */ lvTreeNode *lvAvlTreeNext(lvTreeNode *node) { lvTreeNode *next, *tmp, *parent; DEBUG_ONLY(lvTree *lvt;) assert(NULL != node); next = node->avl_right; if (NULL != next) { /* in-order successor is BELOW "node" */ tmp = next->avl_left; while (NULL != tmp) { next = tmp; tmp = next->avl_left; } } else { /* in-order successor is an ancestor of "node" or could be "" (because "node" is the BIGGEST key in tree) */ parent = node->avl_parent; tmp = node; while (NULL != parent) { if (parent->avl_left == tmp) { next = parent; break; } assert(parent->avl_right == tmp); tmp = parent; parent = tmp->avl_parent; } } assert((NULL == next) || (node == lvAvlTreePrev(next))); return next; } /* Return "node" in AVL tree IMMEDIATELY AFTER input "key" */ lvTreeNode *lvAvlTreeKeyNext(lvTree *lvt, treeKeySubscr *key) { lvTreeNode *node, *tmp, *next, *parent; node = lvAvlTreeLookup(lvt, key, &parent); if (NULL != node) /* most common case */ { next = lvAvlTreeNext(node); assert((NULL == next) || (0 > lvAvlTreeKeySubscrCmp(key, next))); } else { assert(NULL != parent); /* lvAvlTreeLookup should have initialized this */ if (TREE_DESCEND_RIGHT == parent->descent_dir) { assert(NULL == parent->avl_right); assert(0 < lvAvlTreeKeySubscrCmp(key, parent)); next = lvAvlTreeNext(parent); assert((NULL == next) || (0 > lvAvlTreeKeySubscrCmp(key, next))); } else { assert(NULL == parent->avl_left); assert(0 > lvAvlTreeKeySubscrCmp(key, parent)); DEBUG_ONLY(tmp = lvAvlTreePrev(parent);) assert((NULL == tmp) || (0 < lvAvlTreeKeySubscrCmp(key, tmp))); next = parent; } } return next; } /* Return first post-order traversal node in avl tree. Returns NULL if NO key in tree */ lvTreeNode *lvAvlTreeFirstPostOrder(lvTree *lvt) { lvTreeNode *first, *tmp; first = lvt->avl_root; if (NULL == first) return NULL; /* Look for first post-order traversal node under left subtree if any. If not look under right sub-tree. * If neither is present, then this node is it. */ do { if ((NULL != (tmp = first->avl_left)) || (NULL != (tmp = first->avl_right))) first = tmp; /* need to go further down the tree to find post-order successor */ else break; /* found leaf-level post-order successor */ } while (TRUE); return first; } /* Returns the post-order successor of the input "node". Assumes input is in the avl tree and operates within the avl tree. */ lvTreeNode *lvAvlTreeNextPostOrder(lvTreeNode *node) { lvTreeNode *next, *tmp, *parent; assert(NULL != node); parent = node->avl_parent; if (NULL == parent) /* Reached root node of the AVL tree in the post order traversal */ return NULL; /* Done with post-order traversal */ if (node == parent->avl_right) /* done with "node" and its subtree so post-order successor is "parent" */ return parent; assert(node == parent->avl_left); /* Post-order successor will be in the right subtree of "parent" */ next = parent->avl_right; if (NULL == next) return parent; /* No right subtree so "parent" it is */ /* Find post-order successor under the right subtree. Use logic similar to "lvAvlTreeFirstPostOrder" */ do { if ((NULL != (tmp = next->avl_left)) || (NULL != (tmp = next->avl_right))) next = tmp; /* need to go further down the tree to find post-order successor */ else break; /* found leaf-level post-order successor */ } while (TRUE); return next; } /* Returns the collated successor of the input "key" taking into account the currently effective null collation scheme */ lvTreeNode *lvAvlTreeKeyCollatedNext(lvTree *lvt, treeKeySubscr *key) { lvTreeNode *node; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (TREF(local_collseq_stdnull)) { if (MV_IS_STRING(key) && (0 == key->str.len)) { /* want the subscript AFTER the null subscript. That is the FIRST node in the tree * unless the first one happens to also be the null subscript. In that case, we need * to hop over that and get the next node in the tree. */ node = lvAvlTreeFirst(lvt); } else { /* want the subscript AFTER a numeric or string subscript. It could end up resulting * in the null subscript in case "key" is the highest numeric subscript in the tree. * In that case, hop over the null subscript as that comes first in the collation order * even though it comes in between numbers and strings in the tree node storage order. */ node = lvAvlTreeKeyNext(lvt, key); } /* If "node" holds the NULL subscript, then hop over to the next one. */ if ((NULL != node) && MVTYPE_IS_STRING(node->key_mvtype) && (0 == node->key_len)) node = lvAvlTreeNext(node); /* Need to hop over the null subscript */ } else node = lvAvlTreeKeyNext(lvt, key); return node; } /* Returns the collated successor of the input "node" taking into account the currently effective null collation scheme */ lvTreeNode *lvAvlTreeNodeCollatedNext(lvTreeNode *node) { boolean_t get_next; lvTree *lvt; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (TREF(local_collseq_stdnull)) { /* If standard null collation, then null subscript needs special handling. * * If current subscript is a null subscript, the next subscript in collation order could * very well be the first numeric (canonical) subscript in the avl tree (if one exists). * If not the next subscript would be the first non-null string subscript in the tree. * * If current subscript is NOT a null subscript, it is possible we encounter the null * subscript as the next subscript in collation order. In that case, we need to hop over * it as that collates before the current numeric subscript. */ if ((NULL != node) && MVTYPE_IS_STRING(node->key_mvtype) && (0 == node->key_len)) { lvt = LV_GET_PARENT_TREE(node); node = lvAvlTreeFirst(lvt); assert(NULL != node); } else node = lvAvlTreeNext(node); get_next = ((NULL != node) && MVTYPE_IS_STRING(node->key_mvtype) && (0 == node->key_len)); } else get_next = TRUE; if (get_next) node = lvAvlTreeNext(node); return node; } /* Function to clone an avl tree (used by the LV_TREE_CLONE macro). Uses recursion to descend the tree. */ lvTreeNode *lvAvlTreeCloneSubTree(lvTreeNode *node, lvTree *lvt, lvTreeNode *avl_parent) { lvTreeNodeVal *dupVal; lvTreeNode *cloneNode, *left, *right; lvTreeNode *leftSubTree, *rightSubTree; lvTree *lvt_child; lv_val *base_lv; assert(NULL != node); cloneNode = lvtreenode_getslot(LVT_GET_SYMVAL(lvt)); /* The following is optimized to do the initialization of just the needed structure members. For that it assumes a * particular "lvTreeNode" structure layout. The assumed layout is asserted so any changes to the layout will * automatically show an issue here and cause the below initialization to be accordingly reworked. */ assert(0 == OFFSETOF(lvTreeNode, v)); assert(OFFSETOF(lvTreeNode, v) + SIZEOF(cloneNode->v) == OFFSETOF(lvTreeNode, sbs_child)); assert(OFFSETOF(lvTreeNode, sbs_child) + SIZEOF(cloneNode->sbs_child) == OFFSETOF(lvTreeNode, tree_parent)); assert(OFFSETOF(lvTreeNode, tree_parent) + SIZEOF(cloneNode->tree_parent) == OFFSETOF(lvTreeNode, key_mvtype)); assert(OFFSETOF(lvTreeNode, key_mvtype) + SIZEOF(cloneNode->key_mvtype) == OFFSETOF(lvTreeNode, balance)); assert(OFFSETOF(lvTreeNode, balance) + SIZEOF(cloneNode->balance) == OFFSETOF(lvTreeNode, descent_dir)); assert(OFFSETOF(lvTreeNode, descent_dir) + SIZEOF(cloneNode->descent_dir) == OFFSETOF(lvTreeNode, key_len)); assert(OFFSETOF(lvTreeNode, key_len) + SIZEOF(cloneNode->key_len) == OFFSETOF(lvTreeNode, key_addr)); assert(OFFSETOF(lvTreeNode, key_mvtype) + 8 == OFFSETOF(lvTreeNode, key_addr)); GTM64_ONLY(assert(OFFSETOF(lvTreeNode, key_addr) + SIZEOF(cloneNode->key_addr) == OFFSETOF(lvTreeNode, avl_left));) NON_GTM64_ONLY( assert(OFFSETOF(lvTreeNode, key_addr) + SIZEOF(cloneNode->key_addr) == OFFSETOF(lvTreeNode, filler_8byte)); assert(OFFSETOF(lvTreeNode, filler_8byte) + SIZEOF(cloneNode->filler_8byte) == OFFSETOF(lvTreeNode, avl_left)); ) assert(OFFSETOF(lvTreeNode, avl_left) + SIZEOF(cloneNode->avl_left) == OFFSETOF(lvTreeNode, avl_right)); assert(OFFSETOF(lvTreeNode, avl_right) + SIZEOF(cloneNode->avl_right) == OFFSETOF(lvTreeNode, avl_parent)); assert(OFFSETOF(lvTreeNode, avl_parent) + SIZEOF(cloneNode->avl_parent) == SIZEOF(lvTreeNode)); cloneNode->v = node->v; /* "cloneNode->sbs_child" initialized later */ cloneNode->tree_parent = lvt; /* cloneNode->key_mvtype/balance/descent_dir/key_len all initialized in one shot */ memcpy(&cloneNode->key_mvtype, &node->key_mvtype, 8); /* Asserts above keep the 8 byte length secure */ cloneNode->key_addr = node->key_addr; NON_GTM64_ONLY( assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNode, filler_8byte, lvTreeNodeNum, key_m1)); ((lvTreeNodeNum *)cloneNode)->key_m1 = ((lvTreeNodeNum *)node)->key_m1; ) cloneNode->avl_parent = avl_parent; lvt_child = node->sbs_child; base_lv = lvt->base_lv; if (NULL != lvt_child) { LV_TREE_CLONE(lvt_child, cloneNode, base_lv); /* initializes "cloneNode->sbs_child" */ } else cloneNode->sbs_child = NULL; left = node->avl_left; leftSubTree = (NULL != left) ? lvAvlTreeCloneSubTree(left, lvt, cloneNode) : NULL; cloneNode->avl_left = leftSubTree; right = node->avl_right; rightSubTree = (NULL != right) ? lvAvlTreeCloneSubTree(right, lvt, cloneNode) : NULL; cloneNode->avl_right = rightSubTree; return cloneNode; } #ifdef DEBUG /* Function to check integrity of lv key subscript. Currently tests the MV_CANONICAL bit is in sync with the key type */ STATICFNDEF boolean_t lvAvlTreeLookupKeyCheck(treeKeySubscr *key) { mval dummy_mval; boolean_t is_canonical; /* Ensure "key->mvtype" comes in with the MV_CANONICAL bit set if applicable */ dummy_mval = *key; is_canonical = MV_IS_CANONICAL(&dummy_mval); if (is_canonical) TREE_KEY_SUBSCR_SET_MV_CANONICAL_BIT(&dummy_mval); else TREE_KEY_SUBSCR_RESET_MV_CANONICAL_BIT(&dummy_mval); assert(TREE_KEY_SUBSCR_IS_CANONICAL(key->mvtype) == TREE_KEY_SUBSCR_IS_CANONICAL(dummy_mval.mvtype)); assert(TREE_KEY_SUBSCR_IS_CANONICAL(key->mvtype) || MV_IS_STRING(key)); assert(!TREE_KEY_SUBSCR_IS_CANONICAL(key->mvtype) || MV_IS_NUMERIC(key)); return TRUE; } boolean_t lvTreeIsWellFormed(lvTree *lvt) { lvTreeNode *avl_root, *tmpNode, *minNode, *maxNode, *sbs_parent, *avl_node, *node; treeSrchStatus *lastLookup; lvTree *tmplvt; int nm_node_cnt, sbs_depth; lv_val *base_lv; if (NULL != lvt) { /* Check lvt->ident */ assert(MV_LV_TREE == lvt->ident); /* Check lvt->sbs_parent */ sbs_parent = LVT_PARENT(lvt); assert(NULL != sbs_parent); assert(sbs_parent->sbs_child == lvt); /* Check lvt->sbs_depth */ sbs_depth = 1; while (!LV_IS_BASE_VAR(sbs_parent)) { tmplvt = LV_GET_PARENT_TREE(sbs_parent); sbs_parent = tmplvt->sbs_parent; sbs_depth++; } assert(sbs_depth == lvt->sbs_depth); /* Check lvt->base_lv */ assert((lv_val *)sbs_parent == lvt->base_lv); /* Note: lvt->avl_height is checked in lvAvlTreeNodeIsWellFormed */ /* Check lvt->avl_root */ if (NULL != (avl_root = lvt->avl_root)) { /* Check lvt->lastLookup clue fields */ lastLookup = &lvt->lastLookup; if (NULL != (tmpNode = lastLookup->lastNodeLookedUp)) { minNode = lastLookup->lastNodeMin; if (NULL != minNode) assert(0 > lvAvlTreeNodeSubscrCmp(minNode, tmpNode)); maxNode = lastLookup->lastNodeMax; if (NULL != maxNode) assert(0 < lvAvlTreeNodeSubscrCmp(maxNode, tmpNode)); } lvAvlTreeNodeIsWellFormed(lvt, avl_root); } } return TRUE; } STATICFNDEF boolean_t lvAvlTreeNodeIsWellFormed(lvTree *lvt, lvTreeNode *node) { int leftSubTreeHeight, rightSubTreeHeight; boolean_t leftWellFormed, rightWellFormed; lvTreeNode *left, *right; lvTree *sbs_child; if (NULL == node) return TRUE; assert(node->tree_parent == lvt); left = node->avl_left; assert((NULL == left) || (left->avl_parent == node)); right = node->avl_right; assert((NULL == right) || (right->avl_parent == node)); leftWellFormed = ((NULL == left) || (0 > lvAvlTreeNodeSubscrCmp(left, node))); assert(leftWellFormed); rightWellFormed = ((NULL == right) || (0 < lvAvlTreeNodeSubscrCmp(right, node))); assert(rightWellFormed); leftSubTreeHeight = lvAvlTreeNodeHeight(left); rightSubTreeHeight = lvAvlTreeNodeHeight(right); if (rightSubTreeHeight > leftSubTreeHeight) assert(node->balance == TREE_RIGHT_HEAVY); else if (rightSubTreeHeight == leftSubTreeHeight) assert(node->balance == TREE_BALANCED); else assert(node->balance == TREE_LEFT_HEAVY); if (node == node->tree_parent->avl_root) assert(node->tree_parent->avl_height == MAX(leftSubTreeHeight, rightSubTreeHeight) + 1); assert(lvAvlTreeNodeIsWellFormed(lvt, left)); assert(lvAvlTreeNodeIsWellFormed(lvt, right)); sbs_child = node->sbs_child; if (NULL != sbs_child) assert(lvTreeIsWellFormed(sbs_child)); return TRUE; } STATICFNDEF int lvAvlTreeNodeHeight(lvTreeNode *node) { int leftSubTreeHeight, rightSubTreeHeight; if (NULL != node) { leftSubTreeHeight = lvAvlTreeNodeHeight(node->avl_left); rightSubTreeHeight = lvAvlTreeNodeHeight(node->avl_right); return (MAX(leftSubTreeHeight, rightSubTreeHeight) + 1); } return 0; } void assert_tree_member_offsets(void) { STATICDEF boolean_t first_tree_create = TRUE; if (first_tree_create) { /* This is the FIRST "lvTree" that this process is creating. Do a few per-process one-time assertions first. */ assert(0 == TREE_LEFT_HEAVY); /* tree_balance_invert array definition depends on this */ assert(1 == TREE_RIGHT_HEAVY); /* tree_balance_invert array definition depends on this */ assert(2 == TREE_BALANCED); /* tree_balance_invert array definition depends on this */ assert(TREE_DESCEND_LEFT == TREE_LEFT_HEAVY); /* they are interchangeably used for performance reasons */ assert(TREE_DESCEND_RIGHT == TREE_RIGHT_HEAVY); /* they are interchangeably used for performance reasons */ /* A lot of the lv functions are passed in an (lv_val *) which could be a (lvTreeNode *) as well. * For example, in op_kill.c, if "kill a" is done, an "lv_val *" (corresponding to the base local variable "a") * is passed whereas if "kill a(1,2)" is done, a "lvTreeNode *" (corresponding to the subscripted node "a(1,2)") * is passed. From the input pointer, we need to determine in op_kill.c if it is a "lv_val *" or "lvTreeNode *". * Assuming "curr_lv" is the input pointer of type "lv_val *", to find out if it is a pointer to an lv_val or * lvTreeNode, one checks the ident of the parent. If it is MV_SYM, it means the pointer is to an lv_val (base * variable) and if not it is a lvTreeNode pointer. The code will look like the below. * * if (MV_SYM == curr_lv->ptrs.val_ent.parent.sym->ident) * { // curr_lv is a base var pointing to an "lv_val" structure * ... * } else * { // curr_lv points to a lvTreeNode structure whose parent.sym field points to a "lvTree" structure * assert(MV_LV_TREE == curr_lv->ptrs.val_ent.parent.sym->ident); * ... * } * * Note : The MV_SYM == check above has now been folded into a IS_LV_VAL_PTR macro in lv_val.h * * In order for the above check to work, one needs to ensure that that an lv_val.ptrs.val_ent.parent.sym * is at the same offset and size as a lvTreeNode.tree_parent and that a symval.ident is at the same offset and * size as a lvTree.ident. * * Similarly, in op_fndata.c we could be passed in a base lv_val * or a subscripted lv_val (i.e. lvTreeNode *) * and want to find out if this lv_val has any children. To do this we would normally need to check * if the input is an lv_val or a lvTreeNode pointer and access curr_lv->ptrs.val_ent.children or * curr_lv->sbs_child respectively. To avoid this additional if checks, we ensure that both are at the * same offset and have the same size. * * We therefore ensure that all fields below in the same line should be at same structure offset * AND have same size as each other. Note: all of this might not be necessary in current code but * might be useful in the future. Since it is easily possible for us to ensure this, we do so right now. * * lvTreeNode.tree_parent == lv_val.ptrs.val_ent.parent.sym * lvTreeNode.sbs_child == lv_val.ptrs.val_ent.children * lvTree.ident == symval.ident == lv_val.v.mvtype * lvTree.sbs_depth == symval.sbs_depth * lvTreeNode.v == lv_val.v */ /* lvTreeNode.tree_parent == lv_val.ptrs.val_ent.parent.sym */ assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNode, tree_parent, lv_val, ptrs.val_ent.parent.sym)); /* lvTreeNode.sbs_child == lv_val.ptrs.val_ent.children */ assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNode, sbs_child, lv_val, ptrs.val_ent.children)); /* lvTree.ident == symval.ident == lv_val.v.mvtype */ assert(IS_OFFSET_AND_SIZE_MATCH(lvTree, ident, symval, ident)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTree, ident, lv_val, v.mvtype)); /* In order to get OFFSETOF & SIZEOF to work on v.mvtype, the mval field "mvtype" was changed from * being a 16-bit "unsigned int" type bitfield to a "unsigned short". While this should not affect the * size of the "mvtype" fields, we fear it might affect the size of the immediately following fields * "sgn" (1-bit), "e" (7-bit) and "fnpc_index" (8-bit). While all of them together occupy 16-bits, they * have an "unsigned int" as the type specifier. In order to ensure the compiler does not allocate 4-bytes * (because of the int specification) to those 3 bitfields (and actually use only 2-bytes of those) and * create a 2-byte filler space, we assert that the offset of the immediately following non-bitfield (which * is "m[2]" in Unix & "str" in VMS) in the mval is 4-bytes. If the compiler had allocated 4-bytes, then this * offset would have been 8-bytes instead and the assert will fail alerting us of the unnecessary mval size bloat. */ UNIX_ONLY(assert(4 == OFFSETOF(mval, m[0]));) VMS_ONLY(assert(4 == OFFSETOF(mval, str));) /* lvTree.sbs_depth == symval.sbs_depth */ assert(IS_OFFSET_AND_SIZE_MATCH(lvTree, sbs_depth, symval, sbs_depth)); /* lvTreeNode.v == lv_val.v */ assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNode, v, lv_val, v)); /* Assert that lvTreeNodeNum and lvTreeNodeStr structures have ALMOST the same layout. * This makes them interchangeably usable with care on the non-intersecting fields. */ assert(SIZEOF(lvTreeNodeNum) == SIZEOF(lvTreeNodeStr)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeNum, v, lvTreeNodeStr, v)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeNum, sbs_child, lvTreeNodeStr, sbs_child)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeNum, tree_parent, lvTreeNodeStr, tree_parent)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeNum, key_mvtype, lvTreeNodeStr, key_mvtype)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeNum, balance, lvTreeNodeStr, balance)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeNum, descent_dir, lvTreeNodeStr, descent_dir)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeNum, avl_left, lvTreeNodeStr, avl_left)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeNum, avl_right, lvTreeNodeStr, avl_right)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeNum, avl_parent, lvTreeNodeStr, avl_parent)); /* Assert that lvTreeNodeStr and lvTreeNode structures have EXACTLY the same layout. * This makes them interchangeably usable. */ assert(SIZEOF(lvTreeNodeStr) == SIZEOF(lvTreeNode)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeStr, v, lvTreeNode, v)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeStr, sbs_child, lvTreeNode, sbs_child)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeStr, tree_parent, lvTreeNode, tree_parent)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeStr, key_mvtype, lvTreeNode, key_mvtype)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeStr, balance, lvTreeNode, balance)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeStr, descent_dir, lvTreeNode, descent_dir)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeStr, key_len, lvTreeNode, key_len)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeStr, key_addr, lvTreeNode, key_addr)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeStr, avl_left, lvTreeNode, avl_left)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeStr, avl_right, lvTreeNode, avl_right)); assert(IS_OFFSET_AND_SIZE_MATCH(lvTreeNodeStr, avl_parent, lvTreeNode, avl_parent)); first_tree_create = FALSE; } } #endif /* In order to lookup a key in the AVL tree, there are THREE functions. One for each different keytype (integer, number, string). * lvAvlTreeLookupInt (look up an integer subscript) * lvAvlTreeLookupNum (look up a non-integer numeric subscript) * lvAvlTreeLookupStr (look up a string subscript) * The functions share a lot of code but have slightly different codepaths. Since these functions are frequently invoked, * we want to keep their cost to a minimum and having separate functions for each keytype lets us minimize the # of if checks * in them which is why we do it this way even if it means a lot of duplication. * * The lookup first attempts to use the clue (if possible) and avoid a full tree traversal. * If not easily possible, we do the full tree traversal. As part of that, we update the clue (to help with future lookups). * As this is an AVL tree, the full tree traversal will take O(log(n)) (i.e. logarithmic) time. */ lvTreeNode *lvAvlTreeLookupInt(lvTree *lvt, treeKeySubscr *key, lvTreeNode **lookupParent) { int cmp; int4 key_m1; lvTreeNode *node, *nextNode, *lastNodeMin, *lastNodeMax, *minNode, *maxNode, **nodePtr; lvTreeNode *parent, *tmpNode; treeSrchStatus *lastLookup; assert(lvAvlTreeLookupKeyCheck(key)); assert(TREE_KEY_SUBSCR_IS_CANONICAL(key->mvtype)); assert(MVTYPE_IS_INT(key->mvtype)); assert(NULL != lookupParent); TREE_DEBUG_ONLY(assert(lvTreeIsWellFormed(lvt));) key_m1 = key->m[1]; /* First see if node can be looked up easily from the lastLookup clue (without a tree traversal) */ lastLookup = &lvt->lastLookup; if (NULL != (tmpNode = lastLookup->lastNodeLookedUp)) { assert(NULL != lvt->avl_root); /* there better be an AVL tree if we have a non-zero clue */ LV_AVL_TREE_INTKEY_CMP(key, key_m1, tmpNode, cmp); if (0 == cmp) { /* Input key matches last used clue. Return right away with a match. */ node = tmpNode; /* "parent" or "parent->descent_dir" need not be set since node is non-NULL */ return node; } else if (0 < cmp) { /* Input key is GREATER than last used clue. Check RIGHT subtree of clue node to see if input key * could possibly be found there. */ if (NULL == tmpNode->avl_right) { /* No subtree to the right of the "clue" node. * If input key is LESSER than the maximum key that can be found under the "clue" node, * then we know for sure input key can not be found anywhere else in the tree. * If input key is GREATER than the maximum key then it definitely is not under "clue" * but could be somewhere else in the tree. We choose to do a fresh traversal from the top. * If input key is EQUAL to the maximum key then return right away with a match. */ maxNode = lastLookup->lastNodeMax; if (NULL != maxNode) { assert(0 < lvAvlTreeNodeSubscrCmp(maxNode, tmpNode)); LV_AVL_TREE_INTKEY_CMP(key, key_m1, maxNode, cmp); if (0 == cmp) { /* input key is EQUAL to the maximum possible key under "clue" node */ node = maxNode; /* "parent" or "parent->descent_dir" need not be set since node is non-NULL */ return node; } else if (0 > cmp) { /* input key is LESSER than the maximum possible key under "clue" node */ parent = tmpNode; parent->descent_dir = TREE_DESCEND_RIGHT; *lookupParent = parent; return NULL; } } else { /* Note: maxNode == NULL implies, max key is +INFINITY so treat this case the same way * as if input key value is LESSER than the maximum possible key under the "clue" node. */ parent = tmpNode; parent->descent_dir = TREE_DESCEND_RIGHT; *lookupParent = parent; return NULL; } } } else if (NULL == tmpNode->avl_left) { /* Input key is LESSER than last used clue AND no subtree to the left of the "clue" node. * If input key is GREATER than the minimum key that can be found under the "clue" node, * then we know for sure input key can not be found anywhere else in the tree. * If input key is LESSER than the minimum key then it definitely is not under "clue" * but could be somewhere else in the tree. We choose to do a fresh traversal from the top. * If input key is EQUAL to the minimum key then return right away with a match. */ minNode = lastLookup->lastNodeMin; if (NULL != minNode) { assert(0 > lvAvlTreeNodeSubscrCmp(minNode, tmpNode)); LV_AVL_TREE_INTKEY_CMP(key, key_m1, minNode, cmp); if (0 == cmp) { /* input key is EQUAL to the minimum possible key under "clue" node */ node = minNode; /* "parent" or "parent->descent_dir" need not be set since node is non-NULL */ return node; } else if (0 < cmp) { /* input key is GREATER than the minimum possible key under "clue" node */ parent = tmpNode; parent->descent_dir = TREE_DESCEND_LEFT; *lookupParent = parent; return NULL; } } else { /* Note: minNode == NULL implies, min key is -INFINITY so treat this case the same way * as if input key value is GREATER than the minimum possible key under the "clue" node. */ parent = tmpNode; parent->descent_dir = TREE_DESCEND_LEFT; *lookupParent = parent; return NULL; } } } /* Now that we know "clue" did not help, do a fresh traversal looking for the input key. Maintain clue at the same time */ parent = lvt->avl_root; if (NULL == parent) { *lookupParent = NULL; return NULL; } node = parent; lastNodeMin = (lvTreeNode *)NULL; /* the minimum possible key under "clue" is initially -INFINITY */ lastNodeMax = (lvTreeNode *)NULL; /* the maximum possible key under "clue" is initially +INFINITY */ if (NULL != node) { while (TRUE) { LV_AVL_TREE_INTKEY_CMP(key, key_m1, node, cmp); if (0 == cmp) { lvt->lastLookup.lastNodeLookedUp = node; break; } else if (cmp < 0) { node->descent_dir = TREE_DESCEND_LEFT; /* if we descend left, we know for sure all-subtree-keys are < node key so update the max key */ nodePtr = &lastNodeMax; nextNode = node->avl_left; } else /* (cmp > 0) */ { node->descent_dir = TREE_DESCEND_RIGHT; /* if we descend right, we know for sure all-subtree-keys are > node-key so update the min key */ nodePtr = &lastNodeMin; nextNode = node->avl_right; } parent = node; node = nextNode; if (NULL == node) { lvt->lastLookup.lastNodeLookedUp = parent; break; } *nodePtr = parent; /* the actual max-key or min-key update happens here */ } } else lvt->lastLookup.lastNodeLookedUp = NULL; *lookupParent = parent; lvt->lastLookup.lastNodeMin = lastNodeMin; /* now that clue has been set, also set max-key and min-key */ lvt->lastLookup.lastNodeMax = lastNodeMax; return node; } /* All comments for "lvAvlTreeLookupInt" function apply here as well */ lvTreeNode *lvAvlTreeLookupNum(lvTree *lvt, treeKeySubscr *key, lvTreeNode **lookupParent) { int cmp; lvTreeNode *node, *nextNode, *lastNodeMin, *lastNodeMax, *minNode, *maxNode, **nodePtr; lvTreeNode *parent, *tmpNode; treeSrchStatus *lastLookup; assert(lvAvlTreeLookupKeyCheck(key)); assert(TREE_KEY_SUBSCR_IS_CANONICAL(key->mvtype)); assert(!MVTYPE_IS_INT(key->mvtype)); assert(NULL != lookupParent); TREE_DEBUG_ONLY(assert(lvTreeIsWellFormed(lvt));) /* First see if node can be looked up easily from the lastLookup clue (without a tree traversal) */ lastLookup = &lvt->lastLookup; if (NULL != (tmpNode = lastLookup->lastNodeLookedUp)) { assert(NULL != lvt->avl_root); /* there better be an AVL tree if we have a non-zero clue */ LV_AVL_TREE_NUMKEY_CMP(key, tmpNode, cmp); if (0 == cmp) { /* Input key matches last used clue. Return right away with a match. */ node = tmpNode; /* "parent" or "parent->descent_dir" need not be set since node is non-NULL */ return node; } else if (0 < cmp) { /* Input key is GREATER than last used clue. Check RIGHT subtree of clue node to see if input key * could possibly be found there. */ if (NULL == tmpNode->avl_right) { /* No subtree to the right of the "clue" node. * If input key is LESSER than the maximum key that can be found under the "clue" node, * then we know for sure input key can not be found anywhere else in the tree. * If input key is GREATER than the maximum key then it definitely is not under "clue" * but could be somewhere else in the tree. We choose to do a fresh traversal from the top. * If input key is EQUAL to the maximum key then return right away with a match. */ maxNode = lastLookup->lastNodeMax; if (NULL != maxNode) { assert(0 < lvAvlTreeNodeSubscrCmp(maxNode, tmpNode)); LV_AVL_TREE_NUMKEY_CMP(key, maxNode, cmp); if (0 == cmp) { /* input key is EQUAL to the maximum possible key under "clue" node */ node = maxNode; /* "parent" or "parent->descent_dir" need not be set since node is non-NULL */ return node; } else if (0 > cmp) { /* input key is LESSER than the maximum possible key under "clue" node */ parent = tmpNode; parent->descent_dir = TREE_DESCEND_RIGHT; *lookupParent = parent; return NULL; } } else { /* Note: maxNode == NULL implies, max key is +INFINITY so treat this case the same way * as if input key value is LESSER than the maximum possible key under the "clue" node. */ parent = tmpNode; parent->descent_dir = TREE_DESCEND_RIGHT; *lookupParent = parent; return NULL; } } } else if (NULL == tmpNode->avl_left) { /* Input key is LESSER than last used clue AND no subtree to the left of the "clue" node. * If input key is GREATER than the minimum key that can be found under the "clue" node, * then we know for sure input key can not be found anywhere else in the tree. * If input key is LESSER than the minimum key then it definitely is not under "clue" * but could be somewhere else in the tree. We choose to do a fresh traversal from the top. * If input key is EQUAL to the minimum key then return right away with a match. */ minNode = lastLookup->lastNodeMin; if (NULL != minNode) { assert(0 > lvAvlTreeNodeSubscrCmp(minNode, tmpNode)); LV_AVL_TREE_NUMKEY_CMP(key, minNode, cmp); if (0 == cmp) { /* input key is EQUAL to the minimum possible key under "clue" node */ node = minNode; /* "parent" or "parent->descent_dir" need not be set since node is non-NULL */ return node; } else if (0 < cmp) { /* input key is GREATER than the minimum possible key under "clue" node */ parent = tmpNode; parent->descent_dir = TREE_DESCEND_LEFT; *lookupParent = parent; return NULL; } } else { /* Note: minNode == NULL implies, min key is -INFINITY so treat this case the same way * as if input key value is GREATER than the minimum possible key under the "clue" node. */ parent = tmpNode; parent->descent_dir = TREE_DESCEND_LEFT; *lookupParent = parent; return NULL; } } } /* Now that we know "clue" did not help, do a fresh traversal looking for the input key. Maintain clue at the same time */ parent = lvt->avl_root; if (NULL == parent) { *lookupParent = NULL; return NULL; } node = parent; lastNodeMin = (lvTreeNode *)NULL; /* the minimum possible key under "clue" is initially -INFINITY */ lastNodeMax = (lvTreeNode *)NULL; /* the maximum possible key under "clue" is initially +INFINITY */ if (NULL != node) { while (TRUE) { LV_AVL_TREE_NUMKEY_CMP(key, node, cmp); if (0 == cmp) { lvt->lastLookup.lastNodeLookedUp = node; break; } else if (cmp < 0) { node->descent_dir = TREE_DESCEND_LEFT; /* if we descend left, we know for sure all-subtree-keys are < node key so update the max key */ nodePtr = &lastNodeMax; nextNode = node->avl_left; } else /* (cmp > 0) */ { node->descent_dir = TREE_DESCEND_RIGHT; /* if we descend right, we know for sure all-subtree-keys are > node-key so update the min key */ nodePtr = &lastNodeMin; nextNode = node->avl_right; } parent = node; node = nextNode; if (NULL == node) { lvt->lastLookup.lastNodeLookedUp = parent; break; } *nodePtr = parent; /* the actual max-key or min-key update happens here */ } } else lvt->lastLookup.lastNodeLookedUp = NULL; *lookupParent = parent; lvt->lastLookup.lastNodeMin = lastNodeMin; /* now that clue has been set, also set max-key and min-key */ lvt->lastLookup.lastNodeMax = lastNodeMax; return node; } /* All comments for "lvAvlTreeLookupInt" function apply here as well */ lvTreeNode *lvAvlTreeLookupStr(lvTree *lvt, treeKeySubscr *key, lvTreeNode **lookupParent) { int cmp, key_len; char *key_addr; lvTreeNode *node, *nextNode, *lastNodeMin, *lastNodeMax, *minNode, *maxNode, **nodePtr; lvTreeNode *parent, *tmpNode; treeSrchStatus *lastLookup; assert(lvAvlTreeLookupKeyCheck(key)); assert(!TREE_KEY_SUBSCR_IS_CANONICAL(key->mvtype)); assert(MVTYPE_IS_STRING(key->mvtype)); assert(NULL != lookupParent); TREE_DEBUG_ONLY(assert(lvTreeIsWellFormed(lvt));) key_addr = key->str.addr; key_len = key->str.len; /* First see if node can be looked up easily from the lastLookup clue (without a tree traversal) */ lastLookup = &lvt->lastLookup; if (NULL != (tmpNode = lastLookup->lastNodeLookedUp)) { assert(NULL != lvt->avl_root); /* there better be an AVL tree if we have a non-zero clue */ LV_AVL_TREE_STRKEY_CMP(key, key_addr, key_len, tmpNode, cmp); if (0 == cmp) { /* Input key matches last used clue. Return right away with a match. */ node = tmpNode; /* "parent" or "parent->descent_dir" need not be set since node is non-NULL */ return node; } else if (0 < cmp) { /* Input key is GREATER than last used clue. Check RIGHT subtree of clue node to see if input key * could possibly be found there. */ if (NULL == tmpNode->avl_right) { /* No subtree to the right of the "clue" node. * If input key is LESSER than the maximum key that can be found under the "clue" node, * then we know for sure input key can not be found anywhere else in the tree. * If input key is GREATER than the maximum key then it definitely is not under "clue" * but could be somewhere else in the tree. We choose to do a fresh traversal from the top. * If input key is EQUAL to the maximum key then return right away with a match. */ maxNode = lastLookup->lastNodeMax; if (NULL != maxNode) { assert(0 < lvAvlTreeNodeSubscrCmp(maxNode, tmpNode)); LV_AVL_TREE_STRKEY_CMP(key, key_addr, key_len, maxNode, cmp); if (0 == cmp) { /* input key is EQUAL to the maximum possible key under "clue" node */ node = maxNode; /* "parent" or "parent->descent_dir" need not be set since node is non-NULL */ return node; } else if (0 > cmp) { /* input key is LESSER than the maximum possible key under "clue" node */ parent = tmpNode; parent->descent_dir = TREE_DESCEND_RIGHT; *lookupParent = parent; return NULL; } } else { /* Note: maxNode == NULL implies, max key is +INFINITY so treat this case the same way * as if input key value is LESSER than the maximum possible key under the "clue" node. */ parent = tmpNode; parent->descent_dir = TREE_DESCEND_RIGHT; *lookupParent = parent; return NULL; } } } else if (NULL == tmpNode->avl_left) { /* Input key is LESSER than last used clue AND no subtree to the left of the "clue" node. * If input key is GREATER than the minimum key that can be found under the "clue" node, * then we know for sure input key can not be found anywhere else in the tree. * If input key is LESSER than the minimum key then it definitely is not under "clue" * but could be somewhere else in the tree. We choose to do a fresh traversal from the top. * If input key is EQUAL to the minimum key then return right away with a match. */ minNode = lastLookup->lastNodeMin; if (NULL != minNode) { assert(0 > lvAvlTreeNodeSubscrCmp(minNode, tmpNode)); LV_AVL_TREE_STRKEY_CMP(key, key_addr, key_len, minNode, cmp); if (0 == cmp) { /* input key is EQUAL to the minimum possible key under "clue" node */ node = minNode; /* "parent" or "parent->descent_dir" need not be set since node is non-NULL */ return node; } else if (0 < cmp) { /* input key is GREATER than the minimum possible key under "clue" node */ parent = tmpNode; parent->descent_dir = TREE_DESCEND_LEFT; *lookupParent = parent; return NULL; } } else { /* Note: minNode == NULL implies, min key is -INFINITY so treat this case the same way * as if input key value is GREATER than the minimum possible key under the "clue" node. */ parent = tmpNode; parent->descent_dir = TREE_DESCEND_LEFT; *lookupParent = parent; return NULL; } } } /* Now that we know "clue" did not help, do a fresh traversal looking for the input key. Maintain clue at the same time */ parent = lvt->avl_root; if (NULL == parent) { *lookupParent = NULL; return NULL; } node = parent; lastNodeMin = (lvTreeNode *)NULL; /* the minimum possible key under "clue" is initially -INFINITY */ lastNodeMax = (lvTreeNode *)NULL; /* the maximum possible key under "clue" is initially +INFINITY */ if (NULL != node) { while (TRUE) { LV_AVL_TREE_STRKEY_CMP(key, key_addr, key_len, node, cmp); if (0 == cmp) { lvt->lastLookup.lastNodeLookedUp = node; break; } else if (cmp < 0) { node->descent_dir = TREE_DESCEND_LEFT; /* if we descend left, we know for sure all-subtree-keys are < node key so update the max key */ nodePtr = &lastNodeMax; nextNode = node->avl_left; } else /* (cmp > 0) */ { node->descent_dir = TREE_DESCEND_RIGHT; /* if we descend right, we know for sure all-subtree-keys are > node-key so update the min key */ nodePtr = &lastNodeMin; nextNode = node->avl_right; } parent = node; node = nextNode; if (NULL == node) { lvt->lastLookup.lastNodeLookedUp = parent; break; } *nodePtr = parent; /* the actual max-key or min-key update happens here */ } } else lvt->lastLookup.lastNodeLookedUp = NULL; *lookupParent = parent; lvt->lastLookup.lastNodeMin = lastNodeMin; /* now that clue has been set, also set max-key and min-key */ lvt->lastLookup.lastNodeMax = lastNodeMax; return node; } /* Function to lookup an input key in the AVL tree. This function works for any input key type. * Returns if a given key is found or not. "lookupParent" will be updated ONLY IF "node" is NOT found in tree. * Note: It is preferable for performance-sensitive callers to call the lvAvlTreeLookupInt/lvAvlTreeLookupNum/lvAvlTreeLookupStr * functions directly (assuming the caller already knows the key type) instead of going through here thereby avoiding an if check. */ lvTreeNode *lvAvlTreeLookup(lvTree *lvt, treeKeySubscr *key, lvTreeNode **lookupParent) { int key_mvtype; assert(lvAvlTreeLookupKeyCheck(key)); key_mvtype = key->mvtype; if (TREE_KEY_SUBSCR_IS_CANONICAL(key_mvtype)) { if (MVTYPE_IS_INT(key_mvtype)) return lvAvlTreeLookupInt(lvt, key, lookupParent); else return lvAvlTreeLookupNum(lvt, key, lookupParent); } else return lvAvlTreeLookupStr(lvt, key, lookupParent); } /* The below two functions (lvAvlTreeSingleRotation & lvAvlTreeDoubleRotation) do height balancing of AVL tree by tree rotation. * They are used by the "lvAvlTreeNodeInsert" and "lvAvlTreeNodeDelete" functions. * A node insertion or deletion can cause the AVL tree height balance to be disturbed by taking it to one of 4 states. * a) Left Left * b) Right Right * c) Left Right * d) Right Left * Cases (a) and (b) can be taken into a "Balanced" state by just ONE rotation (implemented by lvAvlTreeSingleRotation). * Cases (c) and (d) need TWO rotations to take them to a "Balanced" state as shown below (implemented by lvAvlTreeDoubleRotation). * * In the below illustration (courtesy of http://en.wikipedia.org/wiki/AVL_tree) key points to note are * -> 3,4,5 are nodes with those key values. * -> A,B,C,D are arbitrary subtrees (not necessarily nodes). * -> The double-width link (\\ or //) in each tree is where the rotation happens * (the child in that link becomes the parent) to take it to the next state. * * Left Right case Left Left case Balanced case * ---------------- ----------------- -------------- * * ------- ------- ------------- * | 5 | | 5 | | 4 | * ------- ------- ------------- * / \ // \ / \ * / \ // \ / \ * ------- ------- ------- ------- ------- ------- * | 3 | | D | | 4 | | D | | 3 | | 5 | * ------- ------- ------- ------- ------- ------- * / \\ ----> / \ ----> / \ / \ * / \\ / \ / \ / \ * ------- ------- ------- ------- ------- ------- ------- ------- * | A | | 4 | | 3 | | C | | A | | B | | C | | D | * ------- ------- ------- ------- ------- ------- ------- ------- * / \ / \ * / \ / \ * ------- ------- ------- ------- * | B | | C | | A | | B | * ------- ------- ------- ------- * * Right Left case Right Right case Balanced case * ---------------- ----------------- -------------- * * ------- ------- ------------- * | 3 | | 3 | | 4 | * ------- ------- ------------- * / \ / \\ / \ * / \ / \\ / \ * ------- ------- ------- ------- ------- ------- * | A | | 5 | | A | | 4 | | 3 | | 5 | * ------- ------- ------- ------- ------- ------- * // \ ----> / \ ----> / \ / \ * // \ / \ / \ / \ * ------- ------- ------- ------- ------- ------- ------- ------- * | 4 | | D | | B | | 5 | | A | | B | | C | | D | * ------- ------- ------- ------- ------- ------- ------- ------- * / \ / \ * / \ / \ * ------- ------- ------- ------- * | B | | C | | C | | D | * ------- ------- ------- ------- * */ STATICFNDEF lvTreeNode *lvAvlTreeSingleRotation(lvTreeNode *rebalanceNode, lvTreeNode *anchorNode, int4 balanceFactor) { lvTreeNode *newRoot, *node; TREE_DEBUG1("DOING SINGLE ROTATION\n"); assert((TREE_LEFT_HEAVY == balanceFactor) || (TREE_RIGHT_HEAVY == balanceFactor)); if (TREE_LEFT_HEAVY == balanceFactor) { /* Left-Left path rotate. In above illustration, 5 is rebalanceNode, 4 is anchorNode */ assert(rebalanceNode->avl_left == anchorNode); node = anchorNode->avl_right; rebalanceNode->avl_left = node; anchorNode->avl_right = rebalanceNode; } else { /* Right-Right path rotate. In above illustration, 3 is rebalanceNode, 4 is anchorNode */ assert(rebalanceNode->avl_right == anchorNode); node = anchorNode->avl_left; rebalanceNode->avl_right = node; anchorNode->avl_left = rebalanceNode; } if (node) node->avl_parent = rebalanceNode; rebalanceNode->avl_parent = anchorNode; if (TREE_IS_NOT_BALANCED(anchorNode->balance)) { rebalanceNode->balance = TREE_BALANCED; anchorNode->balance = TREE_BALANCED; } else anchorNode->balance = TREE_INVERT_BALANCE_FACTOR(balanceFactor); newRoot = anchorNode; return newRoot; } /* Comments before "lvAvlTreeSingleRotation" function definition describe what this function does */ STATICFNDEF lvTreeNode *lvAvlTreeDoubleRotation(lvTreeNode *rebalanceNode, lvTreeNode *anchorNode, int4 balanceFactor) { lvTreeNode *newRoot, *node, *rebalanceChild, *anchorChild; int balance; TREE_DEBUG1("DOING DOUBLE ROTATION\n"); assert((TREE_LEFT_HEAVY == balanceFactor) || (TREE_RIGHT_HEAVY == balanceFactor)); if (TREE_LEFT_HEAVY == balanceFactor) { /* Left-Right path rotate. In above illustration, 5 is rebalanceNode, 3 is anchorNode */ assert(rebalanceNode->avl_left == anchorNode); newRoot = anchorNode->avl_right; rebalanceChild = newRoot->avl_right; rebalanceNode->avl_left = rebalanceChild; anchorChild = newRoot->avl_left; anchorNode->avl_right = anchorChild; newRoot->avl_left = anchorNode; newRoot->avl_right = rebalanceNode; } else { /* Right-Left path rotate. In above illustration, 3 is rebalanceNode, 5 is anchorNode */ assert(rebalanceNode->avl_right == anchorNode); newRoot = anchorNode->avl_left; rebalanceChild = newRoot->avl_left; rebalanceNode->avl_right = rebalanceChild; anchorChild = newRoot->avl_right; anchorNode->avl_left = anchorChild; newRoot->avl_left = rebalanceNode; newRoot->avl_right = anchorNode; } if (NULL != rebalanceChild) rebalanceChild->avl_parent = rebalanceNode; if (NULL != anchorChild) anchorChild->avl_parent = anchorNode; anchorNode->avl_parent = newRoot; rebalanceNode->avl_parent = newRoot; balance = newRoot->balance; if (balance == balanceFactor) { rebalanceNode->balance = TREE_INVERT_BALANCE_FACTOR(balanceFactor); anchorNode->balance = TREE_BALANCED; } else if (TREE_IS_BALANCED(balance)) { rebalanceNode->balance = TREE_BALANCED; anchorNode->balance = TREE_BALANCED; } else { /* balance & balanceFactor are opposites */ rebalanceNode->balance = TREE_BALANCED; anchorNode->balance = balanceFactor; } newRoot->balance = TREE_BALANCED; return(newRoot); } /* Function to INSERT a node into the AVL tree. * * At a high level, insertion proceeds by doing a key lookup first and inserting the key wherever the lookup ends. * After inserting a node, it is necessary to check each of the node's ancestors for consistency with the rules of AVL. * For each node checked, if the height difference between the left and right subtrees is atmost 1 then no rotations are necessary. * If not, then the subtree rooted at this node is unbalanced. It is possible more than one node in the ancestor path is * unbalanced due to the insertion but at most ONE tree rotation is needed (at the last unbalanced node down the tree path) * to restore the entire tree to the rules of AVL. * * Key points to note for AVL tree insertion are (courtesy of http://neil.brown.name/blog/20041124101820) * * When we step down from a node to the longest subtree, that node's tree will not get any larger. If the subtree * we descend into grows, a rotation will be needed, but this will result in this tree being the same height as it * was before. The only difference at this level is that it will be balanced whereas it wasn't before. This means * that when we step down a longer path, we can forget about all the nodes above the one we step down from. They * cannot be affected as neither of their subtrees will grow. This observation tells us where the rotation has to happen. * * We only need to rotate if as part of the lookup/insert, we step down to a longer subtree, and then all * subsequent nodes are balanced, without longer or shorter subtrees. The actual rotation that happens * (if needed) will depend on what happens immediately after stepping down to a longer subtree. If the * next step is in the same direction as the step into the larger subtree, then a SINGLE rotation will be * needed. If the next step is in the other direction, then a DOUBLE rotation will be needed. * * The important data that we need is that part of the path from the last unbalanced node to the insertion * point. All nodes in this list other than the first will be balanced, including the newly inserted * node. All of these nodes will either take part in a rotation, or will need to have their balance value * changed (though the new node won't need it's balance changed, it could take part in a rotation though). * * This path may not actually start with an unbalanced node. If every node in the path from the root is * balanced, then that whole path needs to be recorded, and every node will have it's balance changed. * * Time for insert = O(log n) for lookup + O(1) for at most one single or double rotation = O(log n) */ lvTreeNode *lvAvlTreeNodeInsert(lvTree *lvt, treeKeySubscr *key, lvTreeNode *parent) { lvTreeNode *node, *t_root, *tmp_parent, *anchorNode, *tmpNode, **nodePtr; lvTreeNode *rebalanceNode, *rebalanceNodeParent; lvTreeNodeNum *fltNode; int balanceFactor, curBalance, cmp, key_mvtype; treeSrchStatus *lastLookup; DEBUG_ONLY(lvTreeNode *dbg_node); assert(MV_DEFINED(key)); /* At time of node insertion into tree, ensure that if we have MV_CANONICAL bit set, then MV_STR bit is not set. * This makes it clear that the node key is a number and does not have the string representation constructed. */ assert(!TREE_KEY_SUBSCR_IS_CANONICAL(key->mvtype) || MV_IS_NUMERIC(key) && !MV_IS_STRING(key)); assert(NULL == lvAvlTreeLookup(lvt, key, &tmp_parent)); /* create a node in the avl tree and initialize it */ node = lvtreenode_getslot(LVT_GET_SYMVAL(lvt)); assert(NULL != node); /* node->v must be initialized by caller */ node->sbs_child = NULL; node->tree_parent = lvt; node->avl_left = node->avl_right = NULL; node->avl_parent = parent; key_mvtype = key->mvtype; if (TREE_KEY_SUBSCR_IS_CANONICAL(key_mvtype)) { /* Initialize lvTreeNodeNum structure */ fltNode = (lvTreeNodeNum *)node; fltNode->key_mvtype = (key_mvtype & MV_EXT_NUM_MASK); if (MV_INT & key_mvtype) { fltNode->key_m0 = key->m[1]; fltNode->key_flags.key_bits.key_iconv = FALSE; } else { fltNode->key_flags.key_bytes.key_sgne = ((mval_b *)key)->sgne; fltNode->key_m0 = key->m[0]; fltNode->key_m1 = key->m[1]; } } else { /* Initialize lvTreeNode structure */ node->key_mvtype = MV_STR; /* do not use input mvtype as it might have MV_NM or MV_NUM_APPROX bits set */ node->key_len = key->str.len; node->key_addr = key->str.addr; } node->balance = TREE_BALANCED; /* node->descent_dir is initialized later when this node is part of a lvAvlTreeLookup operation. * this field is not used by anyone until then so ok not to initialize it here. * Update lastLookup clue to reflect the newly inserted node. Note that this clue will continue * to be valid inspite of any single or double rotations that happen as part of the insert below. */ lastLookup = &lvt->lastLookup; lastLookup->lastNodeLookedUp = node; /* first part of lastLookup clue update */ /* Do height-balancing tree rotations as needed to maintain avl property */ if (NULL != parent) { if (TREE_DESCEND_LEFT == parent->descent_dir) { parent->avl_left = node; nodePtr = &lastLookup->lastNodeMax; } else { parent->avl_right = node; nodePtr = &lastLookup->lastNodeMin; } *nodePtr = parent; /* second (and last) part of lastLookup clue update */ t_root = lvt->avl_root; /* Do balance factor adjustment & rotation as needed */ tmpNode = parent; while (t_root != tmpNode) { balanceFactor = tmpNode->balance; if (TREE_IS_NOT_BALANCED(balanceFactor)) break; tmpNode->balance = tmpNode->descent_dir; tmpNode = tmpNode->avl_parent; } rebalanceNode = tmpNode; if (TREE_DESCEND_LEFT == rebalanceNode->descent_dir) { anchorNode = rebalanceNode->avl_left; balanceFactor = TREE_LEFT_HEAVY; } else { anchorNode = rebalanceNode->avl_right; balanceFactor = TREE_RIGHT_HEAVY; } curBalance = rebalanceNode->balance; if (TREE_IS_BALANCED(curBalance)) /* tree has grown taller */ { rebalanceNode->balance = balanceFactor; TREE_DEBUG3("Tree height increased from %d to %d\n", lvt->avl_height, (lvt->avl_height + 1)); lvt->avl_height++; assert(1 < lvt->avl_height); } else if (curBalance == TREE_INVERT_BALANCE_FACTOR(balanceFactor)) { /* the tree has gotten more balanced */ rebalanceNode->balance = TREE_BALANCED; } else { /* The tree has gotten out of balance so need a rotation */ rebalanceNodeParent = rebalanceNode->avl_parent; assert(anchorNode->balance == anchorNode->descent_dir); assert(balanceFactor == rebalanceNode->descent_dir); if (anchorNode->balance == balanceFactor) tmpNode = lvAvlTreeSingleRotation(rebalanceNode, anchorNode, balanceFactor); else tmpNode = lvAvlTreeDoubleRotation(rebalanceNode, anchorNode, balanceFactor); tmpNode->avl_parent = rebalanceNodeParent; if (NULL != rebalanceNodeParent) { /* root of tree has NOT changed */ assert(rebalanceNodeParent->descent_dir == ((rebalanceNodeParent->avl_left == rebalanceNode) ? TREE_DESCEND_LEFT : TREE_DESCEND_RIGHT)); if (TREE_DESCEND_LEFT == rebalanceNodeParent->descent_dir) rebalanceNodeParent->avl_left = tmpNode; else rebalanceNodeParent->avl_right = tmpNode; } else lvt->avl_root = tmpNode; /* new root although tree height is still the same */ } } else { /* we just inserted the real root of the tree */ assert(NULL == lvt->avl_root); lvt->avl_root = node; assert(NULL == node->avl_right); assert(NULL == node->avl_left); assert(TREE_BALANCED == node->balance); TREE_DEBUG3("Tree height increased from %d to %d\n", lvt->avl_height, (lvt->avl_height + 1)); assert(0 == lvt->avl_height); lvt->avl_height = 1; lastLookup->lastNodeMin = NULL; /* ensure lastLookup clue is uptodate */ lastLookup->lastNodeMax = NULL; /* ensure lastLookup clue is uptodate */ } TREE_DEBUG_ONLY(assert(lvTreeIsWellFormed(lvt));) return node; } /* Function to DELETE a node from the AVL tree. * * At a high level, deletion proceeds by doing a key lookup first and deleting the node wherever the lookup ends. * After deleting a node, it is necessary to check each of the node's ancestors for consistency with the rules of AVL. * For each node checked, if the height difference between the left and right subtrees is atmost 1 then no rotations are necessary. * If not, then the subtree rooted at this node is unbalanced. It is possible more than one node in the ancestor path is * unbalanced due to the deletion. Unlike insertion, MANY (as many as the height of the tree) tree rotations are needed * to restore the entire tree to the rules of AVL. * * Key points to note for AVL tree deletion are (courtesy of http://neil.brown.name/blog/20041124141849) * * It is easy to remove a node when it only has one child, as that child can replace the deleted node as the child of * the grandparent. If the target node has two children, the easiest approach is to swap the node with a node that does * have at most one child. This can work providing we can find such a node that is adjacent to the target node in the sort-order. * A few moments consideration will confirm that if a node has two children, then there must be a node both immediately above * and below it in the sort order, and that both of these must be further down the tree than the target node, and that neither * of these can have two children (as if they did, then one of the children would lie between that node and the target, which * contradicts the selection of that node). In this implementation we choose the immediately-above node (in-order successor) only. * * While insert only needed one rotation, delete may need rotation at every level. * If the shrinkage of a subtree (i.e. height reduction due to a tree rotation) causes the node's tree to shrink, the change * must propagate up. If it does not, then all higher nodes in the tree will not be affected. * * Time for delete = O(log n) for lookup + at most O(log n) rotations = O(log n) */ void lvAvlTreeNodeDelete(lvTree *lvt, lvTreeNode *node) { boolean_t treeBalanced; int4 balanceFactor, curNodeBalance; lvTreeNode *balanceThisNode, *nextBalanceThisNode, *anchorNode, *newRoot; lvTreeNode *next, *nextLeft, *nextRight, *nextParent, *left; lvTreeNode *nodeLeft, *nodeRight, *nodeParent; lvTreeNode *rebalanceNode, *rebalanceNodeParent; assert(IS_LVAVLTREENODE(((lv_val *)node))); /* ensure input "node" is of type "lvTreeNode *" or "lvTreeNodeNum *" * and not "lv_val *" */ assert(lvt == node->tree_parent); nodeLeft = node->avl_left; nodeRight = node->avl_right; nodeParent = node->avl_parent; if (NULL == nodeRight) { /* No right subtree. Move the left subtree (if it exists) over to the current node. */ balanceThisNode = nodeParent; if (NULL != balanceThisNode) { assert(balanceThisNode->descent_dir == ((balanceThisNode->avl_left == node) ? TREE_DESCEND_LEFT : TREE_DESCEND_RIGHT)); if (TREE_DESCEND_LEFT == balanceThisNode->descent_dir) balanceThisNode->avl_left = nodeLeft; else balanceThisNode->avl_right = nodeLeft; } else { /* No parent and the fact that this is an AVL tree implies only two possibilities * a) deleting only node of tree. * b) deleting root of a height=2 tree that has only one child-node on its left and no other nodes. * In either case, the tree height will reduce by 1 due to the deletion. * Set tree root here. Tree height will be reduced later in the rebalancing for loop. */ lvt->avl_root = nodeLeft; } if (NULL != nodeLeft) nodeLeft->avl_parent = balanceThisNode; } else { /* Replace node with in-order successor, and rearrange */ next = nodeRight; while (TRUE) { left = next->avl_left; if (NULL != left) { next->descent_dir = TREE_DESCEND_LEFT; next = left; } else break; } /* at this point, "next" is the in-order successor of "node" */ assert(NULL == next->avl_left); nextRight = next->avl_right; nextParent = next->avl_parent; if (nextParent != node) { balanceThisNode = nextParent; assert(nextParent->descent_dir == ((nextParent->avl_left == next) ? TREE_DESCEND_LEFT : TREE_DESCEND_RIGHT)); if (TREE_DESCEND_LEFT == nextParent->descent_dir) nextParent->avl_left = nextRight; else nextParent->avl_right = nextRight; if (NULL != nextRight) nextRight->avl_parent = nextParent; next->avl_right = nodeRight; nodeRight->avl_parent = next; } else { assert(nextParent->avl_right == next); balanceThisNode = next; } assert(NULL != balanceThisNode); next->avl_left = nextLeft = nodeLeft; if (NULL != nextLeft) nextLeft->avl_parent = next; next->avl_parent = nodeParent; next->balance = node->balance; next->descent_dir = TREE_DESCEND_RIGHT; if (NULL != nodeParent) { assert(nodeParent->descent_dir == ((nodeParent->avl_left == node) ? TREE_DESCEND_LEFT : TREE_DESCEND_RIGHT)); if (TREE_DESCEND_LEFT == nodeParent->descent_dir) nodeParent->avl_left = next; else nodeParent->avl_right = next; } else lvt->avl_root = next; /* root of avl tree changing from "node" to "next" */ } /* At this point "balanceThisNode" points to the first unbalanced node (from the bottom of the tree path) * which might also need a rotation (single or double). The rotations need to bubble up the tree hence the for loop. */ for ( ; ; balanceThisNode = nextBalanceThisNode) { /* Balancing act */ if (NULL == balanceThisNode) { /* Went past root of tree as part of balance factor adjustments. Tree height has reduced. */ TREE_DEBUG3("Tree height reduced from %d to %d\n", lvt->avl_height, (lvt->avl_height - 1)); assert(lvt->avl_height > 0); lvt->avl_height--; break; } balanceFactor = balanceThisNode->descent_dir; curNodeBalance = balanceThisNode->balance; if (TREE_IS_BALANCED(curNodeBalance)) { /* Found a balanced node in the tree path. Fix its balance to account for the decrease in subtree height. * No more tree rotations needed so break out of the for loop. */ balanceThisNode->balance = TREE_INVERT_BALANCE_FACTOR(balanceFactor); break; } nextBalanceThisNode = balanceThisNode->avl_parent; assert((NULL == nextBalanceThisNode) || nextBalanceThisNode->descent_dir == ((nextBalanceThisNode->avl_left == balanceThisNode) ? TREE_LEFT_HEAVY : TREE_RIGHT_HEAVY)); if (curNodeBalance == balanceFactor) { /* The longer subtree is the one which had its height reduce so this node now becomes balanced. * So no rotation needed for this node, but the height of this node has now reduced so we still * need to trace back up the tree to see if this causes any more height imbalances. */ balanceThisNode->balance = TREE_BALANCED; continue; } /* balanceThisNode->balance == inverse of balanceFactor. * * The subtree at balanceThisNode is already heavy on one side and a node delete has caused * the other side to reduce one more level increasing the height difference between the two * subtrees to be 2 and therefore requires a rebalance (using tree rotation). */ rebalanceNode = balanceThisNode; if (TREE_LEFT_HEAVY == balanceFactor) { balanceFactor = TREE_RIGHT_HEAVY; anchorNode = rebalanceNode->avl_right; } else { balanceFactor = TREE_LEFT_HEAVY; anchorNode = rebalanceNode->avl_left; } treeBalanced = TREE_IS_BALANCED(anchorNode->balance); if (treeBalanced || (anchorNode->balance == balanceFactor)) { newRoot = lvAvlTreeSingleRotation(rebalanceNode, anchorNode, balanceFactor); assert((treeBalanced && TREE_IS_NOT_BALANCED(rebalanceNode->balance) && TREE_IS_NOT_BALANCED(anchorNode->balance)) || (TREE_IS_BALANCED(rebalanceNode->balance) && TREE_IS_BALANCED(anchorNode->balance))); } else newRoot = lvAvlTreeDoubleRotation(rebalanceNode, anchorNode, balanceFactor); rebalanceNodeParent = nextBalanceThisNode; newRoot->avl_parent = rebalanceNodeParent; if (NULL != rebalanceNodeParent) { /* Point parent to new root of the rotated subtree */ assert(rebalanceNodeParent->descent_dir == ((rebalanceNodeParent->avl_left == rebalanceNode) ? TREE_DESCEND_LEFT : TREE_DESCEND_RIGHT)); if (TREE_DESCEND_LEFT == rebalanceNodeParent->descent_dir) rebalanceNodeParent->avl_left = newRoot; else rebalanceNodeParent->avl_right = newRoot; } else lvt->avl_root = newRoot; if (treeBalanced) { /* If tree is balanced at "anchorNode" before the rotation, the post-rotated tree height does NOT change. * This means no more need to propagate the rebalancing up the tree. Break out of the loop now. */ break; } } lvt->lastLookup.lastNodeLookedUp = NULL; /* reset lastLookup clue since all bets are off after the delete */ } fis-gtm-V6.0-003/sr_port/lv_tree.h0000644000032200000250000003657512201176160015657 0ustar librarygtc/**************************************************************** * * * Copyright 2011, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef _TREE_H #define _TREE_H #include /* The "lvTree" typedef defines an AVL tree. One such structure exists for each local variable subscript level (starting from 0) * The "lvTreeNode" typedef defines the layout of the tree node. One structure exists for each tree node in an AVL tree. * e.g. if "a" is a local variable that has the following nodes defined * a(1)=1 * a(1,"a")=2 * a(1,"b")=3 * a(2,"c")=4 * There is ONE "lv_val" structure corresponding to the base local variable "a". * There are THREE "lvTree" structures (i.e. AVL trees) underneath the base local variable "a". * 1) One for the base variable "a". This contains the keys/subscripts 1 and 2. * 2) One for the subscripted variable "a(1)". This contains the keys/subscripts "a" and "b". * 3) One for the subscripted variable "a(2)". This contains the key/subscript "c". * There are FIVE "lvTreeNode" structures underneath the base local variable "a". * 1) One for subscript 1. * 2) One for subscript 2. * 3) One for subscript "a". * 4) One for subscript "b". * 5) One for subscript "c". */ typedef mval lvTreeNodeVal; typedef mval treeKeySubscr; /* A numeric key value stored in the AVL tree is represented in a lvTreeNodeNum structure. Additionally, a string type key can * also be stored in the same AVL tree. Instead of using an "mstr" type directly, we explicitly define the necessary fields * from the mstr (no char_len field) so we can save 8 bytes in the lvTreeNode struct on 64-bit platforms). This way both the * numeric and string lvTreeNode structures require 12 bytes thus have 8-byte alignment for the lvTreeNode* typedefs (on 64-bit * platforms) without any wasted padding space. This means that any code that interprets the key in a lvTreeNode structure * needs to examine the "key_mvtype" field and accordingly use a lvTreeNodeNum or lvTreeNodeStr structure to get at the key. */ typedef struct lvTreeNodeNumStruct { lvTreeNodeVal v; /* If string, will point to stringpool location */ struct lvTreeStruct *sbs_child; /* pointer to lvTreeStruct storing next level subscripts under this node */ struct lvTreeStruct *tree_parent; /* pointer to lvTreeStruct under whose avl tree this node belongs to */ unsigned short key_mvtype; /* will be (if non-integer) or (if integer) */ signed char balance; /* height(left) - height(right). Can be -1, 0, or 1 */ unsigned char descent_dir; /* direction of descent (LEFT = 0, RIGHT = 1) */ /* the value of the numeric key is stored in the key_* members below */ union { struct { unsigned char key_sgne; /* Contains sgn & e fields - fewer instructions to move this one byte * rather than two bit fields when copying to/from an mval */ } key_bytes; struct { # ifdef BIGENDIAN unsigned int key_sgn : 1; /* same as mval layout */ unsigned int key_e : 7; /* same as mval layout */ # else unsigned int key_e : 7; /* same as mval layout */ unsigned int key_sgn : 1; /* same as mval layout */ # endif unsigned int key_iconv : 1; /* 1 if (key_mvtype & MV_INT is TRUE) && (key_m0 field stores the * mval->m[1] value of the integer before it was converted into the * float representation. */ unsigned int filler :23; } key_bits; } key_flags; int4 key_m0; int4 key_m1; struct treeNodeStruct *avl_left; /* left AVL subtree at this subscript level */ struct treeNodeStruct *avl_right; /* right AVL subtree at this subscript level */ struct treeNodeStruct *avl_parent; /* parent node within the current subscript level AVL tree */ } lvTreeNodeNum; typedef struct treeNodeStruct { lvTreeNodeVal v; /* If string, will point to stringpool location */ struct lvTreeStruct *sbs_child; /* pointer to lvTreeStruct storing next level subscripts under this node; * overloaded as the free list pointer if this "lvTreeNode" is in the free list. */ struct lvTreeStruct *tree_parent; /* pointer to lvTreeStruct under whose avl tree this node belongs to */ unsigned short key_mvtype; /* will have MV_STR bit set */ signed char balance; /* height(left) - height(right). Can be -1, 0, or 1 */ unsigned char descent_dir; /* direction of descent (LEFT = 0, RIGHT = 1) */ uint4 key_len; /* byte length of string */ char *key_addr; /* pointer to string */ NON_GTM64_ONLY(uint4 filler_8byte;) /* needed to ensure lvTreeNodeNum & lvTreeNode structures have * same size & layout for 32-bit platforms also */ struct treeNodeStruct *avl_left; /* left AVL subtree at this subscript level */ struct treeNodeStruct *avl_right; /* right AVL subtree at this subscript level */ struct treeNodeStruct *avl_parent; /* parent node within the current subscript level AVL tree */ } lvTreeNode; /* Given a pointer to a "lvTreeNode" structure, the mvtype field will tell us whether it is a lvTreeNodeStr or lvTreeNodeNum type. * key_mvtype will have the MV_STR bit set in case of lvTreeNodeStr and otherwise if lvTreeNodeNum. */ typedef lvTreeNode lvTreeNodeStr; /* last lookup clue structure */ typedef struct { lvTreeNode *lastNodeLookedUp; /* pointer to the node that was last looked up using lvAvlTreeLookup function */ lvTreeNode *lastNodeMin; /* minimum value of key that can be underneath the last looked up node's subtree */ lvTreeNode *lastNodeMax; /* maximum value of key that can be underneath the last looked up node's subtree */ } treeSrchStatus; typedef struct lvTreeStruct { /* Note if first 3 fields are disturbed, make sure to fix LV_CLONE_TREE macro which references them as a group */ unsigned short ident; /* 2-byte field (same size as mvtype) set to the value MV_LV_TREE */ unsigned short sbs_depth; /* == "n" => all nodes in current avl tree represent lvns with "n" subscripts */ uint4 avl_height; /* Height of the AVL tree rooted at "avl_root" */ struct lv_val_struct *base_lv; /* back pointer to base var lv_val (subscript depth 0) */ lvTreeNode *avl_root; /* pointer to the root of the AVL tree corresponding to this subscript level; * overloaded as the free list pointer if this "lvTree" structure is in the free list. */ lvTreeNode *sbs_parent;/* pointer to parent (points to lv_val if sbs_depth==1 and lvTreeNode if sbs_depth>1) */ treeSrchStatus lastLookup; /* clue to last node lookup in the AVL tree rooted at "avl_root" */ } lvTree; /* This section defines macros for the AVL tree implementation. Note that an AVL tree maintains its log(n) height by ensuring * the left and right subtrees at any level never differ in height by more than 1. */ #define MAX_BALANCE 1 /* the maximum difference in height of the left and right subtrees of a tree, * balance > MAX_BALANCE will trigger a re-balance */ #define TREE_DESCEND_LEFT 0 #define TREE_DESCEND_RIGHT 1 /* AVL tree algorithms talk about balance factor as being -1 (left heavy), 1 (right heavy) or 0 (balanced) * but we use 0, 1 and 2 instead for this implementation. */ #define TREE_LEFT_HEAVY 0 /* should be same as TREE_DESCEND_LEFT (an implementation efficiency) */ #define TREE_RIGHT_HEAVY 1 /* should be same as TREE_DESCEND_RIGHT (an implementation efficiency) */ #define TREE_BALANCED 2 #define TREE_IS_LEFT_HEAVY(bal) (bal) == TREE_LEFT_HEAVY #define TREE_IS_RIGHT_HEAVY(bal) (bal) == TREE_RIGHT_HEAVY #define TREE_IS_BALANCED(bal) ((bal) == TREE_BALANCED) #define TREE_IS_NOT_BALANCED(bal) (!(TREE_IS_BALANCED(bal))) #define TREE_INVERT_BALANCE_FACTOR(bal) (tree_balance_invert[bal]) #define TREE_KEY_SUBSCR_IS_CANONICAL(A_MVTYPE) (A_MVTYPE & MV_CANONICAL) #define TREE_KEY_SUBSCR_SET_MV_CANONICAL_BIT(A_MVAL) (A_MVAL)->mvtype |= MV_CANONICAL #define TREE_KEY_SUBSCR_RESET_MV_CANONICAL_BIT(A_MVAL) (A_MVAL)->mvtype &= MV_CANONICAL_OFF /* Macro to get numeric valued subscript in an lv node */ #define LV_NUM_NODE_GET_KEY(NODE, KEY) \ { \ lvTreeNodeNum *lcl_flt_node; \ int lcl_mvtype; \ \ lcl_flt_node = (lvTreeNodeNum *)NODE; \ lcl_mvtype = lcl_flt_node->key_mvtype; \ assert(MVTYPE_IS_NUMERIC(lcl_mvtype)); \ if (MV_INT & lcl_mvtype) \ (KEY)->m[1] = lcl_flt_node->key_m0; \ else \ { \ assert(lcl_flt_node->key_flags.key_bits.key_e || !lcl_flt_node->key_m1); \ ((mval_b *)(KEY))->sgne = lcl_flt_node->key_flags.key_bytes.key_sgne; \ (KEY)->m[0] = lcl_flt_node->key_m0; \ (KEY)->m[1] = lcl_flt_node->key_m1; \ } \ (KEY)->mvtype = lcl_mvtype; \ } /* Macro to get string valued subscript in an lv node */ #define LV_STR_NODE_GET_KEY(NODE, KEY) \ { \ assert(MVTYPE_IS_STRING(NODE->key_mvtype)); \ (KEY)->mvtype = NODE->key_mvtype; \ (KEY)->str.len = NODE->key_len; \ (KEY)->str.addr = NODE->key_addr; \ } /* If NODE contains a numeric key, before returning the key's mval to non-lv code make sure we * reset any bit(s) that are set only in lv code. Non-lv code does not know to handle this bit. * The only one at this point in time is MV_CANONICAL. */ #define LV_NODE_GET_KEY(NODE, KEY_MVAL) \ { \ if (TREE_KEY_SUBSCR_IS_CANONICAL(NODE->key_mvtype)) \ { /* "NODE" is of type "lvTreeNodeNum *" */ \ LV_NUM_NODE_GET_KEY(NODE, KEY_MVAL); \ (KEY_MVAL)->mvtype &= MV_CANONICAL_OFF; \ } else /* "NODE" is of type "lvTreeNode *" */ \ LV_STR_NODE_GET_KEY(NODE, KEY_MVAL); \ } /* Macro to return if a given "lvTreeNode *" pointer is a null subscript string. * Input "node" could actually be any one of "lvTreeNodeNum *" or "lvTreeNode *". * A null subscript string is of actual type "lvTreeNode *". To minimize the checks, we check for the MV_STR bit in the mvtype. * This is asserted below. For "lvTreeNodeNum *", the MV_STR bit is guaranteed not to be set. That leaves us with "lvTreeNode *". */ #define LV_NODE_KEY_IS_STRING(NODE) (DBG_ASSERT(NULL != NODE) \ MVTYPE_IS_STRING(NODE->key_mvtype)) #define LV_NODE_KEY_IS_NULL_SUBS(NODE) (LV_NODE_KEY_IS_STRING(NODE) && (0 == NODE->key_len)) #ifdef DEBUG int lvAvlTreeKeySubscrCmp(treeKeySubscr *aSubscr, lvTreeNode *bNode); int lvAvlTreeNodeSubscrCmp(lvTreeNode *aNode, lvTreeNode *bNode); #endif lvTreeNode *lvAvlTreeFirst(lvTree *lvt); lvTreeNode *lvAvlTreeLast(lvTree *lvt); lvTreeNode *lvAvlTreePrev(lvTreeNode *node); lvTreeNode *lvAvlTreeKeyPrev(lvTree *lvt, treeKeySubscr *key); lvTreeNode *lvAvlTreeNext(lvTreeNode *node); lvTreeNode *lvAvlTreeKeyNext(lvTree *lvt, treeKeySubscr *key); lvTreeNode *lvAvlTreeFirstPostOrder(lvTree *lvt); lvTreeNode *lvAvlTreeNextPostOrder(lvTreeNode *node); lvTreeNode *lvAvlTreeKeyCollatedNext(lvTree *lvt, treeKeySubscr *key); lvTreeNode *lvAvlTreeNodeCollatedNext(lvTreeNode *node); lvTreeNode *lvAvlTreeCloneSubTree(lvTreeNode *node, lvTree *lvt, lvTreeNode *avl_parent); #ifdef DEBUG boolean_t lvTreeIsWellFormed(lvTree *lvt); void assert_tree_member_offsets(void); #endif lvTreeNode *lvAvlTreeLookupInt(lvTree *lvt, treeKeySubscr *key, lvTreeNode **lookupNode); lvTreeNode *lvAvlTreeLookupNum(lvTree *lvt, treeKeySubscr *key, lvTreeNode **lookupNode); lvTreeNode *lvAvlTreeLookupStr(lvTree *lvt, treeKeySubscr *key, lvTreeNode **lookupNode); lvTreeNode *lvAvlTreeLookup(lvTree *lvt, treeKeySubscr *key, lvTreeNode **lookupNode); lvTreeNode *lvAvlTreeNodeInsert(lvTree *lvt, treeKeySubscr *key, lvTreeNode *parent); void lvAvlTreeNodeDelete(lvTree *lvt, lvTreeNode *node); /* The following LV_TREE_* macros are not defined as functions for performance reasons (to avoid overhead of parameter passing * and C stack push and pop) */ #define LV_TREE_CREATE(NEWTREE, SBS_PARENT, SBS_DEPTH, BASE_LV) \ { \ DEBUG_ONLY(assert_tree_member_offsets()); \ NEWTREE = lvtree_getslot(LV_GET_SYMVAL(base_lv)); \ /* Note: the fields are initialized below in the order in which they are defined in the "lvTree" structure */ \ NEWTREE->ident = MV_LV_TREE; \ assert(0 < SBS_DEPTH); \ NEWTREE->sbs_depth = SBS_DEPTH; \ NEWTREE->avl_height = 0; \ NEWTREE->base_lv = BASE_LV; \ NEWTREE->avl_root = NULL; \ NEWTREE->sbs_parent = SBS_PARENT; /* note: LVT_PARENT macro not used as otherwise one would wonder why \ * all members of "lvTree" structure except "sbs_parent" are initialized. \ */ \ (SBS_PARENT)->sbs_child = NEWTREE; \ NEWTREE->lastLookup.lastNodeLookedUp = NULL; \ } #define LV_TREE_NODE_DELETE(LVT, NODE) \ { \ assert(NULL != LVT); \ lvAvlTreeNodeDelete(LVT, NODE); \ /* Now that "NODE" has been removed from the AVL tree, it is safe to free the slot */ \ LVTREENODE_FREESLOT(NODE); \ TREE_DEBUG_ONLY(assert(lvTreeIsWellFormed(LVT));) \ } #define LV_TREE_CLONE(LVT, SBS_PARENT, BASE_LV) \ { \ lvTree *cloneTree; \ lvTreeNode *avl_root; \ \ cloneTree = lvtree_getslot(LV_GET_SYMVAL(BASE_LV)); \ /* The following is optimized to do the initialization of just the needed structure members. \ * For that it assumes a particular "lvTree" structure layout. The assumed layout is asserted \ * so any changes to the layout will automatically alert us (by an assert failure) here and \ * cause the below initialization to be accordingly reworked. \ */ \ assert(8 == OFFSETOF(lvTree, base_lv)); \ assert(OFFSETOF(lvTree, base_lv) + SIZEOF(LVT->base_lv) == OFFSETOF(lvTree, avl_root)); \ assert(OFFSETOF(lvTree, avl_root) + SIZEOF(LVT->avl_root) == OFFSETOF(lvTree, sbs_parent)); \ assert(OFFSETOF(lvTree, sbs_parent) + SIZEOF(LVT->sbs_parent) == OFFSETOF(lvTree, lastLookup)); \ assert(OFFSETOF(lvTree, lastLookup) + SIZEOF(LVT->lastLookup) == SIZEOF(lvTree)); \ /* Directly copy the first 3 fields */ \ memcpy(cloneTree, (LVT), OFFSETOF(lvTree, avl_height) + SIZEOF(LVT->avl_height)); \ cloneTree->base_lv = BASE_LV; \ cloneTree->sbs_parent = SBS_PARENT; /* see comment in LV_TREE_CREATE macro (against sbs_parent \ * initialization) for why LVT_PARENT macro is not used */ \ (SBS_PARENT)->sbs_child = cloneTree; \ /* reset clue in cloned tree as source tree pointers are no longer relevant in cloned tree */ \ cloneTree->lastLookup.lastNodeLookedUp = NULL; \ if (NULL != (avl_root = (LVT)->avl_root)) \ cloneTree->avl_root = lvAvlTreeCloneSubTree(avl_root, cloneTree, NULL); \ else \ cloneTree->avl_root = NULL; \ } #ifdef TREE_DEBUG # define TREE_DEBUG1(p) {printf(p); FFLUSH(stdout);} # define TREE_DEBUG2(p, q) {printf(p, q); FFLUSH(stdout);} # define TREE_DEBUG3(p, q, r) {printf(p, q, r); FFLUSH(stdout);} # define TREE_DEBUG4(p, q, r, s) {printf(p, q, r, s); FFLUSH(stdout);} # define TREE_DEBUG5(p, q, r, s, t) {printf(p, q, r, s, t); FFLUSH(stdout);} # define TREE_DEBUG_ONLY(X) X #else # define TREE_DEBUG1(p) # define TREE_DEBUG2(p, q) # define TREE_DEBUG3(p, q, r) # define TREE_DEBUG4(p, q, r, s) # define TREE_DEBUG5(p, q, r, s, t) # define TREE_DEBUG_ONLY(X) #endif #endif fis-gtm-V6.0-003/sr_port/lv_val.h0000644000032200000250000004475212201176160015476 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef LVVAL_H_INCLUDED #define LVVAL_H_INCLUDED #include /* for OFFSETOF macro used in the IS_OFFSET_AND_SIZE_MATCH macro */ #include "hashtab_mname.h" #include "lv_tree.h" /* Define a few generic LV related macros. These macros work irrespective of whether the input is an unsubscripted * local variable (aka base variable) which is of type (lv_val *) or a subscripted local variable which is of type * (lvTreeNode *). All of these assume the layout of the two structures is very similar (asserted in "LV_TREE_CREATE" * macro). These macros will be used extensively for code centralization and to avoid code duplication. * * The macros that are only passed an LV_PTR need to ensure that it is indeed a "lv_val *" or a "lvTreeNode *". * The macros that are also passed an IS_BASE_VAR parameter can safely assume this to be the case since the IS_BASE_VAR * parameter would have been computed using the LV_IS_BAS_VAR macro which already does the ensure. * So we avoid the duplicate assert in these cases. */ #define SYM_IS_SYMVAL(SYM) (MV_SYM == (SYM)->ident) #define IS_LV_TREE(LVT) (MV_LV_TREE == ((lvTree *)LVT)->ident) #define LV_PARENT(LV) LV_AVLNODE_PARENT(LV) #define LV_AVLNODE_PARENT(PTR) (((lvTreeNode *)PTR)->tree_parent) #define LVT_PARENT(LVT) (((lvTree *)LVT)->sbs_parent) #define IS_LVAVLTREENODE(PTR) (IS_LV_TREE(LV_AVLNODE_PARENT((lv_val *)PTR))) #define IS_PARENT_MV_SYM(LV_PTR) (SYM_IS_SYMVAL(LV_SYMVAL((lv_val *)LV_PTR))) #define DBG_ASSERT_LVT(LVT) DBG_ASSERT(IS_LV_TREE(LVT)) /* is "lvTree *" */ #define DBG_ASSERT_LV_OR_TREENODE(LV_PTR) DBG_ASSERT(IS_PARENT_MV_SYM(LV_PTR) /* is "lv_val *" */ \ || IS_LVAVLTREENODE(LV_PTR)) /* is "lvTreeNode *" or "lvTreeNodeFlt *" */ #define LV_IS_BASE_VAR(LV_PTR) (DBG_ASSERT_LV_OR_TREENODE(LV_PTR) \ IS_PARENT_MV_SYM(LV_PTR)) /* Input to macro is LV_PTR which is guaranteed to be a non-base lv. Return value is the corresponding base_lv */ #define LV_GET_BASE_VAR(LV_PTR) (DBG_ASSERT(!LV_IS_BASE_VAR(LV_PTR)) \ DBG_ASSERT(NULL != LV_AVLNODE_PARENT(LV_PTR)) \ LV_AVLNODE_PARENT(LV_PTR)->base_lv) #define LVT_GET_BASE_VAR(LVT) (DBG_ASSERT_LVT(LVT) \ LVT->base_lv) #define LVT_GET_SYMVAL(LVT) (DBG_ASSERT_LVT(LVT) \ LV_GET_SYMVAL(LVT_GET_BASE_VAR(LVT))) #define LV_GET_PARENT_TREE(LV_PTR) (DBG_ASSERT(!LV_IS_BASE_VAR(LV_PTR)) \ DBG_ASSERT(NULL != LV_AVLNODE_PARENT(LV_PTR)) \ LV_AVLNODE_PARENT(LV_PTR)) /* The following 3 macros operate on the ptrs.val_ent.children field. * If the situation demands returning the children ptr, then use LV_GET_CHILD or LV_CHILD macros in that order of preference. * If the situation demands checking if any children exist, then use LV_HAS_CHILD macro. */ #define LV_CHILD(LV_PTR) (((lv_val *)LV_PTR)->ptrs.val_ent.children) /* The following macro is an enhanced version of LV_CHILD that can be used wherever you would prefer or dont mind additional * assert checking. In some cases, this cannot be used (e.g. in the left hand side of an assignment operation). But otherwise * it is preferrable to use this macro as opposed to LV_CHILD. */ #define LV_GET_CHILD(LV_PTR) (DBG_ASSERT_LV_OR_TREENODE(LV_PTR) \ LV_CHILD(LV_PTR)) \ /* if an lv_ptr's chlidren tree pointer is non-NULL, we should be guaranteed (by lv_kill) * that there is at least one child node in that subscript tree (currently only an avl tree). * assert that as well. */ #define LV_HAS_CHILD(LV_PTR) (DBG_ASSERT_LV_OR_TREENODE(LV_PTR) \ (NULL != LV_CHILD(LV_PTR)) \ DEBUG_ONLY(&& assert(MV_LV_TREE == (LV_CHILD(LV_PTR))->ident)) \ DEBUG_ONLY(&& assert((LV_CHILD(LV_PTR))->avl_height))) /* Like the LV_CHILD and LV_GET_CHILD macro variants, the below macros need to be used with preference to LV_GET_SYMVAL * unless it is needed in the left hand side of an assignment in which case use the LV_SYMVAL macro. */ #define LV_SYMVAL(BASE_VAR) ((BASE_VAR)->ptrs.val_ent.parent.sym) #define LV_GET_SYMVAL(BASE_VAR) (DBG_ASSERT(LV_IS_BASE_VAR(BASE_VAR)) \ LV_SYMVAL(BASE_VAR)) /* The below macro relies on the fact that the parent field is at the same offset in an "lv_val" as it is in a "lvTreeNode". * This is asserted in "LV_TREE_CREATE" macro. */ #define LV_GET_PARENT(LV_PTR) (DBG_ASSERT_LV_OR_TREENODE(LV_PTR) \ LV_AVLNODE_PARENT(LV_PTR)) #define LVT_GET_PARENT(LVT) (DBG_ASSERT_LVT(LVT) \ LVT_PARENT(LVT)) #define LV_IS_VAL_DEFINED(LV_PTR) (DBG_ASSERT_LV_OR_TREENODE(LV_PTR) \ MV_DEFINED(&((lv_val *)LV_PTR)->v)) #define LV_SBS_DEPTH(LV_PTR, IS_BASE_VAR, DEPTH) \ { \ assert(IS_OFFSET_AND_SIZE_MATCH(lvTree, sbs_depth, symval, sbs_depth)); \ assert(!IS_BASE_VAR || (0 == LV_PTR->ptrs.val_ent.parent.sbs_tree->sbs_depth)); \ assert(IS_BASE_VAR || (0 < LV_PTR->ptrs.val_ent.parent.sbs_tree->sbs_depth)); \ DEPTH = LV_PTR->ptrs.val_ent.parent.sbs_tree->sbs_depth; \ } /* Mark mval held by lv_ptr to be undefined. Also lets stp_gcol and lv_gcol know to NOT protect * (from garbage collection) any strings this lv_val was pointing to at the time of the free. */ #define LV_VAL_CLEAR_MVTYPE(LVPTR) (LVPTR)->v.mvtype = 0; /* note: also clears any use as MV_ALIASCONT */ /* Queue an lv_val block back on the lv_val free list at the given anchor. * Operations: * 1) Debugging aids in debug builds. * 2) Do the queueing. * 3) Clear the mv_type so it is definitely a deleted value. * * Callers should use LV_FREESLOT instead of directly invoking LV_FLIST_ENQUEUE. * There are few exceptions like unw_mv_ent.c. */ #define LV_FLIST_ENQUEUE(flist_ptr, lv_ptr) \ { \ lv_val **savflist_ptr = (flist_ptr); \ DBGRFCT((stderr, "\n<< Free list queueing of lv_val at 0x"lvaddr" by %s line %d\n", \ (lv_ptr), __FILE__, __LINE__)); \ assert(LV_IS_BASE_VAR(lv_ptr)); \ /* assert that any subtree underneath this lv_ptr has already been freed up */ \ assert(NULL == LV_CHILD(lv_ptr)); \ LV_VAL_CLEAR_MVTYPE(lv_ptr); \ DEBUG_ONLY(memset((lv_ptr), 0xfd, SIZEOF(lv_val))); \ (lv_ptr)->ptrs.free_ent.next_free = *savflist_ptr; \ *savflist_ptr = (lv_ptr); \ LV_SYMVAL(lv_ptr) = NULL; \ DBGALS_ONLY((lv_ptr)->lvmon_mark = FALSE); \ } /* Increment the cycle for tstarts. Field is compared to same name field in lv_val to signify an lv_val has been seen during a given transaction so reference counts are kept correct. If counter wraps, clear all the counters in all accessible lv_vals. */ #define INCR_TSTARTCYCLE \ { \ symval *lvlsymtab; \ lv_blk *lvbp; \ lv_val *lvp, *lvp_top; \ \ if (0 == ++tstartcycle) \ { /* Set tstart cycle in all active lv_vals to 0 */ \ for (lvlsymtab = curr_symval; lvlsymtab; lvlsymtab = lvlsymtab->last_tab) \ for (lvbp = curr_symval->lv_first_block; lvbp; lvbp = lvbp->next) \ for (lvp = (lv_val *)LV_BLK_GET_BASE(lvbp), lvp_top = LV_BLK_GET_FREE(lvbp, lvp); \ lvp < lvp_top; lvp++) \ lvp->stats.tstartcycle = 0; \ tstartcycle = 1; \ } \ } /* Increment the cycle for misc lv tasks. Field is compared to same name field in lv_val to signify an lv_val has been seen during a given transaction so reference counts are kept correct. If counter wraps, clear all the counters in all accessible lv_vals. */ #define INCR_LVTASKCYCLE \ { \ symval *lvlsymtab; \ lv_blk *lvbp; \ lv_val *lvp, *lvp_top; \ \ if (0 == ++lvtaskcycle) \ { /* Set tstart cycle in all active lv_vals to 0 */ \ for (lvlsymtab = curr_symval; lvlsymtab; lvlsymtab = lvlsymtab->last_tab) \ for (lvbp = curr_symval->lv_first_block; lvbp; lvbp = lvbp->next) \ for (lvp = (lv_val *)LV_BLK_GET_BASE(lvbp), lvp_top = LV_BLK_GET_FREE(lvbp, lvp); \ lvp < lvp_top; lvp++) \ lvp->stats.lvtaskcycle = 0; \ lvtaskcycle = 1; \ } \ } /* Initialize given lv_val (should be of type "lv_val *" and not "lvTreeNode *") */ #define LVVAL_INIT(lv, symvalarg) \ { \ DBGALS_ONLY(GBLREF boolean_t lvmon_enabled;) \ assert(MV_SYM == symvalarg->ident); /* ensure above macro is never used to initialize a "lvTreeNode *" */ \ (lv)->v.mvtype = 0; \ (lv)->stats.trefcnt = 1; \ (lv)->stats.crefcnt = 0; \ (lv)->stats.tstartcycle = 0; \ (lv)->stats.lvtaskcycle = 0; \ (lv)->has_aliascont = FALSE; \ DBGALS_ONLY(if (lvmon_enabled) (lv)->lvmon_mark = TRUE; else (lv)->lvmon_mark = FALSE); \ (lv)->tp_var = NULL; \ LV_CHILD(lv) = NULL; \ LV_SYMVAL(lv) = symvalarg; \ } /* Macro to call lv_var_clone and set the cloned status in the tp_var structure. * Note that we want the cloned tree to have its base_lv point back to "lv" and not the cloned lv. * This is because in case we want to restore the lv, we can then safely move the saved tree * back to "lv" without then having to readjust the base_lv linked in the "lvTree *" structures beneath */ #define TP_VAR_CLONE(lv) \ { \ lv_val *lcl_savelv; \ tp_var *lcl_tp_var; \ \ assert(LV_IS_BASE_VAR(lv)); \ lcl_tp_var = (lv)->tp_var; \ assert(lcl_tp_var); \ assert(!lcl_tp_var->var_cloned); \ lcl_savelv = lcl_tp_var->save_value; \ assert(NULL != lcl_savelv); \ assert(NULL == LV_CHILD(lcl_savelv)); \ LV_CHILD(lcl_savelv) = LV_CHILD(lv); \ lv_var_clone(lcl_savelv, lv); \ lcl_tp_var->var_cloned = TRUE; \ } /* Macro to indicate if a given lv_val is an alias or not */ #define IS_ALIASLV(lv) (DBG_ASSERT(LV_IS_BASE_VAR(lv)) ((1 < (lv)->stats.trefcnt) || (0 < (lv)->stats.crefcnt)) \ DEBUG_ONLY(&& assert(IS_PARENT_MV_SYM(lv)))) #define LV_NEWBLOCK_INIT_ALLOC 16 #define LV_BLK_GET_BASE(LV_BLK) (((sm_uc_ptr_t)LV_BLK) + SIZEOF(lv_blk)) #define LV_BLK_GET_FREE(LV_BLK, LVBLK_BASE) (&LVBLK_BASE[LV_BLK->numUsed]) typedef struct lv_val_struct { mval v; /* Value associated with this lv_val */ /* Note: The offsets of "ptrs.val_ent.children" and "ptrs.val_ent.parent.sym" are relied upon by * other modules (e.g. lv_tree.h) and asserted in LV_TREE_CREATE macro. */ union { struct { lvTree *children; union { /* Note these two fields are still available when mvtype == MV_LVCOPIED * and there is code in "als_check_xnew_var_aliases" that depends on this */ struct symval_struct *sym; lvTree *sbs_tree; } parent; } val_ent; struct { struct lv_val_struct *next_free; } free_ent; struct { /* When xnew'd lv's are copied to previous symtab, their new root is * set here so multiple references can be resolved properly (mvtype == MV_LVCOPIED) */ struct lv_val_struct *newtablv; } copy_loc; } ptrs; struct { /* Note these flags are irrelevant for other than base (unsubscripted) local vars */ int4 trefcnt; /* Total refcnt (includes container vars) */ int4 crefcnt; /* Container reference count */ uint4 tstartcycle; /* Cycle of level 0 tstart command */ uint4 lvtaskcycle; /* Cycle of various lv related tasks */ } stats; boolean_t has_aliascont; /* This base var has or had an alias container in it */ boolean_t lvmon_mark; /* This lv_val is being monitored; Used only #ifdef DEBUG_ALIAS */ struct tp_var_struct *tp_var; } lv_val; typedef struct lv_blk_struct { struct lv_blk_struct *next; uint4 numAlloc; uint4 numUsed; } lv_blk; /* When op_xnew creates a symtab, these blocks will describe the vars that were passed through from the previous symtab. They need special alias processing. Note we keep our own copy of the key (rather than pointing to the hash table entry) since op_xnew processing can cause a hash table expansion and we have no good way to update pointers so save the hash values as part of the key to eliminate another lookup. */ typedef struct lv_xnew_var_struct { struct lv_xnew_var_struct *next; mname_entry key; lv_val *lvval; /* There are two uses for this field. In op_new, it is used to hold the previous lvval addr for the 2nd pass. In unwind processing (als_check_xnew_var_aliases) it holds the lvval in the symtab being popped since it cannot be obtained once the symtab entry is deleted in the first pass (step 2). */ } lv_xnew_var; /* While lv_xnew_var_struct are the structures that were explicitly passed through, this is a list of the structures that are pointed to by any container vars in any of the passed through vars and any of the vars those point to, etc. The objective is to come up with a definitive list of structures to search to see if containers got created in them that point to the structure being torn down. */ typedef struct lv_xnewref_struct { struct lv_xnewref_struct *next; lv_val *lvval; /* This structure can be addressed through the passed thru vars but is not itself one of them */ } lv_xnew_ref; typedef struct symval_struct { unsigned short ident; unsigned short sbs_depth; /* is always 0. Defined to match offset & size of lvTree->sbs_depth. * This way callers can avoid an if check depending on whether * the input pointer is a "symval *" or a "lvTree *" type. * This is also asserted in "LV_TREE_CREATE" macro. */ boolean_t tp_save_all; lv_xnew_var *xnew_var_list; lv_xnew_ref *xnew_ref_list; hash_table_mname h_symtab; lv_blk *lv_first_block; lv_blk *lvtree_first_block; lv_blk *lvtreenode_first_block; lv_val *lv_flist; lvTree *lvtree_flist; lvTreeNode *lvtreenode_flist; struct symval_struct *last_tab; int4 symvlvl; /* Level of symval struct (nesting) */ boolean_t trigr_symval; /* Symval is owned by a trigger */ boolean_t alias_activity; } symval; /* Structure to describe the block allocated to describe a var specified on a TSTART to be restored on a TP restart. Block moved here from tpframe.h due to the structure references it [now] makes. Block can take two forms: (1) the standard tp_data form which marks vars to be modified or (2) the tp_change form where a new symbol table was stacked. */ typedef struct tp_var_struct { struct tp_var_struct *next; struct lv_val_struct *current_value; struct lv_val_struct *save_value; mname_entry key; boolean_t var_cloned; GTM64_ONLY(int4 filler;) } tp_var; typedef struct lvname_info_struct { intszofptr_t total_lv_subs; /* Total subscripts + 1 for name itself */ lv_val *start_lvp; mval *lv_subs[MAX_LVSUBSCRIPTS]; lv_val *end_lvp; } lvname_info; typedef lvname_info *lvname_info_ptr; #define DOTPSAVE_FALSE FALSE /* macro to indicate parameter by name "dotpsave" is passed a value of "FALSE" */ #define DOTPSAVE_TRUE TRUE /* macro to indicate parameter by name "dotpsave" is passed a value of "TRUE" */ #define DO_SUBTREE_FALSE FALSE /* macro to indicate parameter by name "do_subtree" is passed a value of "FALSE" */ #define DO_SUBTREE_TRUE TRUE /* macro to indicate parameter by name "do_subtree" is passed a value of "TRUE" */ #define LV_FREESLOT(LV) \ { \ symval *sym; \ \ assert(LV_IS_BASE_VAR(LV)); \ sym = LV_GET_SYMVAL(LV); \ LV_FLIST_ENQUEUE(&sym->lv_flist, LV); \ } #define LVTREE_FREESLOT(LVT) \ { \ symval *sym; \ \ sym = LVT_GET_SYMVAL(LVT); \ assert(NULL != LVT_GET_PARENT(LVT)); \ LVT_PARENT(LVT) = NULL; /* indicates this is free */ \ /* avl_root is overloaded to store linked list in free state */ \ LVT->avl_root = (lvTreeNode *)sym->lvtree_flist; \ sym->lvtree_flist = LVT; \ } #define LVTREENODE_FREESLOT(LV) \ { \ symval *sym; \ lv_val *base_lv; \ \ assert(!LV_IS_BASE_VAR(LV)); \ base_lv = LV_GET_BASE_VAR(LV); \ sym = LV_GET_SYMVAL(base_lv); \ LV_AVLNODE_PARENT(LV) = NULL; /* indicates to stp_gcol this is free */ \ /* sbs_child is overloaded to store linked list in free state */ \ (LV)->sbs_child = (lvTree *)sym->lvtreenode_flist; \ sym->lvtreenode_flist = LV; \ } unsigned char *format_lvname(lv_val *start, unsigned char *buff, int size); lv_val *lv_getslot(symval *sym); lvTree *lvtree_getslot(symval *sym); lvTreeNode *lvtreenode_getslot(symval *sym); void lv_kill(lv_val *lv, boolean_t dotpsave, boolean_t do_subtree); void lv_killarray(lvTree *lvt, boolean_t dotpsave); void lv_newblock(symval *sym, int numElems); void lv_newname(ht_ent_mname *hte, symval *sym); void lvtree_newblock(symval *sym, int numElems); void lvtreenode_newblock(symval *sym, int numElems); void lv_var_clone(lv_val *clone_var, lv_val *base_lv); void lvzwr_var(lv_val *lv, int4 n); void op_clralsvars(lv_val *dst); void op_fndata(lv_val *x, mval *y); void op_fnzdata(lv_val *x, mval *y); void op_fnincr(lv_val *local_var, mval *increment, mval *result); void op_fnnext(lv_val *src,mval *key,mval *dst); void op_fno2(lv_val *src,mval *key,mval *dst,mval *direct); void op_fnorder(lv_val *src, mval *key, mval *dst); void op_fnzahandle(lv_val *src, mval *dst); void op_fnzprevious(lv_val *src, mval *key, mval *dst); void op_kill(lv_val *lv); void op_killalias(int srcindx); void op_lvzwithdraw(lv_val *lv); void op_setals2als(lv_val *src, int dstindx); void op_setalsin2alsct(lv_val *src, lv_val *dst); void op_setalsctin2als(lv_val *src, int dstindx); void op_setalsct2alsct(lv_val *src, lv_val *dst); void op_setfnretin2als(mval *srcmv, int destindx); /* no an lv_val ref but kept here with its friends so it not lonely */ void op_setfnretin2alsct(mval *srcmv, lv_val *dstlv); void op_zshow(mval *func, int type, lv_val *lvn); lv_val *op_getindx(UNIX_ONLY_COMMA(int argcnt) lv_val *start, ...); lv_val *op_putindx(UNIX_ONLY_COMMA(int argcnt) lv_val *start, ...); lv_val *op_srchindx(UNIX_ONLY_COMMA(int argcnt_arg) lv_val *lv, ...); lv_val *op_m_srchindx(UNIX_ONLY_COMMA(int4 count) lv_val *lvarg, ...); /* Function Prototypes for local variables functions of merge */ boolean_t lcl_arg1_is_desc_of_arg2(lv_val *cur, lv_val *ref); unsigned char *format_key_mvals(unsigned char *buff, int size, lvname_info *lvnp); unsigned char *format_key_lv_val(lv_val *lvpin, unsigned char *buff, int size); #endif fis-gtm-V6.0-003/sr_port/lv_var_clone.c0000644000032200000250000000350412201176160016645 0ustar librarygtc/**************************************************************** * * * Copyright 2009, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include /* For offsetof() macro */ #include "gtm_string.h" #include "gtm_stdio.h" #include "lv_val.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "alias.h" /* Routine to clone the children of a tree. The input lv_val "clone_var" should be a clone of the base lv_val * owning the tree we wish to clone. The pointers in this copy will be duplicated and the new tree linked to * "clone_var". Note that the owning symval of clone_var should be set appropriately such as in the case of * xnew processing where we are cloneing a tree out of one symtab and into another. The new tree will be * created in the symtab of the input lv_val regardless of which symtab owns the processed lv_vals. * * Input "base_lv" is the base variable that the cloned tree should point back to. */ void lv_var_clone(lv_val *clone_var, lv_val *base_lv) { lvTree *clone_lvt; assert(clone_var); assert(LV_IS_BASE_VAR(clone_var)); assert(base_lv); assert(LV_IS_BASE_VAR(base_lv)); DBGRFCT((stderr, "\nlv_var_clone: Cloning lv_val tree at 0x"lvaddr"\n", clone_var)); clone_lvt = LV_GET_CHILD(clone_var); /* "clone_lvt" holds tree to be cloned as we build new tree for clone_var */ if (NULL != clone_lvt) { assert(1 == clone_lvt->sbs_depth); LV_TREE_CLONE(clone_lvt, (lvTreeNode *)clone_var, base_lv); } } fis-gtm-V6.0-003/sr_port/lvn.c0000644000032200000250000000426012201176160014773 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "fullbool.h" #include "opcode.h" #include "mdq.h" #include "toktyp.h" #include "advancewindow.h" #include "show_source_line.h" GBLREF boolean_t run_time; error_def(ERR_MAXNRSUBSCRIPTS); error_def(ERR_RPARENMISSING); error_def(ERR_VAREXPECTED); error_def(ERR_SIDEEFFECTEVAL); int lvn(oprtype *a, opctype index_op, triple *parent) { char x; oprtype *sb, *sb1, *sb2, subscripts[MAX_LVSUBSCRIPTS]; triple *ref, *root; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (TREF(window_token) != TK_IDENT) { stx_error(ERR_VAREXPECTED); return FALSE; } *a = put_mvar(&(TREF(window_ident))); advancewindow(); if (TK_LPAREN != TREF(window_token)) return TRUE; assert(TRIP_REF == a->oprclass); DEBUG_ONLY(ref = a->oprval.tref); assert(OC_VAR == ref->opcode); sb1 = sb2 = subscripts; *sb1++ = *a; for (;;) { if (ARRAYTOP(subscripts) <= sb1) { stx_error(ERR_MAXNRSUBSCRIPTS); return FALSE; } advancewindow(); if (EXPR_FAIL == expr(sb1++, MUMPS_EXPR)) return FALSE; if (TK_RPAREN == (x = TREF(window_token))) /* NOTE assignment */ { advancewindow(); break; } if (TK_COMMA != x) { stx_error(ERR_RPARENMISSING); return FALSE; } } if (parent) { /* only $ORDER, $NEXT, $ZPREV have parent */ sb1--; if ((sb1 - sb2) == 1) /* only name and 1 subscript */ { /* SRCHINDX not necessary if only 1 subscript */ sb = &parent->operand[1]; *sb = *sb1; return TRUE; } } root = ref = newtriple(index_op); ref->operand[0] = put_ilit((mint)(sb1 - sb2)); SUBS_ARRAY_2_TRIPLES(ref, sb1, sb2, subscripts, 0); if (parent) { parent->operand[0] = put_tref(root); sb = &parent->operand[1]; *sb = *sb1; return TRUE; } *a = put_tref(root); return TRUE; } fis-gtm-V6.0-003/sr_port/lvzwr_arg.c0000644000032200000250000000320412201176160016206 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "hashtab_mname.h" #include "hashtab_addr.h" #include "zwrite.h" GBLREF lvzwrite_datablk *lvzwrite_block; void lvzwr_arg(int t, mval *a1, mval *a2) { int sub_idx; assert(lvzwrite_block); sub_idx = lvzwrite_block->subsc_count++; /* it would be good to guard the array sub_idx < sizeof... */ if (a1) { MV_FORCE_DEFINED(a1); if (MV_IS_CANONICAL(a1)) MV_FORCE_NUMD(a1); MV_FORCE_STRD(a1); if ((ZWRITE_VAL != t) && (0 == a1->str.len)) /* value is real - leave it alone */ a1 = NULL; } if (a2) { MV_FORCE_DEFINED(a2); if (MV_IS_CANONICAL(a2)) MV_FORCE_NUMD(a2); MV_FORCE_STRD(a2); if (0 == a2->str.len) /* can never be value */ a2 = NULL; } ((zwr_sub_lst *)lvzwrite_block->sub)->subsc_list[sub_idx].subsc_type = t; ((zwr_sub_lst *)lvzwrite_block->sub)->subsc_list[sub_idx].first = a1; ((zwr_sub_lst *)lvzwrite_block->sub)->subsc_list[sub_idx].second = a2; if ((ZWRITE_ASTERISK != t) && (ZWRITE_ALL != t)) lvzwrite_block->mask |= 1 << sub_idx; if (ZWRITE_VAL != t) lvzwrite_block->fixed = FALSE; return; } fis-gtm-V6.0-003/sr_port/lvzwr_fini.c0000644000032200000250000000532312201176177016376 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "lv_val.h" #include #include "mv_stent.h" #include "mlkdef.h" #include "zshow.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "zwrite.h" #include "op.h" #include "patcode.h" GBLREF symval *curr_symval; GBLREF lvzwrite_datablk *lvzwrite_block; GBLREF zshow_out *zwr_output; error_def(ERR_UNDEF); void lvzwr_fini(zshow_out *out, int t) { int4 size; mval local; mname_entry temp_key; ht_ent_mname *tabent; mident_fixed m; zwr_output = out; assert(lvzwrite_block); if (zwr_patrn_mident == lvzwrite_block->zwr_intype) { /* Mident specified for "pattern" (fixed name, no pattern) */ size = (lvzwrite_block->pat->str.len <= MAX_MIDENT_LEN) ? lvzwrite_block->pat->str.len : MAX_MIDENT_LEN; temp_key.var_name = lvzwrite_block->pat->str; COMPUTE_HASH_MNAME(&temp_key); tabent = lookup_hashtab_mname(&curr_symval->h_symtab, &temp_key); if (!tabent || !LV_IS_VAL_DEFINED(tabent->value) && !LV_HAS_CHILD(tabent->value)) { lvzwrite_block->subsc_count = 0; rts_error(VARLSTCNT(4) ERR_UNDEF, 2, size, lvzwrite_block->pat->str.addr); } else { lvzwrite_block->curr_name = &tabent->key.var_name; lvzwr_var(((lv_val *)tabent->value), 0); } } else { /* mval specified for character "pattern" (pattern matching) */ assert(zwr_patrn_mval == lvzwrite_block->zwr_intype); memset(m.c, 0, SIZEOF(m.c)); local.mvtype = MV_STR; local.str.addr = &m.c[0]; local.str.len = 1; m.c[0] = '%'; /* Starting variable name for search (first possible varname) */ lvzwrite_block->fixed = FALSE; while (local.str.len) { if (do_pattern(&local, lvzwrite_block->pat)) { memset(&m.c[local.str.len], 0, SIZEOF(m.c) - local.str.len); temp_key.var_name = local.str; COMPUTE_HASH_MNAME(&temp_key); if (NULL != (tabent = lookup_hashtab_mname(&curr_symval->h_symtab, &temp_key))) { lvzwrite_block->curr_name = &tabent->key.var_name; lvzwr_var(((lv_val *)tabent->value), 0); } } op_fnlvname(&local, TRUE, &local); assert(local.str.len <= MAX_MIDENT_LEN); memcpy(&m.c[0], local.str.addr, local.str.len); local.str.addr = &m.c[0]; } } lvzwrite_block->curr_subsc = lvzwrite_block->subsc_count = 0; return; } fis-gtm-V6.0-003/sr_port/lvzwr_init.c0000644000032200000250000000424212201176160016403 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "zwrite.h" #include "subscript.h" #include "mlkdef.h" #include "zshow.h" #include "alias.h" GBLREF lvzwrite_datablk *lvzwrite_block; GBLREF int merge_args; GBLREF symval *curr_symval; GBLREF uint4 zwrtacindx; void lvzwr_init(enum zwr_init_types zwrpattyp, mval *val) { lvzwrite_datablk *prevzwrb; /* Standard call at start of zwrite type functions. If this symval has aliases in it, * prep a hash table we will use to track the lv_val addrs we process (but only if not merging). */ if (!merge_args) { /* Re-initialize table even if no "aliases" defined since dotted parms are actually aliases too and * will be placed in this table by lvzwr_out(). */ als_zwrhtab_init(); zwrtacindx = 0; } if (!lvzwrite_block) { lvzwrite_block = (lvzwrite_datablk *)malloc(SIZEOF(lvzwrite_datablk)); memset(lvzwrite_block, 0, SIZEOF(lvzwrite_datablk)); } else { /* Get back to one zwrite_block if multiples were stacked (and left over) */ for (prevzwrb = lvzwrite_block->prev; prevzwrb; lvzwrite_block = prevzwrb, prevzwrb = lvzwrite_block->prev) { if (lvzwrite_block->sub) free(lvzwrite_block->sub); free(lvzwrite_block); } } lvzwrite_block->zwr_intype = zwrpattyp; if (!merge_args && val) { /* val may be null when called from gtm_startup/gtm$startup */ MV_FORCE_STR(val); lvzwrite_block->pat = val; } else lvzwrite_block->pat = NULL; lvzwrite_block->mask = lvzwrite_block->subsc_count = 0; if (!lvzwrite_block->sub) lvzwrite_block->sub = (zwr_sub_lst *)malloc(SIZEOF(zwr_sub_lst) * MAX_LVSUBSCRIPTS); lvzwrite_block->fixed = TRUE; return; } fis-gtm-V6.0-003/sr_port/lvzwr_key.c0000644000032200000250000000274712201176160016240 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "min_max.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "zwrite.h" #include "gtm_string.h" GBLREF lvzwrite_datablk *lvzwrite_block; unsigned char *lvzwr_key(unsigned char *buff, int size) { int sub_idx, len; mstr sub; unsigned char *cp, *cq; assert(lvzwrite_block); len = MIN(size, lvzwrite_block->curr_name->len); assert(MAX_MIDENT_LEN >= len); memcpy(buff, lvzwrite_block->curr_name->addr, len); size -= len; buff += len; if (lvzwrite_block->subsc_count) { if (size) { *buff++ = '('; size--; } for (sub_idx = 0; ; ) { mval_lex(((zwr_sub_lst *)lvzwrite_block->sub)->subsc_list[sub_idx].actual, &sub); if (0 <= (size -= sub.len)) { memcpy(buff, sub.addr, sub.len); buff += sub.len; } else break; if (++sub_idx < lvzwrite_block->curr_subsc && size) { *buff++ = ','; size--; } else { if (size) { *buff++ = ')'; size--; } break; } } } return buff; } fis-gtm-V6.0-003/sr_port/lvzwr_out.c0000644000032200000250000002712612201176160016255 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_stdio.h" #include "lv_val.h" #include "gdsroot.h" #include "gdskill.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "zwrite.h" #include "mlkdef.h" #include "zshow.h" #include "filestruct.h" #include "gdscc.h" #include "copy.h" #include "jnl.h" #include "buddy_list.h" #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "merge_def.h" #include "gvname_info.h" #include "op_merge.h" #include "op.h" #include "gtmmsg.h" #include "sgnl.h" #include "stringpool.h" #include "alias.h" #include "callg.h" GBLREF lvzwrite_datablk *lvzwrite_block; GBLREF zshow_out *zwr_output; GBLREF gv_namehead *gv_target; GBLREF gv_key *gv_currkey; GBLREF int merge_args; GBLREF merge_glvn_ptr mglvnp; GBLREF gd_region *gv_cur_region; GBLREF symval *curr_symval; GBLREF zwr_hash_table *zwrhtab; /* Used to track aliases during zwrites */ GBLREF uint4 zwrtacindx; /* When creating $ZWRTACxxx vars for ZWRite, this holds xxx */ LITDEF MSTR_CONST(semi_star, " ;*"); LITDEF MSTR_CONST(dzwrtac_clean, "$ZWRTAC=\"\""); error_def(ERR_MAXNRSUBSCRIPTS); error_def(ERR_MERGEINCOMPL); void lvzwr_out_targkey(mstr *one); void lvzwr_out_targkey(mstr *one) { int n, nsubs; zshow_output(zwr_output, lvzwrite_block->curr_name); nsubs = lvzwrite_block->curr_subsc; if (nsubs) { *one->addr = '('; zshow_output(zwr_output, one); for (n = 0 ; ; ) { mval_write(zwr_output, ((zwr_sub_lst *)lvzwrite_block->sub)->subsc_list[n].actual, FALSE); if (++n < nsubs) { *one->addr = ','; zshow_output(zwr_output, one); } else { *one->addr = ')'; zshow_output(zwr_output, one); break; } } } } void lvzwr_out(lv_val *lvp) { char buff; uchar_ptr_t lastc; int n, nsubs, sbs_depth; lv_val *dst_lv, *res_lv, *lvpc; mstr one; mval *subscp, *val, outindx; ht_ent_addr *tabent_addr; ht_ent_mname *tabent_mname; boolean_t htent_added, dump_container; zwr_alias_var *newzav, *zav; mident_fixed zwrt_varname; lvzwrite_datablk *newzwrb; gparam_list param_list; /* for op_putindx call through callg */ val = &lvp->v; assert(lvzwrite_block); if (!merge_args) { /* The cases that exist here are: * 1) This is a container variable. If the lv_val it refers to has been printed, show that association. * Else, "create" a $ZWRTACxxx var/index that will define the value. Then before returning, cause * that container var to be dumped with the appropriate $ZWRTACxxx index as the var name. * 2) This is an alias base variable. If first time seen, we print normally but record it and put a * ";#" tag on the end to signify it is an alias var (doesn't affect value). If we look it up and it * is not the first time this lv_val has been printed, then we instead print the statement needed to * alias it to the first seen var. * 3) This is just a normal var needing to be printed normally. */ htent_added = FALSE; one.addr = &buff; one.len = 1; lvzwrite_block->zav_added = FALSE; if (lvp->v.mvtype & MV_ALIASCONT) { /* Case 1 -- have an alias container */ assert(curr_symval->alias_activity); assert(!LV_IS_BASE_VAR(lvp)); /* verify is subscripted var */ lvpc = (lv_val *)lvp->v.str.addr; assert(lvpc); assert(LV_IS_BASE_VAR(lvpc)); /* Verify base var lv_val */ if (tabent_addr = (ht_ent_addr *)lookup_hashtab_addr(&zwrhtab->h_zwrtab, (char **)&lvpc)) { /* The value was found, we have a reference we can print now */ assert(HTENT_VALID_ADDR(tabent_addr, zwr_alias_var, zav)); *one.addr = '*'; zshow_output(zwr_output, &one); lvzwr_out_targkey(&one); *one.addr = '='; zshow_output(zwr_output, &one); zav = (zwr_alias_var *)tabent_addr->value; assert(0 < zav->zwr_var.len); zwr_output->flush = TRUE; zshow_output(zwr_output, (const mstr *)&zav->zwr_var); return; } /* This lv_val isn't known to us yet. Scan the hash curr_symval hash table to see if it is known as a * base variable as we could have a "forward reference" here. */ tabent_mname = als_lookup_base_lvval(lvpc); /* note even though both paths below add a zav, not bothering to set zav_added because that flag is * really only (currently) cared about in reference to processing a basevar so we wouldn't * be in this code path anyway. Comment here to record potential usage if that changes. */ if (tabent_mname) { /* Found a base var it can reference -- create a zwrhtab entry for it */ assert(tabent_mname->key.var_name.len); newzav = als_getzavslot(); newzav->zwr_var = tabent_mname->key.var_name; htent_added = add_hashtab_addr(&zwrhtab->h_zwrtab, (char **)&lvpc, newzav, &tabent_addr); assert(htent_added); dump_container = FALSE; } else { /* Unable to find lv_val .. must be "orphaned" so we generate a new $ZWRTAC var for it. The first * check however is if this is the first $ZWRTAC var being generated for this $ZWR. If yes, generate * a $ZWRTAC="" line to preceed it. This will be a flag to load to clear out all existing $ZWRTAC * temp vars so there is no pollution between loads of ZWRitten data. */ if (0 == zwrtacindx++) { /* Put out "dummy" statement that will clear all the $ZWRTAC vars for a clean slate */ zwr_output->flush = TRUE; zshow_output(zwr_output, &dzwrtac_clean); } MEMCPY_LIT(zwrt_varname.c, DOLLAR_ZWRTAC); lastc = i2asc((uchar_ptr_t)zwrt_varname.c + STR_LIT_LEN(DOLLAR_ZWRTAC), zwrtacindx); newzav = als_getzavslot(); newzav->zwr_var.addr = zwrt_varname.c; newzav->zwr_var.len = INTCAST(((char *)lastc - &zwrt_varname.c[0])); s2pool(&newzav->zwr_var); htent_added = add_hashtab_addr(&zwrhtab->h_zwrtab, (char **)&lvpc, newzav, &tabent_addr); assert(htent_added); dump_container = TRUE; } /* Note value_printed flag in newzav not set since we are NOT dumping the value at this point * but only the association. Since the flag is not set, we *will* dump it when we get to that * actual variable. */ *one.addr = '*'; zshow_output(zwr_output, &one); lvzwr_out_targkey(&one); *one.addr = '='; zshow_output(zwr_output, &one); zwr_output->flush = TRUE; zshow_output(zwr_output, (const mstr *)&newzav->zwr_var); if (dump_container) { /* We want to dump the entire container variable but the name doesn't match the var we are * currently dumping so push a new lvzwrite_block onto the stack, fill it in for the current var * and call lvzwr_var() to handle it. When done, dismantle the temp lvzwrite_block. */ newzwrb = (lvzwrite_datablk *)malloc(SIZEOF(lvzwrite_datablk)); memset(newzwrb, 0, SIZEOF(lvzwrite_datablk)); newzwrb->sub = (zwr_sub_lst *)malloc(SIZEOF(zwr_sub_lst) * MAX_LVSUBSCRIPTS); newzwrb->curr_name = &newzav->zwr_var; newzwrb->prev = lvzwrite_block; lvzwrite_block = newzwrb; lvzwr_var(lvpc, 0); assert(newzav->value_printed); assert(newzwrb == lvzwrite_block); free(newzwrb->sub); lvzwrite_block = newzwrb->prev; free(newzwrb); } return; } else if (LV_IS_BASE_VAR(lvp) && IS_ALIASLV(lvp)) { /* Case 2 -- alias base variable (only base vars have reference counts). Note this can occur with * TP save/restore vars since we increment both trefcnt and crefcnt for these hidden copied references. * Because of that, we can't assert alias_activity but otherwise it shouldn't affect processing. */ if (!(htent_added = add_hashtab_addr(&zwrhtab->h_zwrtab, (char **)&lvp, NULL, &tabent_addr))) { /* Entry already existed -- need to output association rather than values */ assert(tabent_addr); zav = (zwr_alias_var *)tabent_addr->value; assert(zav); if (zav->value_printed) { /* Value has already been output -- print association this time */ *one.addr = '*'; /* Flag as creating an alias */ zshow_output(zwr_output, &one); /* Now for (new) variable name */ zshow_output(zwr_output, lvzwrite_block->curr_name); *one.addr = '='; zshow_output(zwr_output, &one); /* .. and the var name aliasing to (the first seen with this lv_val) */ assert(zav->zwr_var.len); zwr_output->flush = TRUE; zshow_output(zwr_output, &zav->zwr_var); return; } /* Else the value for this entry has not yet been printed so let us fall into case 3 * and get that done. Also set the flag so we mark it as an alias. Note this can happen if * a container value for a name is encountered before the base var it points to. We will * properly resolve the entry but its value won't have been printed until we actually encounter * it in the tree. */ htent_added = TRUE; /* to force the ;# tag at end of value printing */ zav->value_printed = TRUE; /* value will be output shortly below */ } else { /* Entry was added so is first appearance -- give it a value to hold onto and print it */ newzav = als_getzavslot(); newzav->zwr_var = *lvzwrite_block->curr_name; newzav->value_printed = TRUE; /* or rather it will be shortly.. */ tabent_addr->value = (void *)newzav; lvzwrite_block->zav_added = TRUE; /* Note fall into case 3 to print var and value if exists */ } } /* Case 3 - everything else */ if (!MV_DEFINED(val)) return; MV_FORCE_STR(val); lvzwr_out_targkey(&one); *one.addr = '='; zshow_output(zwr_output, &one); mval_write(zwr_output, val, !htent_added); if (htent_added) { /* output the ";#" tag to indicate this is an alias output */ zwr_output->flush = TRUE; zshow_output(zwr_output, &semi_star); } } else { /* MERGE assignment from local variable */ nsubs = lvzwrite_block->curr_subsc; if (MARG1_IS_GBL(merge_args)) { /* Target global var */ memcpy(gv_currkey->base, mglvnp->gblp[IND1]->s_gv_currkey->base, mglvnp->gblp[IND1]->s_gv_currkey->end + 1); gv_currkey->end = mglvnp->gblp[IND1]->s_gv_currkey->end; for (n = 0 ; n < nsubs; n++) { subscp = ((zwr_sub_lst *)lvzwrite_block->sub)->subsc_list[n].actual; MV_FORCE_STR(subscp); mval2subsc(subscp, gv_currkey); if (!subscp->str.len && (ALWAYS != gv_cur_region->null_subs)) sgnl_gvnulsubsc(); } MV_FORCE_STR(val); op_gvput(val); } else { /* Target local var - pre-process target in case is a container */ assert(MARG1_IS_LCL(merge_args)); dst_lv = mglvnp->lclp[IND1]; if (!LV_IS_BASE_VAR(dst_lv)) { LV_SBS_DEPTH(dst_lv, FALSE, sbs_depth); if (MAX_LVSUBSCRIPTS < (sbs_depth + nsubs)) rts_error(VARLSTCNT(3) ERR_MERGEINCOMPL, 0, ERR_MAXNRSUBSCRIPTS); } param_list.arg[0] = dst_lv; /* this is already protected from stp_gcol by op_merge so no need to * push this into the stack for stp_gcol protection. */ for (n = 0 ; n < nsubs; n++) { /* Note: no need to do push these mvals on the stack before calling op_putindx * as lvzwrite_block->sub is already protected by stp_gcol_src.h. */ param_list.arg[n+1] = ((zwr_sub_lst *)lvzwrite_block->sub)->subsc_list[n].actual; } param_list.n = n + 1; dst_lv = (lv_val *)callg((callgfnptr)op_putindx, ¶m_list); MV_FORCE_STR(val); DECR_AC_REF(dst_lv, TRUE); dst_lv->v = *val; dst_lv->v.mvtype &= ~MV_ALIASCONT; /* Make sure alias container property does not pass */ } } } fis-gtm-V6.0-003/sr_port/lvzwr_var.c0000644000032200000250000002675412201176160016244 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdio.h" #include "lv_val.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "zwrite.h" #include "mlkdef.h" #include "zshow.h" #include "collseq.h" #include "stringpool.h" #include "op.h" #include "outofband.h" #include "do_xform.h" #include "numcmp.h" #include "patcode.h" #include "mvalconv.h" #include "follow.h" #include "gtm_string.h" #include "alias.h" #include "promodemo.h" /* for "demote" prototype used in LV_NODE_GET_KEY */ #define eb_less(u, v) (numcmp(u, v) < 0) #define COMMON_STR_PROCESSING(NODE) \ { \ mstr key_mstr; \ mval tmp_sbs; \ \ assert(MV_STR & mv.mvtype); \ if (TREF(local_collseq)) \ { \ key_mstr = mv.str; \ mv.str.len = 0; /* protect from "stp_gcol", if zwr_sub->subsc_list[n].actual points to mv */ \ ALLOC_XFORM_BUFF(key_mstr.len); \ tmp_sbs.mvtype = MV_STR; \ tmp_sbs.str.len = TREF(max_lcl_coll_xform_bufsiz); \ assert(NULL != TREF(lcl_coll_xform_buff)); \ tmp_sbs.str.addr = TREF(lcl_coll_xform_buff); \ do_xform(TREF(local_collseq), XBACK, &key_mstr, &tmp_sbs.str, &length); \ tmp_sbs.str.len = length; \ s2pool(&(tmp_sbs.str)); \ mv.str = tmp_sbs.str; \ } \ do_lev = TRUE; \ if (n < lvzwrite_block->subsc_count) \ { \ if (zwr_sub->subsc_list[n].subsc_type == ZWRITE_PATTERN) \ { \ if (!do_pattern(&mv, zwr_sub->subsc_list[n].first)) \ do_lev = FALSE; \ } else if (zwr_sub->subsc_list[n].subsc_type != ZWRITE_ALL) \ { \ if (zwr_sub->subsc_list[n].first) \ { \ if (!MV_IS_CANONICAL(zwr_sub->subsc_list[n].first) && \ (!follow(&mv, zwr_sub->subsc_list[n].first) && \ (mv.str.len != zwr_sub->subsc_list[n].first->str.len || \ memcmp(mv.str.addr, zwr_sub->subsc_list[n].first->str.addr, \ mv.str.len)))) \ do_lev = FALSE; \ } \ if (do_lev && zwr_sub->subsc_list[n].second) \ { \ if (MV_IS_CANONICAL(zwr_sub->subsc_list[n].second) || \ (!follow(zwr_sub->subsc_list[n].second, &mv) && \ (mv.str.len != zwr_sub->subsc_list[n].second->str.len || \ memcmp(mv.str.addr, \ zwr_sub->subsc_list[n].second->str.addr, \ mv.str.len)))) \ do_lev = FALSE; \ } \ } \ } \ if (do_lev) \ lvzwr_var((lv_val *)NODE, n + 1); \ } #define COMMON_NUMERIC_PROCESSING(NODE) \ { \ do_lev = TRUE; \ if (n < lvzwrite_block->subsc_count) \ { \ if (zwr_sub->subsc_list[n].subsc_type == ZWRITE_PATTERN) \ { \ if (!do_pattern(&mv, zwr_sub->subsc_list[n].first)) \ do_lev = FALSE; \ } else if (zwr_sub->subsc_list[n].subsc_type != ZWRITE_ALL) \ { \ if (zwr_sub->subsc_list[n].first) \ { \ if (!MV_IS_CANONICAL(zwr_sub->subsc_list[n].first) \ || eb_less(&mv, zwr_sub->subsc_list[n].first)) \ do_lev = FALSE; \ } \ if (do_lev && zwr_sub->subsc_list[n].second) \ { \ if (MV_IS_CANONICAL(zwr_sub->subsc_list[n].second) \ && eb_less(zwr_sub->subsc_list[n].second, &mv)) \ do_lev = FALSE; \ } \ } \ } \ if (do_lev) \ lvzwr_var((lv_val *)NODE, n + 1); \ } GBLREF lvzwrite_datablk *lvzwrite_block; GBLREF int4 outofband; GBLREF zshow_out *zwr_output; GBLREF int merge_args; GBLREF zwr_hash_table *zwrhtab; /* How we track aliases during zwrites */ LITREF mval literal_null; error_def(ERR_UNDEF); /* lv subscript usage notes: * 1. The sub field in lvzwrite_datablk is an array allocated at MAX_LVSUBSCRIPTS. * 2. The subscripts that appear at any given time are those for the current node being processed. * 3. Nodes are setup by lvzwr_arg(). * * Example - take the following nodes: * A(1,1)=10 * A(1,2)=20 * * The simplified processing that occurs is as follows: * 1. lvzwr_fini() sets curr_name which is the base var name (A) * 2. First level lvzwr_var is called with level (aka n) == 0 * 3. Since A has no value, nothing is printed. Notices that there are children so lvzwr_arg() * is called recursively with level 1. * 4. Sets up the level 1 subscript (key = 1). * 5. Since A(1) has no value, nothing is printed. Notices that there are children so lvzwr_arg() * is called recursively withe level 2. * 6. Sets up the level 2 subscript (key = 1). * 7. A(1,1) does have a value so lvzwr_out() is called to print the current key (from these * subscripts) and its value. * 8. No more subscripts at this level so pops back to level 1. * 9. There is another child at this level so calls lvzwr_arg() recursively with level 2. * 10. Replaces the level 2 subscript with the new key value (key = 2). * 11. A(1,2) does have a value so lvzwr_out() is called to print the current key. * 12. no more children at any level so everything pops back. */ void lvzwr_var(lv_val *lv, int4 n) { mval mv; int length; lv_val *var; char *top; int4 i; boolean_t do_lev, verify_hash_add, htent_added, value_printed_pending; zwr_sub_lst *zwr_sub; ht_ent_addr *tabent_addr; zwr_alias_var *zav, *newzav; lvTree *lvt; lvTreeNode *node, *nullsubsnode, *parent; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(lvzwrite_block); if (lv == zwr_output->out_var.lv.child) return; if (outofband) { lvzwrite_block->curr_subsc = lvzwrite_block->subsc_count = 0; outofband_action(FALSE); } lvzwrite_block->curr_subsc = n; zwr_sub = (zwr_sub_lst *)lvzwrite_block->sub; zwr_sub->subsc_list[n].actual = (mval *)NULL; /* Before we process this var, there are some special cases to check for first when * this is a base var (0 == lvzwrite_block->subsc_count) and the var is an alias. * * 1. Check if we have seen it before (the lvval is in the zwr_alias_var hash table), then we * need to process this var with lvzwr_out NOW and we will only be processing the base * var, not any of the subscripts. This is because all those subscripts (and the value * of the base var itself) have been dealt with previously when we first saw this * lvval. So in that case, call lvzwr_out() to output the association after which we are * done with this var. * 2. If we haven't seen it before, set a flag so we verify if the base var gets processed by * lvzwr_out or not (i.e. whether it has a value and the "subscript" or lack there of is * either wildcarded or whatever so that it actually gets dumped by lvzwr_out (see conditions * below). If not, then *we* need to add the lvval to the hash table to signify we have seen * it before so the proper associations to this alias var can be printed at a later time * when/if they are encountered. */ verify_hash_add = FALSE; /* By default we don't need to verify add */ value_printed_pending = FALSE; /* Force the "value_printed" flag on if TRUE */ zav = NULL; if (!merge_args && LV_IS_BASE_VAR(lv) && IS_ALIASLV(lv)) { assert(0 == n); /* Verify base var lv_val */ if (tabent_addr = (ht_ent_addr *)lookup_hashtab_addr(&zwrhtab->h_zwrtab, (char **)&lv)) { /* We've seen it before but check if it was actually printed at that point */ zav = (zwr_alias_var *)tabent_addr->value; assert(zav); if (zav->value_printed) { lvzwr_out(lv); lvzwrite_block->curr_subsc = lvzwrite_block->subsc_count = 0; return; } else value_printed_pending = TRUE; /* We will set value_printed flag true later */ } else verify_hash_add = TRUE; } if ((0 == lvzwrite_block->subsc_count) && (0 == n)) zwr_sub->subsc_list[n].subsc_type = ZWRITE_ASTERISK; if (LV_IS_VAL_DEFINED(lv) && (!lvzwrite_block->subsc_count || ((0 == n) && ZWRITE_ASTERISK == zwr_sub->subsc_list[n].subsc_type) || ((0 != n) && !(lvzwrite_block->mask >> n)))) { /* Print value for *this* node */ lvzwr_out(lv); } if (verify_hash_add && !lvzwrite_block->zav_added) { /* lvzwr_out processing didn't add a zav for this var. Take care of that now so we * recognize it as a "dealt with" alias when/if it is encountered later. */ newzav = als_getzavslot(); newzav->zwr_var = *lvzwrite_block->curr_name; newzav->value_printed = TRUE; htent_added = add_hashtab_addr(&zwrhtab->h_zwrtab, (char **)&lv, newzav, &tabent_addr); assert(htent_added); } /* If we processed a base var above to print an alias association but it hadn't been printed yet, * we had to wait until after lvzwr_out() was called before we could set the flag that indicated * the printing had occurred. Do that now. Note that it is only when this flag is set we are * certain to have a good value in zav. */ if (value_printed_pending) { assert(zav); zav->value_printed = TRUE; } if (lvzwrite_block->subsc_count && (n >= lvzwrite_block->subsc_count) && (ZWRITE_ASTERISK != zwr_sub->subsc_list[lvzwrite_block->subsc_count - 1].subsc_type)) return; if (n < lvzwrite_block->subsc_count && ZWRITE_VAL == zwr_sub->subsc_list[n].subsc_type) { var = op_srchindx(VARLSTCNT(2) lv, zwr_sub->subsc_list[n].first); zwr_sub->subsc_list[n].actual = zwr_sub->subsc_list[n].first; if (var && (LV_IS_VAL_DEFINED(var) || n < lvzwrite_block->subsc_count -1)) { lvzwr_var(var, n + 1); zwr_sub->subsc_list[n].actual = (mval *)NULL; lvzwrite_block->curr_subsc = n; } else { if (lvzwrite_block->fixed) { unsigned char buff[512], *end; lvzwrite_block->curr_subsc++; end = lvzwr_key(buff, SIZEOF(buff)); zwr_sub->subsc_list[n].actual = (mval *)NULL; lvzwrite_block->curr_subsc = lvzwrite_block->subsc_count = 0; rts_error(VARLSTCNT(4) ERR_UNDEF, 2, end - buff, buff); } } } else if (lvt = LV_GET_CHILD(lv)) { /* If node has children, process them now */ zwr_sub->subsc_list[n].actual = &mv; /* In case of standard null collation, first process null subscript if it exists */ if (TREF(local_collseq_stdnull)) { nullsubsnode = lvAvlTreeLookupStr(lvt, (treeKeySubscr *)&literal_null, &parent); if (NULL != nullsubsnode) { assert(MVTYPE_IS_STRING(nullsubsnode->key_mvtype) && !nullsubsnode->key_len); /* Process null subscript first */ LV_STR_NODE_GET_KEY(nullsubsnode, &mv); /* Get node key into "mv" */ COMMON_STR_PROCESSING(nullsubsnode); } } else nullsubsnode = NULL; for (node = lvAvlTreeFirst(lvt); NULL != node; node = lvAvlTreeNext(node)) { if (node == nullsubsnode) { assert(TREF(local_collseq_stdnull)); continue; /* skip null subscript as it has already been processed */ } LV_NODE_GET_KEY(node, &mv); /* Get node key into "mv" depending on the structure type of "node" */ if (!MVTYPE_IS_STRING(mv.mvtype)) { /* "node" is of type "lvTreeNodeNum *" */ COMMON_NUMERIC_PROCESSING(node); } else { /* "node" is of type "lvTreeNode *" */ COMMON_STR_PROCESSING(node); } } zwr_sub->subsc_list[n].actual = (mval *)NULL; lvzwrite_block->curr_subsc = n; } } fis-gtm-V6.0-003/sr_port/m_break.c0000644000032200000250000000155112201176160015574 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Inforformation Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "cmd.h" int m_break(void) { DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if ((TK_SPACE != TREF(window_token)) && (TK_EOL != TREF(window_token))) if (!m_xecute()) return FALSE; newtriple(OC_BREAK); if (TREF(for_stack_ptr) == TADR(for_stack)) start_fetches (OC_FETCH); else start_for_fetches (); return TRUE; } fis-gtm-V6.0-003/sr_port/m_close.c0000644000032200000250000000350112201176160015612 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "io_params.h" #include "indir_enum.h" #include "advancewindow.h" #include "cmd.h" #include "deviceparameters.h" int m_close(void) { static readonly unsigned char empty_plist[1] = { iop_eol }; boolean_t inddevparms; int rval; oprtype devpopr, plist, sopr; triple *indref, *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; inddevparms = FALSE; if (EXPR_FAIL == (rval = expr(&sopr, MUMPS_STR))) /* NOTE assignment */ return FALSE; if (TK_COLON != TREF(window_token)) { /* Single parameter */ if (EXPR_INDR == rval) { /* Indirect entire parameter list */ make_commarg(&sopr, indir_close); return TRUE; } else /* default device parms */ plist = put_str((char *)empty_plist, SIZEOF(empty_plist)); } else { /* Have device parms. Determine type */ advancewindow(); if (TK_ATSIGN == TREF(window_token)) { /* Have indirect device parms */ if (!indirection(&devpopr)) return FALSE; indref = newtriple(OC_INDDEVPARMS); indref->operand[0] = devpopr; indref->operand[1] = put_ilit(IOP_CLOSE_OK); inddevparms = TRUE; } else { /* Process device parameters now */ if (!deviceparameters(&plist, IOP_CLOSE_OK)) return FALSE; } } ref = newtriple(OC_CLOSE); ref->operand[0] = sopr; ref->operand[1] = !inddevparms ? plist : put_tref(indref); return TRUE; } fis-gtm-V6.0-003/sr_port/m_do.c0000644000032200000250000001334212201176160015113 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "mdq.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "mmemory.h" #include "advancewindow.h" #include "cmd.h" GBLREF boolean_t run_time; error_def(ERR_ACTOFFSET); int m_do(void) { oprtype *cr; triple *calltrip, *labelref, *obp, *oldchain, *ref0, *ref1, *routineref, tmpchain, *triptr, *tripsize; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if ((TK_SPACE == TREF(window_token)) || (TK_EOL == TREF(window_token))) { if (!run_time) /* DO SP SP is a noop at run time */ { calltrip = newtriple(OC_CALLSP); calltrip->operand[0] = put_mnxl(); calltrip->operand[1] = put_ocnt(); } return TRUE; } else if (TK_AMPERSAND == TREF(window_token)) { if (!extern_func(0)) return FALSE; else return TRUE; } dqinit(&tmpchain, exorder); oldchain = setcurtchain(&tmpchain); calltrip = entryref(OC_CALL, OC_EXTCALL, (mint)indir_do, TRUE, FALSE, FALSE); setcurtchain(oldchain); if (!calltrip) return FALSE; if (TK_LPAREN == TREF(window_token)) { if (OC_CALL == calltrip->opcode) { assert(MLAB_REF == calltrip->operand[0].oprclass); calltrip->opcode = OC_EXCAL; ref0 = newtriple(OC_PARAMETER); calltrip->operand[1] = put_tref(ref0); ref0->operand[0] = put_tsiz(); /* parm to hold size of jump codegen */ tripsize = ref0->operand[0].oprval.tref; assert(OC_TRIPSIZE == tripsize->opcode); } else { if (OC_EXTCALL == calltrip->opcode) { assert(TRIP_REF == calltrip->operand[1].oprclass); if (OC_CDLIT == calltrip->operand[1].oprval.tref->opcode) assert(CDLT_REF == calltrip->operand[1].oprval.tref->operand[0].oprclass); else { assert(OC_LABADDR == calltrip->operand[1].oprval.tref->opcode); assert(TRIP_REF == calltrip->operand[1].oprval.tref->operand[1].oprclass); assert(OC_PARAMETER == calltrip->operand[1].oprval.tref->operand[1].oprval.tref->opcode); assert(TRIP_REF == calltrip->operand[1].oprval.tref->operand[1].oprval.tref->operand[0].oprclass); assert(OC_ILIT == calltrip->operand[1].oprval.tref->operand[1].oprval.tref-> operand[0].oprval.tref->opcode); assert(ILIT_REF == calltrip->operand[1].oprval.tref->operand[1].oprval.tref-> operand[0].oprval.tref->operand[0].oprclass); if (0 != calltrip->operand[1].oprval.tref->operand[1].oprval.tref-> operand[0].oprval.tref->operand[0].oprval.ilit) { stx_error(ERR_ACTOFFSET); return FALSE; } } } else /* DO _ @dlabel actuallist */ { assert(OC_COMMARG == calltrip->opcode); assert(TRIP_REF == calltrip->operand[1].oprclass); assert(OC_ILIT == calltrip->operand[1].oprval.tref->opcode); assert(ILIT_REF == calltrip->operand[1].oprval.tref->operand[0].oprclass); assert((mint)indir_do == calltrip->operand[1].oprval.tref->operand[0].oprval.ilit); assert(calltrip->exorder.fl == &tmpchain); routineref = maketriple(OC_CURRHD); labelref = maketriple(OC_LABADDR); ref0 = maketriple(OC_PARAMETER); dqins(calltrip->exorder.bl, exorder, routineref); dqins(calltrip->exorder.bl, exorder, labelref); dqins(calltrip->exorder.bl, exorder, ref0); labelref->operand[0] = calltrip->operand[0]; labelref->operand[1] = put_tref(ref0); ref0->operand[0] = calltrip->operand[1]; ref0->operand[0].oprval.tref->operand[0].oprval.ilit = 0; ref0->operand[1] = put_tref(routineref); calltrip->operand[0] = put_tref(routineref); calltrip->operand[1] = put_tref(labelref); } calltrip->opcode = OC_EXTEXCAL; ref0 = newtriple(OC_PARAMETER); ref0->operand[0] = calltrip->operand[1]; calltrip->operand[1] = put_tref(ref0); } if (!actuallist(&ref0->operand[1])) return FALSE; } else if (OC_CALL == calltrip->opcode) { calltrip->operand[1] = put_ocnt(); if (TREF(for_stack_ptr) != TADR(for_stack)) { if (TAREF1(for_temps, (TREF(for_stack_ptr) - TADR(for_stack)))) calltrip->opcode = OC_FORLCLDO; } } if (TK_COLON == TREF(window_token)) { advancewindow(); cr = (oprtype *)mcalloc(SIZEOF(oprtype)); if (!bool_expr(FALSE, cr)) return FALSE; if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(TREF(expr_start)); } obp = oldchain->exorder.bl; dqadd(obp, &tmpchain, exorder); /*this is a violation of info hiding*/ if (OC_EXCAL == calltrip->opcode) { triptr = newtriple(OC_JMP); triptr->operand[0] = put_mfun(&calltrip->operand[0].oprval.lab->mvname); calltrip->operand[0].oprclass = ILIT_REF; /* dummy placeholder */ tripsize->operand[0].oprval.tsize->ct = triptr; } if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { ref0 = newtriple(OC_JMP); ref1 = newtriple(OC_GVRECTARG); ref1->operand[0] = put_tref(TREF(expr_start)); *cr = put_tjmp(ref1); tnxtarg(&ref0->operand[0]); } else tnxtarg(cr); } else { obp = oldchain->exorder.bl; dqadd(obp, &tmpchain, exorder); /*this is a violation of info hiding*/ if (OC_EXCAL == calltrip->opcode) { triptr = newtriple(OC_JMP); triptr->operand[0] = put_mfun(&calltrip->operand[0].oprval.lab->mvname); calltrip->operand[0].oprclass = ILIT_REF; /* dummy placeholder */ tripsize->operand[0].oprval.tsize->ct = triptr; } } return TRUE; } fis-gtm-V6.0-003/sr_port/m_else.c0000644000032200000250000000207312201176160015440 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "mmemory.h" #include "cmd.h" error_def(ERR_SPOREOL); int m_else(void) { triple *jmpref, elsepos_in_chain; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; elsepos_in_chain = TREF(pos_in_chain); if (TK_EOL == TREF(window_token)) return TRUE; if (TK_SPACE != TREF(window_token)) { stx_error(ERR_SPOREOL); return FALSE; } jmpref = newtriple(OC_JMPTSET); FOR_END_OF_SCOPE(0, jmpref->operand[0]); if (!linetail()) { tnxtarg(&jmpref->operand[0]); TREF(pos_in_chain) = elsepos_in_chain; return FALSE; } else return TRUE; } fis-gtm-V6.0-003/sr_port/m_for.c0000644000032200000250000003160112201176160015275 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "mdq.h" #include "opcode.h" #include "toktyp.h" #include "mmemory.h" #include "advancewindow.h" #include "cmd.h" #include "lv_val.h" error_def(ERR_EQUAL); error_def(ERR_FOROFLOW); error_def(ERR_MAXFORARGS); error_def(ERR_SPOREOL); /* The following macro checks to see if the evaluation of control variable components has done * anything that might have expose us to a messed up the control variable context. We only * have a problem when the control variable is subscripted, because if an extrinsic rearranges * the array - a KILL will do it - the op_putindx we did initially might be pointing into * never-neverland and slamming a value into it would definately not be a healthly thing. * Without indirection we know at compile time whether or not the control variable is subscripted * but with indirection we only know at run-time; we tried some contortions to skip the refresh if * it's not needed but lost the battle with the compiler's tendency to lose reference with a scope * that's not short - OC_PASSTHRU is suppose to give it a clue but having two of those in a row * seems not to work. */ #define DEAL_WITH_DANGER(CNTRL_LVN, CNTL_VAR, VAL) \ { \ triple *REF; \ \ if (need_control_rfrsh) \ { \ REF = newtriple(OC_RFRSHLVN); \ REF->operand[0] = CNTRL_LVN; \ REF->operand[1] = put_ilit(OC_PUTINDX); \ CNTL_VAR = put_tref(REF); \ newtriple(OC_PASSTHRU)->operand[0] = CNTRL_LVN; \ newtriple(OC_PASSTHRU)->operand[0] = CNTL_VAR; /* warn off optimizer */ \ } \ REF = newtriple(OC_STO); \ REF->operand[0] = CNTL_VAR; \ REF->operand[1] = VAL; \ } /* the macro below pushes the compiler FOR stack - the FOR_POP is in compiler.h 'cause stx_error uses it * there are actually two stacks - one for code references and one for temps flags; the code reference * one, for_stack, uses for_stack_ptr; the for_temps doesn't have its own global index, but instead uses * a local variable calculated from the relationship between the for_stack and for_stack_ptr */ #define FOR_PUSH() \ { \ int Level; \ \ Level = ((++(TREF(for_stack_ptr))) - (oprtype **)TADR(for_stack)); \ if (MAX_FOR_STACK > Level) \ { \ assert(TREF(for_stack_ptr) > (oprtype **)TADR(for_stack)); \ *(TREF(for_stack_ptr)) = NULL; \ TAREF1(for_temps, Level) = TAREF1(for_temps, Level - 1); \ } else \ { \ --(TREF(for_stack_ptr)); \ stx_error(ERR_FOROFLOW, 1, (MAX_FOR_STACK - 1)); \ FOR_POP(BLOWN_FOR); \ return FALSE; \ } \ } /* the macro below tucks a code reference into the for_stack so a FOR that's done can move on correctly when skipped */ #define SAVE_FOR_OVER_ADDR() \ { \ assert(TREF(for_stack_ptr) >= (oprtype **)TADR(for_stack)); \ assert(TREF(for_stack_ptr) < (oprtype **)(TADR(for_stack) + (MAX_FOR_STACK * SIZEOF(oprtype **)))); \ if (NULL == *(TREF(for_stack_ptr))) \ *(TREF(for_stack_ptr)) = (oprtype *)mcalloc(SIZEOF(oprtype)); \ tnxtarg(*(TREF(for_stack_ptr))); \ } int m_for(void) { unsigned int arg_cnt, arg_index, for_stack_level; oprtype arg_eval_addr[MAX_FORARGS], increment[MAX_FORARGS], terminate[MAX_FORARGS], arg_next_addr, arg_value, dummy, control_variable, control_slot, v, *iteration_start_addr, iteration_start_addr_indr, *not_even_once_addr; triple *eval_next_addr[MAX_FORARGS], *control_ref, *forchk1opc, forpos_in_chain, *init_ref, *push, *ref, *s, *sav, *share, *step_ref, *term_ref, *var_ref; boolean_t need_control_rfrsh = FALSE; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; forpos_in_chain = TREF(pos_in_chain); FOR_PUSH(); if (TK_SPACE == TREF(window_token)) { /* "argumentless" form */ FOR_END_OF_SCOPE(1, dummy); ref = newtriple(OC_FORCHK1); if (!linetail()) { TREF(pos_in_chain) = forpos_in_chain; assert(TREF(source_error_found)); stx_error(TREF(source_error_found)); FOR_POP(BLOWN_FOR); return FALSE; } SAVE_FOR_OVER_ADDR(); /* stash address of next op in the for_stack array */ newtriple(OC_JMP)->operand[0] = put_tjmp(ref); /* transfer back to just before the begining of the body */ FOR_POP(GOOD_FOR); /* and pop the array */ return TRUE; } for_stack_level = (TREF(for_stack_ptr) - TADR(for_stack)); if (TK_ATSIGN == TREF(window_token)) { if (!indirection(&v)) { FOR_POP(BLOWN_FOR); return FALSE; } need_control_rfrsh = TRUE; push = newtriple(OC_GLVNSLOT); push->operand[0] = put_ilit(for_stack_level); control_slot = put_tref(push); sav = newtriple(OC_INDSAVLVN); sav->operand[0] = v; sav->operand[1] = control_slot; } else { DEBUG_ONLY(control_ref = (TREF(curtchain))->exorder.bl); if (!lvn(&control_variable, OC_SAVLVN, NULL)) { FOR_POP(BLOWN_FOR); return FALSE; } s = control_variable.oprval.tref; if (OC_SAVLVN == s->opcode) { /* Control variable has subscripts. If no subscripts, shouldn't need refreshing. */ need_control_rfrsh = TRUE; push = maketriple(OC_GLVNSLOT); push->operand[0] = put_ilit(for_stack_level); control_slot = put_tref(push); share = maketriple(OC_SHARESLOT); share->operand[0] = put_tref(push); share->operand[1] = put_ilit(OC_SAVLVN); dqins(s->exorder.bl, exorder, share); dqins(share->exorder.bl, exorder, push); } assert(OC_VAR == control_ref->exorder.fl->opcode); assert(MVAR_REF == control_ref->exorder.fl->operand[0].oprclass); } if (TK_EQUAL != TREF(window_token)) { stx_error(ERR_EQUAL); FOR_POP(BLOWN_FOR); return FALSE; } if (need_control_rfrsh) { ref = newtriple(OC_RFRSHLVN); ref->operand[0] = control_slot; ref->operand[1] = put_ilit(OC_PUTINDX); control_variable = put_tref(ref); TAREF1(for_temps, for_stack_level) = TRUE; newtriple(OC_PASSTHRU)->operand[0] = control_slot; } newtriple(OC_PASSTHRU)->operand[0] = control_variable; /* make sure optimizer doesn't ditch control_variable */ FOR_END_OF_SCOPE(1, dummy); assert((0 < for_stack_level) && (MAX_FOR_STACK >= for_stack_level)); iteration_start_addr = (oprtype *)mcalloc(SIZEOF(oprtype)); iteration_start_addr_indr = put_indr(iteration_start_addr); arg_next_addr.oprclass = NO_REF; not_even_once_addr = NULL; /* used to skip processing where the initial control exceeds the termination */ for (arg_cnt = 0; ; ++arg_cnt) { if (MAX_FORARGS <= arg_cnt) { stx_error(ERR_MAXFORARGS); FOR_POP(BLOWN_FOR); return FALSE; } assert((TK_COMMA == TREF(window_token)) || (TK_EQUAL == TREF(window_token))); advancewindow(); tnxtarg(&arg_eval_addr[arg_cnt]); /* put location of this arg eval in arg_eval_addr array */ if (NULL != not_even_once_addr) { *not_even_once_addr = arg_eval_addr[arg_cnt]; not_even_once_addr = NULL; } if (EXPR_FAIL == expr(&arg_value, MUMPS_EXPR)) /* starting (possibly only) value */ { FOR_POP(BLOWN_FOR); return FALSE; } assert(TRIP_REF == arg_value.oprclass); if (TK_COLON != TREF(window_token)) { /* list point value? */ increment[arg_cnt].oprclass = terminate[arg_cnt].oprclass = NO_REF; DEAL_WITH_DANGER(control_slot, control_variable, arg_value); } else { /* stepping value */ init_ref = newtriple(OC_STOTEMP); /* tuck it in a temp undisturbed by coming evals */ init_ref->operand[0] = arg_value; newtriple(OC_CONUM)->operand[0] = put_tref(init_ref); /* make start numeric */ advancewindow(); /* past the first colon */ var_ref = (TREF(curtchain))->exorder.bl; if (EXPR_FAIL == expr(&increment[arg_cnt], MUMPS_EXPR)) /* pick up step */ { FOR_POP(BLOWN_FOR); return FALSE; } assert(TRIP_REF == increment[arg_cnt].oprclass); ref = increment[arg_cnt].oprval.tref; if (OC_LIT != var_ref->exorder.fl->opcode) { TAREF1(for_temps, for_stack_level) = TRUE; if (OC_VAR == var_ref->exorder.fl->opcode) { /* The above relies on lvn() always generating an OC_VAR triple first - asserted earlier */ step_ref = newtriple(OC_STOTEMP); step_ref->operand[0] = put_tref(ref); increment[arg_cnt] = put_tref(step_ref); } } if (TK_COLON != TREF(window_token)) { DEAL_WITH_DANGER(control_slot, control_variable, put_tref(init_ref)); terminate[arg_cnt].oprclass = NO_REF; /* no termination on iteration for this arg */ } else { advancewindow(); /* past the second colon */ var_ref = (TREF(curtchain))->exorder.bl; if (EXPR_FAIL == expr(&terminate[arg_cnt], MUMPS_EXPR)) /* termination control value */ { FOR_POP(BLOWN_FOR); return FALSE; } assert(TRIP_REF == terminate[arg_cnt].oprclass); ref = terminate[arg_cnt].oprval.tref; if (OC_LIT != ref->opcode) { TAREF1(for_temps, for_stack_level) = TRUE; if (OC_VAR == var_ref->exorder.fl->opcode) { /* The above relies on lvn() always generating an OC_VAR triple first */ term_ref = newtriple(OC_STOTEMP); term_ref->operand[0] = put_tref(ref); terminate[arg_cnt] = put_tref(term_ref); } } DEAL_WITH_DANGER(control_slot, control_variable, put_tref(init_ref)); term_ref = newtriple(OC_PARAMETER); term_ref->operand[0] = terminate[arg_cnt]; step_ref = newtriple(OC_PARAMETER); step_ref->operand[0] = increment[arg_cnt]; step_ref->operand[1] = put_tref(term_ref); ref = newtriple(OC_FORINIT); ref->operand[0] = control_variable; ref->operand[1] = put_tref(step_ref); not_even_once_addr = newtriple(OC_JMPGTR)->operand; } } if ((0 < arg_cnt) || (TK_COMMA == TREF(window_token))) { TAREF1(for_temps, for_stack_level) = TRUE; if (NO_REF == arg_next_addr.oprclass) arg_next_addr = put_tref(newtriple(OC_CDADDR)); (eval_next_addr[arg_cnt] = newtriple(OC_LDADDR))->destination = arg_next_addr; } if (TK_COMMA != TREF(window_token)) break; newtriple(OC_JMP)->operand[0] = iteration_start_addr_indr; } forchk1opc = newtriple(OC_FORCHK1); /* FORCHK1 is a do-nothing routine used by the out-of-band mechanism */ *iteration_start_addr = put_tjmp(forchk1opc); if ((TK_EOL != TREF(window_token)) && (TK_SPACE != TREF(window_token))) { stx_error(ERR_SPOREOL); FOR_POP(BLOWN_FOR); return FALSE; } if (!linetail()) { TREF(pos_in_chain) = forpos_in_chain; assert(TREF(source_error_found)); stx_error(TREF(source_error_found)); FOR_POP(BLOWN_FOR); return FALSE; } if (not_even_once_addr) /* if above errors leave FOR remains behind, improper operval.indr explodes OC_JMPGTR */ FOR_END_OF_SCOPE(1, *not_even_once_addr); /* 1 means down a level */ SAVE_FOR_OVER_ADDR(); /* stash address of next op in the for_stack array */ if (0 < arg_cnt) newtriple(OC_JMPAT)->operand[0] = put_tref(eval_next_addr[0]); for (arg_index = 0; arg_index <= arg_cnt; ++arg_index) { if (0 < arg_cnt) tnxtarg(eval_next_addr[arg_index]->operand); if (need_control_rfrsh) { /* since it might have moved, before touching the control variable get a fix on it */ ref = newtriple(OC_RFRSHLVN); ref->operand[0] = control_slot; if (increment[arg_index].oprclass || terminate[arg_index].oprclass) ref->operand[1] = put_ilit(OC_SRCHINDX); else /* if increment rather than new value, rfrsh w/ srchindx else putindx */ ref->operand[1] = put_ilit(OC_PUTINDX); newtriple(OC_PASSTHRU)->operand[0] = control_slot; control_variable = put_tref(ref); } newtriple(OC_PASSTHRU)->operand[0] = control_variable; /* warn off optimizer */ if (terminate[arg_index].oprclass) { term_ref = newtriple(OC_PARAMETER); term_ref->operand[0] = terminate[arg_index]; step_ref = newtriple(OC_PARAMETER); step_ref->operand[0] = increment[arg_index]; step_ref->operand[1] = put_tref(term_ref); init_ref = newtriple(OC_PARAMETER); init_ref->operand[0] = control_variable; init_ref->operand[1] = put_tref(step_ref); ref = newtriple(OC_FORLOOP); /* redirects back to forchk1, which is at the beginning of new iteration */ ref->operand[0] = *iteration_start_addr; ref->operand[1] = put_tref(init_ref); } else if (increment[arg_index].oprclass) { step_ref = newtriple(OC_ADD); step_ref->operand[0] = control_variable; step_ref->operand[1] = increment[arg_index]; ref = newtriple(OC_STO); ref->operand[0] = control_variable; ref->operand[1] = put_tref(step_ref); newtriple(OC_JMP)->operand[0] = *iteration_start_addr; } if (arg_index < arg_cnt) /* go back and evaluate the next argument */ newtriple(OC_JMP)->operand[0] = arg_eval_addr[arg_index + 1]; } FOR_POP(GOOD_FOR); return TRUE; } fis-gtm-V6.0-003/sr_port/m_goto.c0000644000032200000250000000351312201176160015460 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "mdq.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "mmemory.h" #include "advancewindow.h" #include "cmd.h" int m_goto(void) { oprtype *cr; triple *obp, *oldchain, *ref0, *ref1, tmpchain, *triptr; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; dqinit(&tmpchain, exorder); oldchain = setcurtchain(&tmpchain); if (!entryref(OC_JMP, OC_EXTJMP, (mint)indir_goto, TRUE, FALSE, FALSE)) { setcurtchain(oldchain); return FALSE; } setcurtchain(oldchain); if (TK_COLON == TREF(window_token)) { advancewindow(); cr = (oprtype *)mcalloc(SIZEOF(oprtype)); if (!bool_expr(FALSE, cr)) return FALSE; if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(TREF(expr_start)); } obp = oldchain->exorder.bl; dqadd(obp, &tmpchain, exorder); /*this is a violation of info hiding*/ if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { ref0 = newtriple(OC_JMP); ref1 = newtriple(OC_GVRECTARG); ref1->operand[0] = put_tref(TREF(expr_start)); *cr = put_tjmp(ref1); tnxtarg(&ref0->operand[0]); } else tnxtarg(cr); return TRUE; } obp = oldchain->exorder.bl; dqadd(obp, &tmpchain, exorder); /*this is a violation of info hiding*/ return TRUE; } fis-gtm-V6.0-003/sr_port/m_halt.c0000644000032200000250000000115012201176160015433 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "cmd.h" int m_halt(void) { oprtype x; newtriple(OC_HALT); return TRUE; } fis-gtm-V6.0-003/sr_port/m_hang.c0000644000032200000250000000175512201176160015433 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "cmd.h" int m_hang(void) { oprtype ot; triple *triptr; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; switch (expr(&ot, MUMPS_NUM)) { case EXPR_FAIL: return FALSE; case EXPR_GOOD: triptr = newtriple(OC_HANG); triptr->operand[0] = ot; return TRUE; case EXPR_INDR: make_commarg(&ot, indir_hang); return TRUE; default: GTMASSERT; } return FALSE; /* This should never get executed, added to make compiler happy */ } fis-gtm-V6.0-003/sr_port/m_hcmd.c0000644000032200000250000000133312201176160015421 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "cmd.h" int m_hcmd(void) { DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if ((TK_SPACE == TREF(window_token)) || (TK_EOL == TREF(window_token))) return m_halt(); return m_hang(); } fis-gtm-V6.0-003/sr_port/m_if.c0000644000032200000250000000753412201176160015115 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "mdq.h" #include "mmemory.h" #include "advancewindow.h" #include "cmd.h" #include "fullbool.h" error_def(ERR_INDEXTRACHARS); error_def(ERR_SPOREOL); typedef struct jmpchntype { struct { struct jmpchntype *fl,*bl; } link; triple *jmptrip; } jmpchn; int m_if(void) { triple *ref0, *ref1, *ref2, *jmpref, ifpos_in_chain, *triptr; oprtype x, y, *ta_opr; boolean_t first_time, t_set, is_commarg; jmpchn *jmpchain, *nxtjmp; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; ifpos_in_chain = TREF(pos_in_chain); jmpchain = (jmpchn *)mcalloc(SIZEOF(jmpchn)); dqinit(jmpchain, link); if (TK_EOL == TREF(window_token)) return TRUE; is_commarg = (1 == TREF(last_source_column)); FOR_END_OF_SCOPE(0, x); assert(INDR_REF == x.oprclass); if (TK_SPACE == TREF(window_token)) { jmpref = newtriple(OC_JMPTCLR); jmpref->operand[0] = x; nxtjmp = (jmpchn *)mcalloc(SIZEOF(jmpchn)); nxtjmp->jmptrip = jmpref; dqins(jmpchain, link, nxtjmp); } else { first_time = TRUE; for (;;) { ta_opr = (oprtype *)mcalloc(SIZEOF(oprtype)); if (!bool_expr(TRUE, ta_opr)) return FALSE; if (((OC_JMPNEQ == (ref0 = (TREF(curtchain))->exorder.bl)->opcode)) && (OC_COBOOL == (ref1 = ref0->exorder.bl)->opcode) && (OC_INDGLVN == (ref2 = ref1->exorder.bl)->opcode)) { /* short-circuit only optimization that turns a trailing INDGLVN COBOOL into separate indirect IF */ dqdel(ref0, exorder); ref1->opcode = OC_JMPTSET; ref1->operand[0] = put_indr(ta_opr); ref2->opcode = OC_COMMARG; ref2->operand[1] = put_ilit((mint)indir_if); } t_set = (OC_JMPTSET == (TREF(curtchain))->exorder.bl->opcode); if (!t_set) newtriple(OC_CLRTEST); if (TREF(expr_start) != TREF(expr_start_orig) && (OC_NOOP != (TREF(expr_start))->opcode)) { assert((OC_GVSAVTARG == (TREF(expr_start))->opcode)); if ((OC_GVRECTARG != (TREF(curtchain))->exorder.bl->opcode) || ((TREF(curtchain))->exorder.bl->operand[0].oprval.tref != TREF(expr_start))) newtriple(OC_GVRECTARG)->operand[0] = put_tref(TREF(expr_start)); } jmpref = newtriple(OC_JMP); jmpref->operand[0] = x; nxtjmp = (jmpchn *)mcalloc(SIZEOF(jmpchn)); nxtjmp->jmptrip = jmpref; dqins(jmpchain, link, nxtjmp); tnxtarg(ta_opr); if (first_time) { if (!t_set) newtriple(OC_SETTEST); if (TREF(expr_start) != TREF(expr_start_orig) && (OC_NOOP != (TREF(expr_start))->opcode)) { assert((OC_GVSAVTARG == (TREF(expr_start))->opcode)); if ((OC_GVRECTARG != (TREF(curtchain))->exorder.bl->opcode) || ((TREF(curtchain))->exorder.bl->operand[0].oprval.tref != TREF(expr_start))) newtriple(OC_GVRECTARG)->operand[0] = put_tref(TREF(expr_start)); } first_time = FALSE; } if (TK_COMMA != TREF(window_token)) break; advancewindow(); } } if (is_commarg) { while (TK_SPACE == TREF(window_token)) /* Eat up trailing white space */ advancewindow(); if (TK_EOL != TREF(window_token)) { stx_error(ERR_INDEXTRACHARS); return FALSE; } return TRUE; } if ((TK_EOL != TREF(window_token)) && (TK_SPACE != TREF(window_token))) { stx_error(ERR_SPOREOL); return FALSE; } if (!linetail()) { tnxtarg(&x); dqloop(jmpchain,link,nxtjmp) { ref1 = nxtjmp->jmptrip; ref1->operand[0] = x; } TREF(pos_in_chain) = ifpos_in_chain; return FALSE; } return TRUE; } fis-gtm-V6.0-003/sr_port/m_job.c0000644000032200000250000000762512201176160015272 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "iotimer.h" #include "job.h" #include "advancewindow.h" #include "cmd.h" GBLREF boolean_t run_time; GBLREF mident routine_name; LITREF mident zero_ident; error_def(ERR_COMMAORRPAREXP); error_def(ERR_JOBACTREF); error_def(ERR_MAXACTARG); error_def(ERR_RTNNAME); int m_job(void) { boolean_t is_timeout, dummybool; static readonly unsigned char empty_plist[1] = { jp_eol }; int argcnt; oprtype arglst, *argptr, argval, label, offset, routine, plist, timeout; triple *next, *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; label = put_str(zero_ident.addr, zero_ident.len); offset = put_ilit((mint)0); if (!lref(&label, &offset, FALSE, indir_job, TRUE, &dummybool)) return FALSE; if ((TRIP_REF == label.oprclass) && (OC_COMMARG == label.oprval.tref->opcode)) return TRUE; if (TK_CIRCUMFLEX != TREF(window_token)) { if (!run_time) routine = put_str(routine_name.addr, routine_name.len); else routine = put_tref(newtriple(OC_CURRTN)); } else { advancewindow(); switch (TREF(window_token)) { case TK_IDENT: routine = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); advancewindow(); break; case TK_ATSIGN: if (!indirection(&routine)) return FALSE; break; default: stx_error(ERR_RTNNAME); return FALSE; } } argcnt = 0; if (TK_LPAREN == TREF(window_token)) { advancewindow(); argptr = &arglst; while (TK_RPAREN != TREF(window_token)) { if (MAX_ACTUALS < argcnt) { stx_error(ERR_MAXACTARG); return FALSE; } if (TK_PERIOD == TREF(window_token)) { stx_error(ERR_JOBACTREF); return FALSE; } if (TK_COMMA == TREF(window_token)) { ref = newtriple(OC_NULLEXP); argval = put_tref(ref); } else if (EXPR_FAIL == expr(&argval, MUMPS_EXPR)) return FALSE; ref = newtriple(OC_PARAMETER); ref->operand[0] = argval; *argptr = put_tref(ref); argptr = &ref->operand[1]; argcnt++; if (TK_COMMA == TREF(window_token)) advancewindow(); else if (TK_RPAREN != TREF(window_token)) { stx_error(ERR_COMMAORRPAREXP); return FALSE; } } advancewindow(); /* jump over close paren */ } if (TK_COLON == TREF(window_token)) { advancewindow(); if (TK_COLON == TREF(window_token)) { is_timeout = TRUE; plist = put_str((char *)empty_plist,SIZEOF(empty_plist)); } else { if (!jobparameters(&plist)) return FALSE; is_timeout = (TK_COLON == TREF(window_token)); } if (is_timeout) { advancewindow(); if (EXPR_FAIL == expr(&timeout, MUMPS_INT)) return FALSE; } else timeout = put_ilit(NO_M_TIMEOUT); } else { is_timeout = FALSE; plist = put_str((char *)empty_plist,SIZEOF(empty_plist)); timeout = put_ilit(NO_M_TIMEOUT); } ref = newtriple(OC_JOB); ref->operand[0] = put_ilit(argcnt + 5); /* parameter list + five fixed arguments */ next = newtriple(OC_PARAMETER); ref->operand[1] = put_tref(next); next->operand[0] = label; ref = newtriple(OC_PARAMETER); next->operand[1] = put_tref(ref); ref->operand[0] = offset; next = newtriple(OC_PARAMETER); ref->operand[1] = put_tref(next); next->operand[0] = routine; ref = newtriple(OC_PARAMETER); next->operand[1] = put_tref(ref); ref->operand[0] = plist; next = newtriple(OC_PARAMETER); ref->operand[1] = put_tref(next); next->operand[0] = timeout; if (argcnt) next->operand[1] = arglst; if (is_timeout) newtriple(OC_TIMTRU); return TRUE; } fis-gtm-V6.0-003/sr_port/m_kill.c0000644000032200000250000000650112201176160015443 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "mdq.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "advancewindow.h" #include "cmd.h" error_def(ERR_ALIASEXPECTED); error_def(ERR_NOALIASLIST); error_def(ERR_RPARENMISSING); error_def(ERR_VAREXPECTED); int m_kill(void) { boolean_t alias_processing; int count; mvar *mvarptr; oprtype tmparg; triple *next, *org, *ref, *s; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (alias_processing = (TK_ASTERISK == TREF(window_token))) /* NOTE assignment */ advancewindow(); switch (TREF(window_token)) { case TK_IDENT: /* If doing alias processing, we need to pass the index of the var rather than its lv_val but do the common case first. Note that a kill of an alias container is handled the same as the kill of any other regular local variable. */ if (!alias_processing || (TK_LPAREN == TREF(director_token))) { if (!lvn(&tmparg,OC_SRCHINDX,0)) return FALSE; ref = newtriple(OC_KILL); ref->operand[0] = tmparg; } else { /* alias (unsubscripted var) kill */ ref = newtriple(OC_KILLALIAS); mvarptr = get_mvaddr(&(TREF(window_ident))); ref->operand[0] = put_ilit(mvarptr->mvidx); advancewindow(); } break; case TK_CIRCUMFLEX: if (alias_processing) { stx_error(ERR_ALIASEXPECTED); return FALSE; } if (!gvn()) return FALSE; ref = newtriple(OC_GVKILL); break; case TK_ATSIGN: if (alias_processing) { stx_error(ERR_ALIASEXPECTED); return FALSE; } if (!indirection(&tmparg)) return FALSE; ref = maketriple(OC_COMMARG); ref->operand[0] = tmparg; ref->operand[1] = put_ilit((mint)indir_kill); ins_triple(ref); return TRUE; case TK_EOL: case TK_SPACE: newtriple(alias_processing ? OC_KILLALIASALL : OC_KILLALL); break; case TK_LPAREN: if (alias_processing) { stx_error(ERR_NOALIASLIST); return FALSE; } ref = org = maketriple(OC_XKILL); count = 0; do { advancewindow(); next = maketriple(OC_PARAMETER); ref->operand[1] = put_tref(next); switch (TREF(window_token)) { case TK_IDENT: next->operand[0] = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); advancewindow(); break; case TK_ATSIGN: if (!indirection(&tmparg)) return FALSE; s = newtriple(OC_INDLVARG); s->operand[0] = tmparg; next->operand[0] = put_tref(s); break; case TK_ASTERISK: stx_error(ERR_NOALIASLIST); return FALSE; default: stx_error(ERR_VAREXPECTED); return FALSE; } ins_triple(next); ref = next; count++; } while (TK_COMMA == TREF(window_token)); if (TK_RPAREN != TREF(window_token)) { stx_error(ERR_RPARENMISSING); return FALSE; } advancewindow(); org->operand[0] = put_ilit((mint)count); ins_triple(org); return TRUE; default: stx_error(alias_processing ? ERR_ALIASEXPECTED : ERR_VAREXPECTED); return FALSE; } return TRUE; } fis-gtm-V6.0-003/sr_port/m_lock.c0000644000032200000250000000435712201176160015447 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "iotimer.h" #include "indir_enum.h" #include "advancewindow.h" #include "cmd.h" error_def(ERR_RPARENMISSING); int m_lock(void) { boolean_t indirect; opctype ox; oprtype indopr; triple *ref, *restart; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; restart = newtriple(OC_RESTARTPC); newtriple(OC_LKINIT); indirect = FALSE; switch (TREF(window_token)) { case TK_MINUS: advancewindow(); ox = OC_LCKDECR; break; case TK_PLUS: advancewindow(); ox = OC_LCKINCR; break; case TK_EOL: case TK_SPACE: ox = OC_UNLOCK; restart->opcode = OC_NOOP; newtriple(OC_UNLOCK); return TRUE; break; case TK_ATSIGN: if (!indirection(&indopr)) return FALSE; ref = maketriple(OC_COMMARG); ref->operand[0] = indopr; if (TK_COLON != TREF(window_token)) { ref->operand[1] = put_ilit((mint) indir_lock); ins_triple(ref); return TRUE; } ref->operand[1] = put_ilit((mint) indir_nref); indirect = TRUE; /*** CAUTION: FALL-THROUGH ***/ default: newtriple(OC_UNLOCK); ox = OC_LOCK; } if (indirect) ins_triple(ref); else { switch (TREF(window_token)) { case TK_LPAREN: do { advancewindow(); if (nref() == EXPR_FAIL) return FALSE; } while (TK_COMMA == TREF(window_token)); if (TK_RPAREN != TREF(window_token)) { stx_error(ERR_RPARENMISSING); return FALSE; } advancewindow(); break; default: if (nref() == EXPR_FAIL) return FALSE; break; } } ref = maketriple(ox); if (TK_COLON != TREF(window_token)) { ref->operand[0] = put_ilit(NO_M_TIMEOUT); ins_triple(ref); } else { advancewindow(); if (EXPR_FAIL == expr(&(ref->operand[0]), MUMPS_INT)) return FALSE; ins_triple(ref); newtriple(OC_TIMTRU); } return TRUE; } fis-gtm-V6.0-003/sr_port/m_merge.c0000644000032200000250000001105312201176160015605 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "mdq.h" #include "opcode.h" #include "indir_enum.h" #include "nametabtyp.h" #include "toktyp.h" #include "merge_def.h" #include "cmd.h" #include "mvalconv.h" #include "advancewindow.h" #include "glvn_pool.h" error_def(ERR_EQUAL); error_def(ERR_RPARENMISSING); error_def(ERR_VAREXPECTED); int m_merge(void) { int type; boolean_t used_glvn_slot; mval mv; opctype put_oc; oprtype mopr, control_slot; triple *obp, *ref, *restart, *s1, *sub, tmpchain; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; used_glvn_slot = FALSE; sub = NULL; restart = newtriple(OC_RESTARTPC); /* Here is where a restart should pick up */ dqinit(&tmpchain, exorder); /* Left Hand Side of EQUAL sign */ switch (TREF(window_token)) { case TK_IDENT: if (!lvn(&mopr, OC_PUTINDX, 0)) return FALSE; if (OC_PUTINDX == mopr.oprval.tref->opcode) { /* we insert left hand side argument into tmpchain. */ sub = mopr.oprval.tref; put_oc = OC_PUTINDX; dqdel(mopr.oprval.tref, exorder); dqins(tmpchain.exorder.bl, exorder, mopr.oprval.tref); } ref = maketriple(OC_MERGE_LVARG); ref->operand[0] = put_ilit(MARG1_LCL); ref->operand[1] = mopr; dqins(tmpchain.exorder.bl, exorder, ref); break; case TK_CIRCUMFLEX: s1 = (TREF(curtchain))->exorder.bl; if (!gvn()) return FALSE; for (sub = (TREF(curtchain))->exorder.bl; sub != s1; sub = sub->exorder.bl) { put_oc = sub->opcode; if (OC_GVNAME == put_oc || OC_GVNAKED == put_oc || OC_GVEXTNAM == put_oc) break; } assert((OC_GVNAME == put_oc) || (OC_GVNAKED == put_oc) || (OC_GVEXTNAM == put_oc)); /* we insert left hand side argument into tmpchain. */ dqdel(sub, exorder); dqins(tmpchain.exorder.bl ,exorder, sub); ref = maketriple(OC_MERGE_GVARG); ref->operand[0] = put_ilit(MARG1_GBL); dqins(tmpchain.exorder.bl, exorder, ref); break; case TK_ATSIGN: if (!indirection(&mopr)) return FALSE; if (TK_EQUAL != TREF(window_token)) { ref = newtriple(OC_COMMARG); ref->operand[0] = mopr; ref->operand[1] = put_ilit((mint) indir_merge); return TRUE; } type = MARG1_LCL | MARG1_GBL; MV_FORCE_MVAL(&mv, type); MV_FORCE_STRD(&mv); if (TREF(side_effect_handling)) { /* save and restore the variable lookup for true left-to-right evaluation */ used_glvn_slot = TRUE; INSERT_INDSAVGLVN(control_slot, mopr, ANY_SLOT, 0); /* 0 flag to defer global reference */ ref = maketriple(OC_INDMERGE2); ref->operand[0] = control_slot; } else { /* quick and dirty old way */ ref = maketriple(OC_INDMERGE); ref->operand[0] = put_lit(&mv); ref->operand[1] = mopr; } /* we insert left hand side argument into tmpchain. */ dqins(tmpchain.exorder.bl, exorder, ref); break; default: stx_error(ERR_VAREXPECTED); return FALSE; } if (TREF(window_token) != TK_EQUAL) { stx_error(ERR_EQUAL); return FALSE; } advancewindow(); /* Right Hand Side of EQUAL sign */ TREF(temp_subs) = FALSE; switch (TREF(window_token)) { case TK_IDENT: if (!lvn(&mopr, OC_M_SRCHINDX, 0)) return FALSE; ref = newtriple(OC_MERGE_LVARG); ref->operand[0] = put_ilit(MARG2_LCL); ref->operand[1] = mopr; break; case TK_CIRCUMFLEX: if (!gvn()) return FALSE; ref = newtriple(OC_MERGE_GVARG); ref->operand[0] = put_ilit(MARG2_GBL); break; case TK_ATSIGN: TREF(temp_subs) = TRUE; if (!indirection(&mopr)) { stx_error(ERR_VAREXPECTED); return FALSE; } type = MARG2_LCL | MARG2_GBL; MV_FORCE_MVAL(&mv, type); MV_FORCE_STRD(&mv); ref = maketriple(OC_INDMERGE); ref->operand[0] = put_lit(&mv); ref->operand[1] = mopr; ins_triple(ref); break; default: stx_error(ERR_VAREXPECTED); return FALSE; } /* * Make sure that during runtime right hand side argument is processed first. * This is specially important if global naked variable is used . */ obp = (TREF(curtchain))->exorder.bl; dqadd(obp, &tmpchain, exorder); if (TREF(temp_subs) && TREF(side_effect_handling) && sub) create_temporaries(sub, put_oc); TREF(temp_subs) = FALSE; if (used_glvn_slot) { ref = newtriple(OC_GLVNPOP); ref->operand[0] = control_slot; } ref = newtriple(OC_MERGE); return TRUE; } fis-gtm-V6.0-003/sr_port/m_new.c0000644000032200000250000001026312201176160015301 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "mdq.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "svnames.h" #include "nametabtyp.h" #include "funsvn.h" #include "advancewindow.h" #include "cmd.h" #include "namelook.h" GBLREF triple *curr_fetch_trip, *curr_fetch_opr; GBLREF int4 curr_fetch_count; LITREF unsigned char svn_index[]; LITREF nametabent svn_names[]; LITREF svn_data_type svn_data[]; error_def(ERR_INVSVN); error_def(ERR_RPARENMISSING); error_def(ERR_SVNEXPECTED); error_def(ERR_SVNONEW); error_def(ERR_VAREXPECTED); int m_new(void) { oprtype tmparg; triple *ref, *next, *org, *tmp, *s, *fetch; int n; int count; mvar *var; boolean_t parse_warn; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; switch (TREF(window_token)) { case TK_IDENT: var = get_mvaddr(&(TREF(window_ident))); if (var->last_fetch != curr_fetch_trip) { fetch = newtriple(OC_PARAMETER); curr_fetch_opr->operand[1] = put_tref(fetch); fetch->operand[0] = put_ilit(var->mvidx); curr_fetch_count++; curr_fetch_opr = fetch; var->last_fetch = curr_fetch_trip; } tmp = maketriple(OC_NEWVAR); tmp->operand[0] = put_ilit(var->mvidx); ins_triple(tmp); advancewindow(); return TRUE; case TK_ATSIGN: if (!indirection(&tmparg)) return FALSE; ref = maketriple(OC_COMMARG); ref->operand[0] = tmparg; ref->operand[1] = put_ilit((mint) indir_new); ins_triple(ref); start_fetches(OC_FETCH); return TRUE; case TK_DOLLAR: advancewindow(); if (TK_IDENT == TREF(window_token)) { parse_warn = FALSE; if ((0 <= (n = namelook(svn_index, svn_names, (TREF(window_ident)).addr, (TREF(window_ident)).len)))) { /* NOTE assignment above */ switch (svn_data[n].opcode) { case SV_ZTRAP: case SV_ETRAP: case SV_ESTACK: case SV_ZYERROR: case SV_ZGBLDIR: GTMTRIG_ONLY(case SV_ZTWORMHOLE:) tmp = maketriple(OC_NEWINTRINSIC); tmp->operand[0] = put_ilit(svn_data[n].opcode); break; default: STX_ERROR_WARN(ERR_SVNONEW); /* sets "parse_warn" to TRUE */ } } else { STX_ERROR_WARN(ERR_INVSVN); /* sets "parse_warn" to TRUE */ } advancewindow(); if (!parse_warn) ins_triple(tmp); else { /* OC_RTERROR triple would have been inserted in curtchain by ins_errtriple * (invoked by stx_error). No need to do anything else. */ assert(OC_RTERROR == (TREF(curtchain))->exorder.bl->exorder.bl->exorder.bl->opcode); } return TRUE; } stx_error(ERR_SVNEXPECTED); return FALSE; case TK_EOL: case TK_SPACE: tmp = maketriple(OC_XNEW); tmp->operand[0] = put_ilit((mint) 0); ins_triple(tmp); if (TREF(for_stack_ptr) == TADR(for_stack)) start_fetches (OC_FETCH); else start_for_fetches (); return TRUE; case TK_LPAREN: ref = org = maketriple(OC_XNEW); count = 0; do { advancewindow(); next = maketriple(OC_PARAMETER); ref->operand[1] = put_tref(next); switch (TREF(window_token)) { case TK_IDENT: next->operand[0] = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); advancewindow(); break; case TK_ATSIGN: if (!indirection(&tmparg)) return FALSE; s = newtriple(OC_INDLVARG); s->operand[0] = tmparg; next->operand[0] = put_tref(s); break; default: stx_error(ERR_VAREXPECTED); return FALSE; } ins_triple(next); ref = next; count++; } while (TK_COMMA == TREF(window_token)); if (TK_RPAREN != TREF(window_token)) { stx_error(ERR_RPARENMISSING); return FALSE; } advancewindow(); org->operand[0] = put_ilit((mint) count); ins_triple(org); if (TREF(for_stack_ptr) == TADR(for_stack)) start_fetches (OC_FETCH); else start_for_fetches (); return TRUE; default: stx_error(ERR_VAREXPECTED); return FALSE; } } fis-gtm-V6.0-003/sr_port/m_open.c0000644000032200000250000000556612201176160015463 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "iotimer.h" #include "io_params.h" #include "advancewindow.h" #include "cmd.h" #include "deviceparameters.h" #include "mdq.h" LITREF mval literal_null; int m_open(void) { boolean_t is_timeout, inddevparms; static readonly unsigned char empty_plist[1] = { iop_eol }; int rval; opctype opcd; oprtype devpopr, mspace, plist, sopr, timeout; triple *indref, *ref1, *ref2, tmpchain; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; inddevparms = FALSE; if (EXPR_FAIL == (rval = expr(&sopr, MUMPS_STR))) /* NOTE assignment */ return FALSE; if (TK_COLON != TREF(window_token)) { /* Single arg specified */ if (EXPR_INDR == rval) { /* All arguments indirect */ make_commarg(&sopr, indir_open); return TRUE; } else /* Only device given, default device parms */ plist = put_str((char *)empty_plist, SIZEOF(empty_plist)); } else { advancewindow(); switch (TREF(window_token)) { case TK_COLON: /* Default device parms */ plist = put_str((char *)empty_plist, SIZEOF(empty_plist)); break; case TK_ATSIGN: /* Indirect for device parms */ if (!indirection(&devpopr)) return FALSE; indref = newtriple(OC_INDDEVPARMS); indref->operand[0] = devpopr; indref->operand[1] = put_ilit(IOP_OPEN_OK); inddevparms = TRUE; break; default: /* Literal device parms specified */ if (!deviceparameters(&plist, IOP_OPEN_OK)) return FALSE; } } /* Code generation for the optional timeout parm */ is_timeout = FALSE; if (TK_COLON != TREF(window_token)) timeout = put_ilit(NO_M_TIMEOUT); else { advancewindow(); if (TK_COLON == TREF(window_token)) timeout = put_ilit(NO_M_TIMEOUT); else { is_timeout = TRUE; if (EXPR_FAIL == expr(&timeout, MUMPS_INT)) return FALSE; } } if (TK_COLON != TREF(window_token)) mspace = put_lit((mval *)&literal_null); else { advancewindow(); if (EXPR_FAIL == expr(&mspace, MUMPS_EXPR)) return FALSE; } ref1 = newtriple(OC_OPEN); ref1->operand[0] = sopr; ref2 = newtriple(OC_PARAMETER); ref1->operand[1] = put_tref(ref2); ref2->operand[0] = !inddevparms ? plist : put_tref(indref); ref1 = newtriple(OC_PARAMETER); ref2->operand[1] = put_tref(ref1); ref1->operand[0] = timeout; ref2 = newtriple(OC_PARAMETER); ref1->operand[1] = put_tref(ref2); ref2->operand[0] = mspace; if (is_timeout) newtriple(OC_TIMTRU); return TRUE; } fis-gtm-V6.0-003/sr_port/m_quit.c0000644000032200000250000000432512201176160015474 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "mmemory.h" #include "cmd.h" #include "indir_enum.h" #include "advancewindow.h" GBLREF boolean_t run_time; error_def(ERR_ALIASEXPECTED); error_def(ERR_QUITARGLST); error_def(ERR_QUITARGUSE); int m_quit(void) { boolean_t arg; int rval; mvar *mvarptr; oprtype tmparg, x; triple *r, *triptr; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; arg = ((TK_EOL != TREF(window_token)) && (TK_SPACE != TREF(window_token))); if (TREF(for_stack_ptr) == TADR(for_stack)) { /* not FOR */ if (!arg) { newtriple((run_time) ? OC_HARDRET : OC_RET); return TRUE; } /* We now know we have an arg. See if it is an alias indicated arg */ if (TK_ASTERISK == TREF(window_token)) { /* We have QUIT * alias syntax */ advancewindow(); if (TK_IDENT == TREF(window_token)) { /* Both alias and alias container sources go through here */ if (!lvn(&tmparg, OC_GETINDX, 0)) return FALSE; r = newtriple(OC_RETARG); r->operand[0] = tmparg; r->operand[1] = put_ilit(TRUE); return TRUE; } else { /* Unexpected text after alias indicator */ stx_error(ERR_ALIASEXPECTED); return FALSE; } } else if (EXPR_FAIL != (rval = expr(&x, MUMPS_EXPR)) && (TK_COMMA != TREF(window_token))) /* NOTE assignment */ { if (EXPR_INDR != rval) { r = newtriple(OC_RETARG); r->operand[0] = x; r->operand[1] = put_ilit(FALSE); } else /* Indirect argument */ make_commarg(&x, indir_quit); return TRUE; } if (TK_COMMA == TREF(window_token)) stx_error (ERR_QUITARGLST); return FALSE; } else if (!arg) /* FOR */ { triptr = newtriple(OC_JMP); FOR_END_OF_SCOPE(1, triptr->operand[0]); return TRUE; } stx_error(ERR_QUITARGUSE); return FALSE; } fis-gtm-V6.0-003/sr_port/m_read.c0000644000032200000250000001075512201176160015431 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "iotimer.h" #include "mdq.h" #include "advancewindow.h" #include "cmd.h" #include "rwformat.h" error_def(ERR_RWARG); int m_read(void) { boolean_t local; opctype put_oc, read_oc; oprtype *timeout, x; triple *put, *ref, *s1, *sub, tmpchain; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; TREF(temp_subs) = FALSE; local = TRUE; dqinit(&tmpchain, exorder); switch (TREF(window_token)) { case TK_ASTERISK: advancewindow(); switch (TREF(window_token)) { default: case TK_IDENT: if (!lvn(&x, OC_PUTINDX, 0)) return FALSE; if (OC_PUTINDX == x.oprval.tref->opcode) { dqdel(x.oprval.tref, exorder); dqins(tmpchain.exorder.bl, exorder, x.oprval.tref); sub = x.oprval.tref; put_oc = OC_PUTINDX; } put = maketriple(OC_STO); put->operand[0] = x; dqins(tmpchain.exorder.bl, exorder, put); break; case TK_CIRCUMFLEX: local = FALSE; s1 = (TREF(curtchain))->exorder.bl; if (!gvn()) return FALSE; for (sub = (TREF(curtchain))->exorder.bl; sub != s1; sub = sub->exorder.bl) { put_oc = sub->opcode; if ((OC_GVNAME == put_oc) || (OC_GVNAKED == put_oc) || (OC_GVEXTNAM == put_oc)) break; } assert((OC_GVNAME == put_oc) || (OC_GVNAKED == put_oc) || (OC_GVEXTNAM == put_oc)); dqdel(sub, exorder); dqins(tmpchain.exorder.bl, exorder, sub); put = maketriple(OC_GVPUT); dqins(tmpchain.exorder.bl, exorder, put); break; case TK_ATSIGN: if (!indirection(&x)) return FALSE; put = maketriple(OC_INDSET); put->operand[0] = x; dqins(tmpchain.exorder.bl, exorder, put); break; } if (TK_HASH == TREF(window_token)) { stx_error(ERR_RWARG); return FALSE; } read_oc = OC_RDONE; break; case TK_QUESTION: case TK_EXCLAIMATION: case TK_HASH: case TK_SLASH: return rwformat(); case TK_STRLIT: x = put_lit(&(TREF(window_mval))); advancewindow(); ref = newtriple(OC_WRITE); ref->operand[0] = x; return TRUE; case TK_IDENT: if (!lvn(&x, OC_PUTINDX, 0)) return FALSE; read_oc = OC_READ; if (OC_PUTINDX == x.oprval.tref->opcode) { dqdel(x.oprval.tref, exorder); dqins(tmpchain.exorder.bl, exorder, x.oprval.tref); sub = x.oprval.tref; put_oc = OC_PUTINDX; } put = maketriple(OC_STO); put->operand[0] = x; dqins(tmpchain.exorder.bl, exorder, put); break; case TK_CIRCUMFLEX: local = FALSE; read_oc = OC_READ; s1 = (TREF(curtchain))->exorder.bl; if (!gvn()) return FALSE; for (sub = (TREF(curtchain))->exorder.bl; sub != s1; sub = sub->exorder.bl) { put_oc = sub->opcode; if ((OC_GVNAME == put_oc) || (OC_GVNAKED == put_oc) || (OC_GVEXTNAM == put_oc)) break; } assert((OC_GVNAME == put_oc) || (OC_GVNAKED == put_oc) || (OC_GVEXTNAM == put_oc)); dqdel(sub, exorder); dqins(tmpchain.exorder.bl, exorder, sub); put = maketriple(OC_GVPUT); dqins(tmpchain.exorder.bl, exorder, put); break; case TK_ATSIGN: if (!indirection(&x)) return FALSE; if ((TK_COLON != TREF(window_token)) && (TK_HASH != TREF(window_token))) { ref = maketriple(OC_COMMARG); ref->operand[0] = x; ref->operand[1] = put_ilit(indir_read); ins_triple(ref); return TRUE; } put = maketriple(OC_INDSET); put->operand[0] = x; dqins(tmpchain.exorder.bl, exorder, put); read_oc = OC_READ; break; default: stx_error(ERR_RWARG); return FALSE; } if (TK_HASH == TREF(window_token)) { advancewindow(); ref = maketriple(OC_READFL); if (EXPR_FAIL == expr(&ref->operand[0], MUMPS_INT)) return FALSE; timeout = &ref->operand[1]; } else { ref = maketriple(read_oc); timeout = &ref->operand[0]; } if (TK_COLON != TREF(window_token)) { *timeout = put_ilit(NO_M_TIMEOUT); ins_triple(ref); } else { advancewindow(); if (EXPR_FAIL == expr(timeout, MUMPS_INT)) return FALSE; ins_triple(ref); newtriple(OC_TIMTRU); } put->operand[local ? 1 : 0] = put_tref(ref); ref = (TREF(curtchain))->exorder.bl; dqadd(ref, &tmpchain, exorder); /*this is a violation of info hiding*/ return TRUE; } fis-gtm-V6.0-003/sr_port/m_set.c0000644000032200000250000010724012201176160015305 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_ctype.h" #include "compiler.h" #include "mdq.h" #include "opcode.h" #include "indir_enum.h" #include "nametabtyp.h" #include "toktyp.h" #include "funsvn.h" #include "mmemory.h" #include "advancewindow.h" #include "namelook.h" #include "cmd.h" #include "svnames.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "alias.h" #include "glvn_pool.h" #ifdef UNICODE_SUPPORTED #include "gtm_utf8.h" #endif GBLREF boolean_t badchar_inhibit; GBLREF boolean_t gtm_utf8_mode; error_def(ERR_ALIASEXPECTED); error_def(ERR_COMMA); error_def(ERR_DZWRNOALIAS); error_def(ERR_DZWRNOPAREN); error_def(ERR_EQUAL); error_def(ERR_INVSVN); error_def(ERR_NOALIASLIST); error_def(ERR_RPARENMISSING); error_def(ERR_SVNOSET); error_def(ERR_VAREXPECTED); LITREF unsigned char svn_index[], fun_index[]; LITREF nametabent svn_names[], fun_names[]; LITREF svn_data_type svn_data[]; LITREF fun_data_type fun_data[]; #define FIRST_SETLEFT_NOTSEEN -1 /* see comment against variable "first_setleft_invalid" for details */ /* This macro is used to insert the conditional jump triples (in SET $PIECE/$EXTRACT) ahead of the global variable * reference of the SET $PIECE target. This is to ensure the naked indicator is not touched in cases where the M-standard * says it should not be. e.g. set $piece(^x,"delim",2,1) should not touch naked indicator since 2>1. */ #define DQINSCURTARGCHAIN(curtargtriple) \ { \ dqins(curtargchain, exorder, curtargtriple); \ assert(curtargchain->exorder.fl == curtargtriple); \ curtargchain = curtargtriple; \ } #define RESTORE_CURTCHAIN_IF_NEEDED \ { \ if (curtchain_switched) \ { \ assert(NULL != save_curtchain); \ setcurtchain(save_curtchain); \ curtchain_switched = FALSE; \ } \ } #define SYNTAX_ERROR(errnum) \ { \ RESTORE_CURTCHAIN_IF_NEEDED; \ stx_error(errnum); \ return FALSE; \ } #define SYNTAX_ERROR_NOREPORT_HERE \ { \ RESTORE_CURTCHAIN_IF_NEEDED; \ return FALSE; \ } void allow_dzwrtac_as_mident(void); int m_set(void) { /* Some comment on "parse_warn". It is set to TRUE whenever the parse encounters an invalid setleft target. * Note that even if "parse_warn" is TRUE, we should not return FALSE right away but need to continue the parse * until the end of the current SET command. This way any remaining commands in the current parse line will be * parsed and triples generated for them. This is necessary just in case the currently parsed invalid SET command * does not get executed at runtime (due to postconditionals etc.) * * Some comment on the need for "first_setleft_invalid". This variable is needed only in the * case we encounter an invalid-SVN/invalid-FCN/unsettable-SVN as a target of the SET. We need to evaluate the * right-hand-side of the SET command only if at least one valid setleft target is parsed before an invalid setleft * target is encountered. This is because we still need to execute the valid setlefts at runtime before triggering * a runtime error for the invalid setleft. If the first setleft target is an invalid one, then there is no need * to evaluate the right-hand-side. In fact, in this case, adding triples (corresponding to the right hand side) * to the execution chain could cause problems with emit_code later in the compilation as the destination * for the right hand side triples could now be undefined (for example a valid SVN on the left side of the * SET would have generated an OC_SVPUT triple with one of its operands holding the result of the right * hand side evaluation, but an invalid SVN on the left side which would have instead caused an OC_RTERROR triple * to have been generated leaving no triple to receive the result of the right hand side evaluation thus causing * emit_code to be confused and GTMASSERT). Therefore discard all triples generated by the right hand side in this case. * By the same reasoning, discard all triples generated by setleft targets AFTER this invalid one as well. * "first_setleft_invalid" is set to TRUE if the first setleft target is invalid and set to FALSE if the first setleft * target is valid. It is initialized to -1 before the start of the parse. */ boolean_t alias_processing, delim1char, first_is_lit, got_lparen, have_lh_alias, is_extract, last_is_lit, valid_char; boolean_t parse_warn; /* set to TRUE in case of an invalid SVN etc. */ boolean_t curtchain_switched; /* set to TRUE if a setcurtchain was done */ boolean_t temp_subs_was_FALSE; boolean_t used_glvn_slot; int delimlen, first_val_lit, index, last_val_lit, nakedzalias, setop; int first_setleft_invalid; /* set to TRUE if the first setleft target is invalid */ opctype put_oc; oprtype delimval, firstval, lastval, resptr, *result, v, control_slot, first_control_slot; triple *curtargchain, *delimiter, discardcurtchain, *first, *get, *jmptrp1, *jmptrp2, *last, *obp, *put; triple *s, *s0, *s1, save_targchain, *save_curtchain, *save_curtchain1, *sub, targchain, *tmp; triple *ref; mint delimlit; mval *delim_mval; mvar *mvarptr; union { uint4 unichar_val; unsigned char unibytes_val[4]; } unichar; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; TREF(temp_subs) = FALSE; used_glvn_slot = FALSE; dqinit(&targchain, exorder); result = (oprtype *)mcalloc(SIZEOF(oprtype)); resptr = put_indr(result); delimiter = sub = last = NULL; /* A SET clause must be entirely alias related or a normal set. Parenthized multiple sets of aliases are not allowed * and will trigger an error. This is because the source and targets of aliases require different values and references * than normal sets do and thus cannot be mixed. */ if (alias_processing = (TK_ASTERISK == TREF(window_token))) advancewindow(); if (got_lparen = (TK_LPAREN == TREF(window_token))) { if (alias_processing) stx_error(ERR_NOALIASLIST); advancewindow(); TREF(temp_subs) = TRUE; } /* Some explanation: The triples from the left hand side of the SET expression that are * expressly associated with fetching (in case of set $piece/$extract) and/or storing of * the target value are removed from curtchain and placed on the targchain. Later, these * triples will be added to the end of curtchain to do the finishing store of the target * after the righthand side has been evaluated. This is per the M standard. * * Note that SET $PIECE/$EXTRACT have special conditions in which the first argument is not referenced at all. * (e.g. set $piece(^a," ",3,2) in this case 3 > 2 so this should not evaluate ^a and therefore should not * modify the naked indicator). That is, the triples that do these conditional checks need to be inserted * ahead of the OC_GVNAME of ^a, all of which need to be inserted on the targchain. But the conditionalization * can be done only after parsing the first argument of the SET $PIECE and examining the remaining arguments. * Therefore we maintain the "curtargchain" variable which stores the value of the "targchain" at the beginning * of the iteration (at the start of the $PIECE parsing) and all the conditionalization will be inserted right * here which is guaranteed to be ahead of where the OC_GVNAME gets inserted. * * For example, SET $PIECE(^A(x,y),delim,first,last)=RHS will generate a final triple chain as follows * * A - Triples to evaluate subscripts (x,y) of the global ^A * A - Triples to evaluate delim * A - Triples to evaluate first * A - Triples to evaluate last * B - Triples to evaluate RHS * C - Triples to do conditional check (e.g. first > last etc.) * C - Triples to branch around if the checks indicate this is a null operation SET $PIECE * D - Triple that does OC_GVNAME of ^A * D - Triple that does OC_SETPIECE to determine the new value * D - Triple that does OC_GVPUT of the new value into ^A(x,y) * This is the point where the conditional check triples will branch around to if they chose to. * * A - triples that evaluate the arguments/subscripts in the left-hand-side of the SET command * These triples are built in "curtchain" * B - triples that evaluate the arguments/subscripts in the right-hand-side of the SET command * These triples are built in "curtchain" * C - triples that do conditional check for any $PIECE/$EXTRACT in the left side of the SET command. * These triples are built in "curtargchain" * D - triples that generate the reference to the target of the SET and the store into the target. * These triples are built in "targchain" * * Note alias processing does not support the SET *(...)=.. type syntax because the type of argument * created for RHS processing is dependent on the LHS receiver type and we do not support more than one * type of source argument in a single SET. */ first_setleft_invalid = FIRST_SETLEFT_NOTSEEN; curtchain_switched = FALSE; nakedzalias = have_lh_alias = FALSE; save_curtchain = NULL; assert(FIRST_SETLEFT_NOTSEEN != TRUE); assert(FIRST_SETLEFT_NOTSEEN != FALSE); for (parse_warn = FALSE; ; parse_warn = FALSE) { curtargchain = targchain.exorder.bl; jmptrp1 = jmptrp2 = NULL; delim1char = is_extract = FALSE; allow_dzwrtac_as_mident(); /* Allows $ZWRTACxxx as target to be treated as an mident */ switch (TREF(window_token)) { case TK_IDENT: /* A slight diversion first. If this is a $ZWRTAC set (indication of $ in first char * is currently enough to signify that), then we need to check a few conditions first. * If this is a "naked $ZWRTAC", meaning no numeric suffix, then this is a flag that * all the $ZWRTAC vars in the local variable tree need to be kill *'d which will not * be generating a SET instruction. First we need to verify that fact and make sure * we are not in PARENs and not doing alias processing. Note *any* value can be * specified as the source but while it will be evaluated, it is NOT stored anywhere. */ if ('$' == *(TREF(window_ident)).addr) { /* We have a $ZWRTAC target */ if (got_lparen) /* We don't allow $ZWRTACxxx to be specified in a parenthesized list. * Verify that first */ SYNTAX_ERROR(ERR_DZWRNOPAREN); if (STR_LIT_LEN(DOLLAR_ZWRTAC) == (TREF(window_ident)).len) { /* Ok, this is a naked $ZWRTAC targeted set */ if (alias_processing) SYNTAX_ERROR(ERR_DZWRNOALIAS); nakedzalias = TRUE; /* This opcode doesn't really need args but it is easier to fit in with the rest * of m_set processing to pass it the result arg, which there may actually be * a use for someday.. */ put = maketriple(OC_CLRALSVARS); put->operand[0] = resptr; dqins(targchain.exorder.bl, exorder, put); advancewindow(); break; } } /* If we are doing alias processing, there are two possibilities: * 1) LHS is unsubscripted - it is an alias variable being created or replaced. Need to parse * the varname as if this were a regular set. * 2) LHS is subscripted - it is an alias container variable being created or replaced. The * processing here is to pass the base variable index to the store routine so bypass the * lvn() call. */ if (!alias_processing || (TK_LPAREN == TREF(director_token))) { /* Normal variable processing or we have a lh alias container */ if (!lvn(&v, OC_PUTINDX, 0)) SYNTAX_ERROR_NOREPORT_HERE; if (OC_PUTINDX == v.oprval.tref->opcode) { dqdel(v.oprval.tref, exorder); dqins(targchain.exorder.bl, exorder, v.oprval.tref); sub = v.oprval.tref; put_oc = OC_PUTINDX; if (TREF(temp_subs)) create_temporaries(sub, put_oc); } } else { /* Have alias variable. Argument is index into var table rather than pointer to var */ have_lh_alias = TRUE; /* We only want the variable index in this case. Since the entire hash structure to which * this variable is going to be pointing to is changing, doing anything that calls fetch() * is somewhat pointless so we avoid it by just accessing the variable information * directly. */ mvarptr = get_mvaddr(&(TREF(window_ident))); v = put_ilit(mvarptr->mvidx); advancewindow(); } /* Determine correct storing triple */ put = maketriple((!alias_processing ? OC_STO : (have_lh_alias ? OC_SETALS2ALS : OC_SETALSIN2ALSCT))); put->operand[0] = v; put->operand[1] = resptr; dqins(targchain.exorder.bl, exorder, put); break; case TK_CIRCUMFLEX: if (alias_processing) SYNTAX_ERROR(ERR_ALIASEXPECTED); s1 = (TREF(curtchain))->exorder.bl; if (!gvn()) SYNTAX_ERROR_NOREPORT_HERE; for (sub = (TREF(curtchain))->exorder.bl; sub != s1; sub = sub->exorder.bl) { put_oc = sub->opcode; if ((OC_GVNAME == put_oc) || (OC_GVNAKED == put_oc) || (OC_GVEXTNAM == put_oc)) break; } assert((OC_GVNAME == put_oc) || (OC_GVNAKED == put_oc) || (OC_GVEXTNAM == put_oc)); dqdel(sub, exorder); dqins(targchain.exorder.bl, exorder, sub); if (TREF(temp_subs)) create_temporaries(sub, put_oc); put = maketriple(OC_GVPUT); put->operand[0] = resptr; dqins(targchain.exorder.bl, exorder, put); break; case TK_ATSIGN: if (alias_processing) SYNTAX_ERROR(ERR_ALIASEXPECTED); if (!indirection(&v)) SYNTAX_ERROR_NOREPORT_HERE; if (!got_lparen && (TK_EQUAL != TREF(window_token))) { assert(!curtchain_switched); put = newtriple(OC_COMMARG); put->operand[0] = v; put->operand[1] = put_ilit(indir_set); return TRUE; } if (TREF(side_effect_handling)) { /* save and restore the variable lookup for true left-to-right evaluation */ INSERT_INDSAVGLVN(control_slot, v, ANY_SLOT, 0); /* 0 flag to defer global reference */ if (!used_glvn_slot) { used_glvn_slot = TRUE; first_control_slot = control_slot; } put = maketriple(OC_STOGLVN); put->operand[0] = control_slot; } else { /* quick and dirty old way */ put = maketriple(OC_INDSET); put->operand[0] = v; } put->operand[1] = resptr; dqins(targchain.exorder.bl, exorder, put); break; case TK_DOLLAR: if (alias_processing) SYNTAX_ERROR(ERR_ALIASEXPECTED); advancewindow(); if (TK_IDENT != TREF(window_token)) SYNTAX_ERROR(ERR_VAREXPECTED); if (TK_LPAREN != TREF(director_token)) { /* Look for intrinsic special variables */ s1 = (TREF(curtchain))->exorder.bl; if (0 > (index = namelook(svn_index, svn_names, (TREF(window_ident)).addr, (TREF(window_ident)).len))) { /* NOTE assignment above */ STX_ERROR_WARN(ERR_INVSVN); /* sets "parse_warn" to TRUE */ } else if (!svn_data[index].can_set) { STX_ERROR_WARN(ERR_SVNOSET); /* sets "parse_warn" to TRUE */ } advancewindow(); if (!parse_warn) { if ((SV_ETRAP != svn_data[index].opcode) && (SV_ZTRAP != svn_data[index].opcode)) { /* Setting of $ZTRAP or $ETRAP must go through opp_svput because they * may affect the stack pointer. All others directly to op_svput(). */ put = maketriple(OC_SVPUT); } else put = maketriple(OC_PSVPUT); put->operand[0] = put_ilit(svn_data[index].opcode); put->operand[1] = resptr; dqins(targchain.exorder.bl, exorder, put); } else { /* OC_RTERROR triple would have been inserted in curtchain by ins_errtriple * (invoked by stx_error). To maintain consistency with the "if" portion of * this code, we need to move this triple to the "targchain". */ tmp = (TREF(curtchain))->exorder.bl; /* corresponds to put_ilit(FALSE) in ins_errtriple */ tmp = tmp->exorder.bl; /* corresponds to put_ilit(in_error) in ins_errtriple */ tmp = tmp->exorder.bl; /* corresponds to newtriple(OC_RTERROR) in ins_errtriple */ assert(OC_RTERROR == tmp->opcode); dqdel(tmp, exorder); dqins(targchain.exorder.bl, exorder, tmp); CHKTCHAIN(&targchain); } break; } /* Only 4 function names allowed on left side: $[Z]Piece and $[Z]Extract */ index = namelook(fun_index, fun_names, (TREF(window_ident)).addr, (TREF(window_ident)).len); if (0 > index) { STX_ERROR_WARN(ERR_INVFCN); /* sets "parse_warn" to TRUE */ /* OC_RTERROR triple would have been inserted in "curtchain" by ins_errtriple * (invoked by stx_error). We need to switch it to "targchain" to be consistent * with every other codepath in this module. */ tmp = (TREF(curtchain))->exorder.bl; /* corresponds to put_ilit(FALSE) in ins_errtriple */ tmp = tmp->exorder.bl; /* corresponds to put_ilit(in_error) in ins_errtriple */ tmp = tmp->exorder.bl; /* corresponds to newtriple(OC_RTERROR) in ins_errtriple */ assert(OC_RTERROR == tmp->opcode); dqdel(tmp, exorder); dqins(targchain.exorder.bl, exorder, tmp); CHKTCHAIN(&targchain); advancewindow(); /* skip past the function name */ advancewindow(); /* skip past the left paren */ /* Parse the remaining arguments until corresponding RIGHT-PAREN/SPACE/EOL is reached */ if (!parse_until_rparen_or_space()) SYNTAX_ERROR_NOREPORT_HERE; } else { switch (fun_data[index].opcode) { case OC_FNPIECE: setop = OC_SETPIECE; break; case OC_FNEXTRACT: is_extract = TRUE; setop = OC_SETEXTRACT; break; case OC_FNZPIECE: setop = OC_SETZPIECE; break; case OC_FNZEXTRACT: is_extract = TRUE; setop = OC_SETZEXTRACT; break; default: SYNTAX_ERROR(ERR_VAREXPECTED); } advancewindow(); advancewindow(); /* Although we see the get (target) variable first, we need to save it's processing * on another chain -- the targchain -- because the retrieval of the target is bypassed * and the naked indicator is not reset if the first/last parameters are not set in a * logical manner (must be > 0 and first <= last). So the evaluation order is * delimiter (if $piece), first, last, RHS of the set and then the target if applicable. * Set up primary action triple now since it is ref'd by the put triples generated below. */ s = maketriple(setop); /* Even for SET[Z]PIECE and SET[Z]EXTRACT, the SETxxxxx opcodes * do not do the final store, they only create the final value TO be * stored so generate the triples that will actually do the store now. * Note we are still building triples on the original curtchain. */ switch (TREF(window_token)) { case TK_IDENT: if (!lvn(&v, OC_PUTINDX, 0)) SYNTAX_ERROR(ERR_VAREXPECTED); if (OC_PUTINDX == v.oprval.tref->opcode) { dqdel(v.oprval.tref, exorder); dqins(targchain.exorder.bl, exorder, v.oprval.tref); sub = v.oprval.tref; put_oc = OC_PUTINDX; if (TREF(temp_subs)) create_temporaries(sub, put_oc); } get = maketriple(OC_FNGET); get->operand[0] = v; put = maketriple(OC_STO); put->operand[0] = v; put->operand[1] = put_tref(s); break; case TK_ATSIGN: if (!indirection(&v)) SYNTAX_ERROR(ERR_VAREXPECTED); INSERT_INDSAVGLVN(control_slot, v, ANY_SLOT, 0); if (!used_glvn_slot) { used_glvn_slot = TRUE; first_control_slot = control_slot; } get = maketriple(OC_INDGET1); get->operand[0] = control_slot; put = maketriple(OC_STOGLVN); put->operand[0] = control_slot; put->operand[1] = put_tref(s); break; case TK_CIRCUMFLEX: s1 = (TREF(curtchain))->exorder.bl; if (!gvn()) SYNTAX_ERROR_NOREPORT_HERE; for (sub = (TREF(curtchain))->exorder.bl; sub != s1 ; sub = sub->exorder.bl) { put_oc = sub->opcode; if ((OC_GVNAME == put_oc) || (OC_GVNAKED == put_oc) || (OC_GVEXTNAM == put_oc)) break; } assert((OC_GVNAME == put_oc) || (OC_GVNAKED == put_oc) || (OC_GVEXTNAM == put_oc)); dqdel(sub, exorder); dqins(targchain.exorder.bl, exorder, sub); if (TREF(temp_subs)) create_temporaries(sub, put_oc); get = maketriple(OC_FNGVGET); get->operand[0] = put_str(0, 0); put = maketriple(OC_GVPUT); put->operand[0] = put_tref(s); break; default: SYNTAX_ERROR(ERR_VAREXPECTED); } s->operand[0] = put_tref(get); /* Code to fetch args for target triple are on targchain. Put get there now too. */ dqins(targchain.exorder.bl, exorder, get); CHKTCHAIN(&targchain); if (!is_extract) { /* Set $[z]piece */ delimiter = newtriple(OC_PARAMETER); s->operand[1] = put_tref(delimiter); first = newtriple(OC_PARAMETER); delimiter->operand[1] = put_tref(first); /* Process delimiter string ($[z]piece only) */ if (TK_COMMA != TREF(window_token)) SYNTAX_ERROR(ERR_COMMA); advancewindow(); if (EXPR_FAIL == expr(&delimval, MUMPS_STR)) SYNTAX_ERROR_NOREPORT_HERE; assert(TRIP_REF == delimval.oprclass); } else { /* Set $[Z]Extract */ first = newtriple(OC_PARAMETER); s->operand[1] = put_tref(first); } /* Process first integer value */ if (TK_COMMA != TREF(window_token)) firstval = put_ilit(1); else { advancewindow(); if (EXPR_FAIL == expr(&firstval, MUMPS_INT)) SYNTAX_ERROR(ERR_COMMA); assert(TRIP_REF == firstval.oprclass); } first->operand[0] = firstval; if (first_is_lit = (OC_ILIT == firstval.oprval.tref->opcode)) { assert(ILIT_REF ==firstval.oprval.tref->operand[0].oprclass); first_val_lit = firstval.oprval.tref->operand[0].oprval.ilit; } if (TK_COMMA != TREF(window_token)) { /* There is no "last" value. Only if 1 char literal delimiter and * no "last" value can we generate shortcut code to op_set[z]p1 entry * instead of op_set[z]piece. Note if UTF8 mode is in effect, then this * optimization applies if the literal is one unicode char which may in * fact be up to 4 bytes but will still be passed as a single unsigned * integer. */ if (!is_extract) { delim_mval = &delimval.oprval.tref->operand[0].oprval.mlit->v; valid_char = TRUE; /* Basic assumption unles proven otherwise */ if ((OC_LIT == delimval.oprval.tref->opcode) && (1 == (gtm_utf8_mode ? MV_FORCE_LEN(delim_mval) : delim_mval->str.len))) { /* Single char delimiter for set $piece */ # ifdef UNICODE_SUPPORTED if (gtm_utf8_mode) { /* We have a supposed single char delimiter but it * must be a valid utf8 char to be used by * op_setp1() and MV_FORCE_LEN won't tell us that. */ valid_char = UTF8_VALID(delim_mval->str.addr, (delim_mval->str.addr + delim_mval->str.len), delimlen); if (!valid_char && !badchar_inhibit) UTF8_BADCHAR(0, delim_mval->str.addr, (delim_mval->str.addr + delim_mval->str.len), 0, NULL); } # endif if (valid_char || (1 == delim_mval->str.len)) { /* This reference to a one character literal or a single * byte invalid utf8 character that needs to be turned into * an explict formated integer literal instead */ unichar.unichar_val = 0; if (!gtm_utf8_mode) { /* Single byte delimiter */ assert(1 == delim_mval->str.len); UNIX_ONLY(s->opcode = OC_SETZP1); VMS_ONLY(s->opcode = OC_SETP1); unichar.unibytes_val[0] = *delim_mval->str.addr; } # ifdef UNICODE_SUPPORTED else { /* Potentially multiple bytes in one int */ assert(SIZEOF(int) >= delim_mval->str.len); memcpy(unichar.unibytes_val, delim_mval->str.addr, delim_mval->str.len); s->opcode = OC_SETP1; } # endif delimlit = (mint)unichar.unichar_val; delimiter->operand[0] = put_ilit(delimlit); delim1char = TRUE; } } } if (!delim1char) { /* Was not handled as a single char delim by code above either bcause it * was (1) not set $piece, or (2) was not a single char delim or (3) it was * not a VALID utf8 single char delim and badchar was inhibited. */ if (!is_extract) delimiter->operand[0] = delimval; last = newtriple(OC_PARAMETER); first->operand[1] = put_tref(last); last->operand[0] = first->operand[0]; /* start = end range */ } /* Generate test sequences for first/last to bypass the set operation if * first/last are not in a usable form */ if (first_is_lit) { if (1 > first_val_lit) { jmptrp1 = maketriple(OC_JMP); DQINSCURTARGCHAIN(jmptrp1); } /* note else no test necessary since first == last and are > 0 */ } else { /* Generate test for first being <= 0 */ jmptrp1 = maketriple(OC_COBOOL); jmptrp1->operand[0] = first->operand[0]; DQINSCURTARGCHAIN(jmptrp1); jmptrp1 = maketriple(OC_JMPLEQ); DQINSCURTARGCHAIN(jmptrp1); } } else { /* There IS a last value */ if (!is_extract) delimiter->operand[0] = delimval; last = newtriple(OC_PARAMETER); first->operand[1] = put_tref(last); advancewindow(); if (EXPR_FAIL == expr(&lastval, MUMPS_INT)) SYNTAX_ERROR_NOREPORT_HERE; assert(TRIP_REF == lastval.oprclass); last->operand[0] = lastval; /* Generate inline code to test first/last for usability and if found * lacking, branch around the getchain and the actual store so we avoid * setting the naked indicator so far as the target gvn is concerned. */ if (last_is_lit = (OC_ILIT == lastval.oprval.tref->opcode)) /* NOTE assignment */ { /* Case 1: last is a literal */ assert(ILIT_REF == lastval.oprval.tref->operand[0].oprclass); last_val_lit = lastval.oprval.tref->operand[0].oprval.ilit; if ((1 > last_val_lit) || ((first_is_lit && (first_val_lit > last_val_lit)))) { /* .. and first is a literal and one or both of them is no good * so unconditionally branch around the whole thing. */ jmptrp1 = maketriple(OC_JMP); DQINSCURTARGCHAIN(jmptrp1); } /* else case actually handled at next 'if' .. */ } else { /* Last is not literal. Do test if it is greater than 0 */ jmptrp1 = maketriple(OC_COBOOL); jmptrp1->operand[0] = last->operand[0]; DQINSCURTARGCHAIN(jmptrp1); jmptrp1 = maketriple(OC_JMPLEQ); DQINSCURTARGCHAIN(jmptrp1); } if (!last_is_lit || !first_is_lit) { /* Compare to check that last >= first */ jmptrp2 = maketriple(OC_VXCMPL); jmptrp2->operand[0] = first->operand[0]; jmptrp2->operand[1] = last->operand[0]; DQINSCURTARGCHAIN(jmptrp2); jmptrp2 = maketriple(OC_JMPGTR); DQINSCURTARGCHAIN(jmptrp2); } } } if (TK_RPAREN != TREF(window_token)) SYNTAX_ERROR(ERR_RPARENMISSING); advancewindow(); if (!parse_warn) { dqins(targchain.exorder.bl, exorder, s); dqins(targchain.exorder.bl, exorder, put); CHKTCHAIN(&targchain); /* Put result operand on the chain. End of chain depends on whether or not * we are calling the shortcut or the full set-piece code */ if (delim1char) first->operand[1] = resptr; else last->operand[1] = resptr; /* Set jump targets if we did tests above. The function "tnxtarg" operates on "curtchain" * but we want to set targets based on "targchain", so temporarily switch them. Should not * use "save_curtchain" here as it might already be in use. */ save_curtchain1 = setcurtchain(&targchain); if (NULL != jmptrp1) tnxtarg(&jmptrp1->operand[0]); if (NULL != jmptrp2) tnxtarg(&jmptrp2->operand[0]); setcurtchain(save_curtchain1); } break; case TK_ASTERISK: /* The only way an asterisk can be detected here is if we are inside a list so mention this is * not possible and give error. */ stx_error(ERR_NOALIASLIST); return FALSE; default: SYNTAX_ERROR(ERR_VAREXPECTED); } if (FIRST_SETLEFT_NOTSEEN == first_setleft_invalid) { first_setleft_invalid = parse_warn; if (first_setleft_invalid) { /* We are not going to evaluate the right hand side of the SET command. This means * we should not evaluate any more setleft targets (whether they parse validly or not) * as well since their source (the RHS of the set) is undefined. To achieve this, we * switch to a temporary chain (both for curtchain and targchain) that will be discarded finally. */ /* save curtchain */ dqinit(&discardcurtchain, exorder); save_curtchain = setcurtchain(&discardcurtchain); assert(!curtchain_switched); curtchain_switched = TRUE; /* save targchain */ save_targchain = targchain; dqinit(&targchain, exorder); } } assert(FIRST_SETLEFT_NOTSEEN != first_setleft_invalid); if (!got_lparen) break; if (TK_COMMA == TREF(window_token)) advancewindow(); else { if (TK_RPAREN == TREF(window_token)) { advancewindow(); break; } else SYNTAX_ERROR(ERR_RPARENMISSING); } } if (TK_EQUAL != TREF(window_token)) SYNTAX_ERROR(ERR_EQUAL); advancewindow(); assert(FIRST_SETLEFT_NOTSEEN != first_setleft_invalid); temp_subs_was_FALSE = (FALSE == TREF(temp_subs)); /* Note down if temp_subs is FALSE at this point */ /* If we are in alias processing mode, the RHS cannot be an expression but must be one of a subscripted or unsubscripted * local variable, or a $$func(..) function call. */ if (!alias_processing) { /* Normal case first - evaluate expression creating triples on the current chain */ if (EXPR_FAIL == expr(result, MUMPS_EXPR)) SYNTAX_ERROR_NOREPORT_HERE; } else { /* Alias processing -- determine which of the three types of sources we have: var, subscripted var or $$func */ allow_dzwrtac_as_mident(); /* Allow source of $ZWRTACxxx as an mident */ if (TK_IDENT != TREF(window_token)) { /* Check if we have a $$func() call source */ if ((TK_DOLLAR == TREF(window_token)) && (TK_DOLLAR == TREF(director_token))) { /* Parse the function only with exfunc(). We definitely do not want an expression */ TREF(temp_subs) = TRUE; /* RHS $$ function detected - need temporary */ advancewindow(); if (!exfunc(result, TRUE)) SYNTAX_ERROR_NOREPORT_HERE; if (OC_SETALSIN2ALSCT == put->opcode) /* Change opcode to create an alias container from the returned alias */ put->opcode = OC_SETFNRETIN2ALSCT; else { /* Change opcode to create an alias from the returned alias */ assert(OC_SETALS2ALS == put->opcode); put->opcode = OC_SETFNRETIN2ALS; } } else /* Else, only local variables allowed as aliases */ SYNTAX_ERROR(ERR_ALIASEXPECTED); } else { /* Alias var source */ if (('$' == *(TREF(window_ident)).addr) && (STR_LIT_LEN(DOLLAR_ZWRTAC) >= (TREF(window_ident)).len)) /* $ZWRTAC is not allowed as a "source" value. Must be a $ZWRTACn format */ SYNTAX_ERROR(ERR_DZWRNOALIAS); if (TK_LPAREN == TREF(director_token)) { /* Subscripted local variable - have alias container. * The storing opcode set into the "put" triple at the top of this routine was * set assuming the source was an alias. Now that we know the source is actually * an alias container (and hence a different data type), we need to adjust the * opcode accordingly. */ if (OC_SETALS2ALS == put->opcode) put->opcode = OC_SETALSCTIN2ALS; else { assert(OC_SETALSIN2ALSCT == put->opcode); put->opcode = OC_SETALSCT2ALSCT; } } /* For RHS processing, both alias var and alias container vars have their lv_val addr * passed so normal var processing applies. */ if (!lvn(result, OC_GETINDX, 0)) SYNTAX_ERROR(ERR_ALIASEXPECTED); } } if (first_setleft_invalid) { /* switch from the temporary chain back to the current execution chain */ assert(curtchain_switched); RESTORE_CURTCHAIN_IF_NEEDED; /* does a setcurtchain(save_curtchain) */ targchain = save_targchain; } /* Now add in the left-hand side triples */ assert(!curtchain_switched); obp = (TREF(curtchain))->exorder.bl; dqadd(obp, &targchain, exorder); /* this is a violation of info hiding */ /* Check if "temp_subs" was FALSE originally but got set to TRUE as part of evaluating the right hand side * (for example, if rhs had $$ or $& or $INCR usages). If so need to create temporaries. */ if (TREF(temp_subs) && temp_subs_was_FALSE && (NULL != sub)) create_temporaries(sub, put_oc); TREF(temp_subs) = FALSE; if (used_glvn_slot) { /* Free up slots we're done with. */ ref = newtriple(OC_GLVNPOP); ref->operand[0] = first_control_slot; } return TRUE; } /* Prior to Alias support, the ZWRITE command was able to dump the entire local variable environment such that it could be * reloaded by Xecuting the dumped lines. With the addition of Alias type variables, the output lines not only include the * variable content but their alias associations as well. One aspect of this is the $ZWRTAC variable which is a temporary * "variable" which we allow to hold the content of what would otherwise be "orphaned data" or data which has a container * pointing to it but is not referenced by a base variable. During the reload operation, it is this orphaned data that is * put into the $ZWRTAC environment. The first orphaned array is put into $ZWRTAC1(...), the second into $ZWRTAC2(..) and * so on. Setting the $ZWRTAC variable itself to null (or to any value actually - null only is not enforced) causes all of * the $ZWRTAC variables to be KILL *'d. The only syntactic allowances for using $ZWRTACxxx as an mident in GTM are in this * SET statement. We do not support its use in any other statement type. This routine allows us to modify the tokens so that * if the current token is a '$' and the next token is ZWRTACxxx, we can combine them into a single token and the parser * need not be further modified. */ void allow_dzwrtac_as_mident(void) { char_ptr_t chrp, chrpmin, chrplast; int movlen; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (TK_DOLLAR != TREF(window_token)) return; /* Couldn't be $ZWRTACxxx without first $ */ if (TK_IDENT != TREF(director_token)) return; /* Couldn't be $ZWRTACxxx without token 2nd part */ if (STR_LIT_LEN("ZWRTAC") > (TREF(director_ident)).len) return; /* Couldn't be $ZALAISxxx without sufficient length of name */ if (0 != MEMCMP_LIT((TREF(director_ident)).addr, "ZWRTAC")) return; /* Couldn't be $ZWRTACxxx without ZWRTAC as first part of token */ /* We need to shift the existing token over 1 byte to make room for insertion of the '$' prefix. Normally, * we wouldn't want to do this as we are verifying but since if the verification fails the code path will * raise an error and since the error does not use this token buffer, we are safe in migrating while * we do the verification check. Saves us having to scan the line backwards via memmove() again below. So * verify the token suffix is all numeric while we do our shift. */ movlen = ((MAX_MIDENT_LEN) > (TREF(director_ident)).len) ? (TREF(director_ident)).len : MAX_MIDENT_LEN - 1; for (chrplast = (TREF(director_ident)).addr + movlen, chrp = chrplast - 1, chrpmin = (TREF(director_ident)).addr + STR_LIT_LEN("ZWRTAC") - 1; chrp > chrpmin; --chrp, --chrplast) { if (!ISDIGIT_ASCII((int)*chrp)) return; /* Couldn't be $ZWRTACxxx without all numeric suffix (if exists) */ *chrplast = *chrp; } /* Verification (and shift) complete -- finish modifying director token */ MEMCPY_LIT((TREF(director_ident)).addr, DOLLAR_ZWRTAC); (TREF(director_ident)).len = movlen + 1; /* Nnw forward the scan to pull director token values into window token for use by our caller */ advancewindow(); assert(TK_IDENT == TREF(window_token)); } fis-gtm-V6.0-003/sr_port/m_tcommit.c0000644000032200000250000000145012201176160016162 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "cmd.h" error_def(ERR_SPOREOL); int m_tcommit(void) { DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (TK_EOL != (TREF(window_token)) && (TK_SPACE != TREF(window_token))) { stx_error(ERR_SPOREOL); return FALSE; } newtriple(OC_TCOMMIT); return TRUE; } fis-gtm-V6.0-003/sr_port/m_trestart.c0000644000032200000250000000153612201176160016363 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "cmd.h" error_def(ERR_SPOREOL); int m_trestart(void) { triple *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if ((TK_EOL != TREF(window_token)) && (TK_SPACE != TREF(window_token))) { stx_error(ERR_SPOREOL); return FALSE; } ref = newtriple(OC_TRESTART); ref->operand[0] = put_ilit(1); return TRUE; } fis-gtm-V6.0-003/sr_port/m_trollback.c0000644000032200000250000000221612201176160016464 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "indir_enum.h" #include "opcode.h" #include "toktyp.h" #include "cmd.h" int m_trollback(void) { oprtype x; triple *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if ((TK_SPACE == TREF(window_token)) || (TK_EOL == TREF(window_token))) { ref = newtriple(OC_TROLLBACK); ref->operand[0] = put_ilit(0); return TRUE; } else { switch (expr(&x, MUMPS_INT)) { case EXPR_FAIL: return FALSE; case EXPR_GOOD: ref = newtriple(OC_TROLLBACK); ref->operand[0] = x; return TRUE; case EXPR_INDR: make_commarg(&x,indir_trollback); return TRUE; } } return FALSE; /* This should never get executed, added to make compiler happy */ } fis-gtm-V6.0-003/sr_port/m_tstart.c0000644000032200000250000001102712201176160016030 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "nametabtyp.h" #include "indir_enum.h" #include "advancewindow.h" #include "cmd.h" #include "namelook.h" static readonly nametabent tst_param_names[] = { {1,"S"} ,{6,"SERIAL"} ,{1,"T"} ,{8,"TRANSACT*"} }; /* Offset of letter with dev_param_names */ static readonly unsigned char tst_param_index[27] = { /* A B C D E F G H I J K L M N */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* O P Q R S T U V W X Y Z end */ 0, 0, 0, 0, 0, 2, 4, 4, 4, 4, 4, 4, 4 }; error_def(ERR_RPARENMISSING); error_def(ERR_TSTRTPARM); error_def(ERR_VAREXPECTED); int m_tstart(void) { boolean_t bad_parse, has_lpar, has_ser, has_tid; int count, n; mval dummyid; oprtype tmparg; triple *fetch, *ref, *s, *ser, *tid, *varlst, *varnext, *varp; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; count = -1; /* indicates not restartable */ varlst = newtriple(OC_PARAMETER); switch (TREF(window_token)) { case TK_IDENT: count = 1; varlst->operand[1] = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); advancewindow(); break; case TK_ASTERISK: count = -2; /* indicates save all variables */ advancewindow(); break; case TK_ATSIGN: if (!indirection(&tmparg)) return FALSE; if (TK_COLON == TREF(window_token)) { ref = newtriple(OC_COMMARG); ref->operand[0] = tmparg; ref->operand[1] = put_ilit((mint) indir_tstart); return TRUE; } else { count = 1; fetch = newtriple(OC_INDLVARG); fetch->operand[0] = tmparg; varlst->operand[1] = put_tref(fetch); } break; case TK_EOL: case TK_SPACE: break; case TK_LPAREN: varp = varlst; for(count = 0; ;) { advancewindow(); switch (TREF(window_token)) { case TK_IDENT: varnext = newtriple(OC_PARAMETER); varnext->operand[0] = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); varp->operand[1] = put_tref(varnext); varp = varnext; advancewindow(); count++; break; case TK_ATSIGN: if (!indirection(&tmparg)) return FALSE; s = newtriple(OC_INDLVARG); s->operand[0] = tmparg; varnext = newtriple(OC_PARAMETER); varnext->operand[0] = put_tref(s); varp->operand[1] = put_tref(varnext); varp = varnext; count++; break; case TK_RPAREN: break; default: stx_error(ERR_VAREXPECTED); return FALSE; } if (TK_COMMA != TREF(window_token)) break; } if (TK_RPAREN != TREF(window_token)) { stx_error(ERR_RPARENMISSING); return FALSE; } advancewindow(); break; } varlst->operand[0] = put_ilit(count); has_ser = has_tid = FALSE; tid = newtriple(OC_PARAMETER); if (TK_COLON == TREF(window_token)) { advancewindow(); if (has_lpar = (TK_LPAREN == TREF(window_token))) advancewindow(); for(;;) { bad_parse = TRUE; if (TK_IDENT == TREF(window_token)) { if ((0 <= (n = namelook(tst_param_index, tst_param_names, (TREF(window_ident)).addr, (TREF(window_ident)).len)))) { /* NOTE assignment above */ if (n < 2 && !has_ser) { has_ser = TRUE; bad_parse = FALSE; advancewindow(); } else if (!has_tid) { advancewindow(); if (TK_EQUAL == TREF(window_token)) { advancewindow(); if (EXPR_FAIL == expr(&tid->operand[0], MUMPS_EXPR)) return FALSE; has_tid = TRUE; bad_parse = FALSE; } } } } if (bad_parse) { stx_error(ERR_TSTRTPARM); return FALSE; } if (!has_lpar || (TK_RPAREN == TREF(window_token))) break; if (TK_COLON != TREF(window_token)) { stx_error(ERR_TSTRTPARM); return FALSE; } advancewindow(); } if (has_lpar) { assert(TK_RPAREN == TREF(window_token)); advancewindow(); } } if (!has_tid) { dummyid.mvtype = MV_STR; dummyid.str.len = 0; tid->operand[0] = put_lit(&dummyid); } tid->operand[1] = put_tref(varlst); ref = newtriple(OC_TSTART); ref->operand[0] = put_ilit(has_ser); ref->operand[1] = put_tref(tid); return TRUE; } fis-gtm-V6.0-003/sr_port/m_use.c0000644000032200000250000000346712201176160015314 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "io_params.h" #include "indir_enum.h" #include "advancewindow.h" #include "cmd.h" #include "deviceparameters.h" int m_use(void) { boolean_t inddevparms; static readonly unsigned char empty_plist[1] = { iop_eol }; int rval; oprtype sopr, plist, devpopr; triple *indref, *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; inddevparms = FALSE; if (EXPR_FAIL == (rval = expr(&sopr, MUMPS_STR))) /* NOTE assignment */ return FALSE; if (TK_COLON != TREF(window_token)) { /* Single parameter */ if (EXPR_INDR == rval) { /* Indirect entire parameter list */ make_commarg(&sopr, indir_use); return TRUE; } else /* default device parms */ plist = put_str((char *)empty_plist, SIZEOF(empty_plist)); } else { /* Have device parms. Determine type */ advancewindow(); if (TK_ATSIGN == TREF(window_token)) { /* Have indirect device parms */ if (!indirection(&devpopr)) return FALSE; indref = newtriple(OC_INDDEVPARMS); indref->operand[0] = devpopr; indref->operand[1] = put_ilit(IOP_USE_OK); inddevparms = TRUE; } else { /* Process device parameters now */ if (!deviceparameters(&plist, IOP_USE_OK)) return FALSE; } } ref = newtriple(OC_USE); ref->operand[0] = sopr; ref->operand[1] = !inddevparms ? plist : put_tref(indref); return TRUE; } fis-gtm-V6.0-003/sr_port/m_view.c0000644000032200000250000000316112201176160015461 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "toktyp.h" #include "opcode.h" #include "indir_enum.h" #include "advancewindow.h" #include "cmd.h" error_def(ERR_FCHARMAXARGS); int m_view(void) { oprtype argv[CHARMAXARGS], *argp; unsigned short count; triple *view, *parm, *parm1; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; argp = &argv[0]; count = 0; switch (expr(argp, MUMPS_EXPR)) { case EXPR_FAIL: return FALSE; case EXPR_INDR: if (TK_COLON != TREF(window_token)) { make_commarg(argp, indir_view); return TRUE; } /* caution: fall through */ case EXPR_GOOD: view = maketriple(OC_VIEW); parm = newtriple(OC_PARAMETER); view->operand[1] = put_tref(parm); parm->operand[0] = *argp; count++; argp++; break; } for (;;) { if (TK_COLON != TREF(window_token)) break; advancewindow(); if (EXPR_FAIL == expr(argp, MUMPS_EXPR)) return FALSE; parm1 = newtriple(OC_PARAMETER); parm->operand[1] = put_tref(parm1); parm1->operand[0] = *argp; parm = parm1; count++; argp++; if (CHARMAXARGS <= count) { stx_error(ERR_FCHARMAXARGS); return FALSE; } } view->operand[0] = put_ilit(count); ins_triple(view); return TRUE; } fis-gtm-V6.0-003/sr_port/m_write.c0000644000032200000250000000642612201176160015650 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "compiler.h" #include "stringpool.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "advancewindow.h" #include "cmd.h" #include "rwformat.h" GBLREF spdesc stringpool; GBLREF bool devctlexp; error_def(ERR_STRINGOFLOW); #define STO_LLPTR(X) (llptr ? *++llptr = (X) : 0) #define LITLST_TOP (&litlst[(SIZEOF(litlst) / SIZEOF(triple *)) - 2]) int m_write(void) { char *cp; int lnx; mval lit; mstr *msp; oprtype *oprptr, x; triple *litlst[128], **llptr, **ltop, **ptx, *ref, *t1; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; llptr = litlst; ltop = 0; *llptr = 0; for (;;) { devctlexp = FALSE; switch (TREF(window_token)) { case TK_ASTERISK: advancewindow(); if (EXPR_FAIL == expr(&x, MUMPS_INT)) return FALSE; assert(TRIP_REF == x.oprclass); ref = newtriple(OC_WTONE); ref->operand[0] = x; STO_LLPTR((OC_ILIT == x.oprval.tref->opcode) ? ref : 0); break; case TK_QUESTION: case TK_EXCLAIMATION: case TK_HASH: case TK_SLASH: if (!rwformat()) return FALSE; STO_LLPTR(0); break; default: switch (expr(&x, MUMPS_STR)) { case EXPR_FAIL: return FALSE; case EXPR_GOOD: assert(TRIP_REF == x.oprclass); if (devctlexp) { ref = newtriple(OC_WRITE); ref->operand[0] = x; STO_LLPTR(0); } else if (x.oprval.tref->opcode == OC_CAT) wrtcatopt(x.oprval.tref, &llptr, LITLST_TOP); else { ref = newtriple(OC_WRITE); ref->operand[0] = x; STO_LLPTR((OC_LIT == x.oprval.tref->opcode) ? ref : 0); } break; case EXPR_INDR: make_commarg(&x, indir_write); STO_LLPTR(0); break; default: assert(FALSE); } break; } if (TK_COMMA != TREF(window_token)) break; advancewindow(); if (LITLST_TOP <= llptr) { *++llptr = 0; ltop = llptr; llptr = 0; } } STO_LLPTR(0); if (ltop) llptr = ltop; for (ptx = litlst ; ptx < llptr ; ptx++) { if (*ptx && *(ptx + 1)) { lit.mvtype = MV_STR; lit.str.addr = cp = (char *)stringpool.free; for (t1 = ref = *ptx++ ; ref ; ref = *ptx++) { if (OC_WRITE == ref->opcode) { msp = &(ref->operand[0].oprval.tref->operand[0].oprval.mlit->v.str); lnx = msp->len; ENSURE_STP_FREE_SPACE(lnx); memcpy(cp, msp->addr, lnx); cp += lnx; } else { assert(OC_WTONE == ref->opcode); ENSURE_STP_FREE_SPACE(1); *cp++ = ref->operand[0].oprval.tref->operand[0].oprval.ilit; } ref->operand[0].oprval.tref->opcode = OC_NOOP; ref->opcode = OC_NOOP; ref->operand[0].oprval.tref->operand[0].oprclass = OC_NOOP; ref->operand[0].oprclass = NO_REF; } ptx--; stringpool.free = (unsigned char *) cp; lit.str.len = INTCAST(cp - lit.str.addr); s2n(&lit); t1->opcode = OC_WRITE; t1->operand[0] = put_lit(&lit); } } return TRUE; } fis-gtm-V6.0-003/sr_port/m_xecute.c0000644000032200000250000000405512201176160016007 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "mdq.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "mmemory.h" #include "advancewindow.h" #include "cmd.h" int m_xecute(void) { oprtype *cr, x; triple *obp, *oldchain, *ref0, *ref1, tmpchain, *triptr; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; dqinit(&tmpchain,exorder); oldchain = setcurtchain(&tmpchain); switch (expr(&x, MUMPS_STR)) { case EXPR_FAIL: setcurtchain(oldchain); return FALSE; case EXPR_INDR: if (TK_COLON != TREF(window_token)) { make_commarg(&x,indir_xecute); break; } /* caution: fall through */ case EXPR_GOOD: ref0 = maketriple(OC_COMMARG); ref0->operand[0] = x; ref0->operand[1] = put_ilit(indir_linetail); ins_triple(ref0); } setcurtchain(oldchain); if (TK_COLON == TREF(window_token)) { advancewindow(); cr = (oprtype *)mcalloc(SIZEOF(oprtype)); if (!bool_expr(FALSE, cr)) return FALSE; if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(TREF(expr_start)); } obp = oldchain->exorder.bl; dqadd(obp,&tmpchain,exorder); /* violates info hiding */ if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { ref0 = newtriple(OC_JMP); ref1 = newtriple(OC_GVRECTARG); ref1->operand[0] = put_tref(TREF(expr_start)); *cr = put_tjmp(ref1); tnxtarg(&ref0->operand[0]); } else tnxtarg(cr); return TRUE; } obp = oldchain->exorder.bl; dqadd(obp,&tmpchain,exorder); /* violates info hiding */ return TRUE; } fis-gtm-V6.0-003/sr_port/m_zallocate.c0000644000032200000250000000345112201176160016467 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "iotimer.h" #include "indir_enum.h" #include "advancewindow.h" #include "cmd.h" error_def(ERR_RPARENMISSING); int m_zallocate(void) { boolean_t indirect; oprtype indopr; triple *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; newtriple(OC_RESTARTPC); indirect = FALSE; newtriple(OC_LKINIT); switch (TREF(window_token)) { case TK_ATSIGN: if (!indirection(&indopr)) return FALSE; ref = newtriple(OC_COMMARG); ref->operand[0] = indopr; if (TK_COLON != TREF(window_token)) { ref->operand[1] = put_ilit((mint)indir_zallocate); return TRUE; } ref->operand[1] = put_ilit((mint)indir_nref); indirect = TRUE; break; case TK_LPAREN: do { advancewindow(); if (EXPR_FAIL == nref()) return FALSE; } while (TK_COMMA == TREF(window_token)); if (TK_RPAREN != TREF(window_token)) { stx_error(ERR_RPARENMISSING); return FALSE; } advancewindow(); break; default: if (EXPR_FAIL == nref()) return FALSE; break; } ref = maketriple(OC_ZALLOCATE); if (TK_COLON != TREF(window_token)) { ref->operand[0] = put_ilit(NO_M_TIMEOUT); ins_triple(ref); } else { advancewindow(); if (EXPR_FAIL == expr(&(ref->operand[0]), MUMPS_INT)) return EXPR_FAIL; ins_triple(ref); newtriple(OC_TIMTRU); } return EXPR_GOOD; } fis-gtm-V6.0-003/sr_port/m_zattach.c0000644000032200000250000000223012201176160016141 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "cmd.h" int m_zattach(void) { oprtype x; triple *triptr; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if ((TK_EOL == TREF(window_token)) || (TK_SPACE == TREF(window_token))) { triptr = newtriple(OC_ZATTACH); triptr->operand[0] = put_str("",0); return TRUE; } else { switch (expr(&x, MUMPS_STR)) { case EXPR_FAIL: return FALSE; case EXPR_GOOD: triptr = newtriple(OC_ZATTACH); triptr->operand[0] = x; return TRUE; case EXPR_INDR: make_commarg(&x,indir_zattach); return TRUE; } } return FALSE; /* This should never get executed, added to make compiler happy */ } fis-gtm-V6.0-003/sr_port/m_zbreak.c0000644000032200000250000000666312201176160015777 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "advancewindow.h" #include "cmd.h" #define CANCEL_ONE -1 #define CANCEL_ALL -2 GBLREF boolean_t run_time; GBLREF mident routine_name; LITREF mident zero_ident; error_def(ERR_LABELEXPECTED); error_def(ERR_RTNNAME); int m_zbreak(void) { boolean_t cancel, cancel_all, dummybool, is_count; oprtype action, count, label, offset, routine; triple *next, *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; label = put_str((char *)zero_ident.addr, zero_ident.len); cancel_all = FALSE; action = put_str("B", 1); if (TK_MINUS == TREF(window_token)) { advancewindow(); cancel = TRUE; count = put_ilit((mint)CANCEL_ONE); } else { cancel = FALSE; count = put_ilit((mint)0); } if (TK_ASTERISK == TREF(window_token)) { if (cancel) { advancewindow(); cancel_all = TRUE; if (!run_time) routine = put_str(routine_name.addr, routine_name.len); else routine = put_tref(newtriple(OC_CURRTN)); offset = put_ilit((mint) 0); count = put_ilit((mint) CANCEL_ALL); } else { stx_error(ERR_LABELEXPECTED); return FALSE; } } else { offset = put_ilit((mint) 0); if (!lref(&label,&offset, TRUE, indir_zbreak, !cancel, &dummybool)) return FALSE; if (label.oprclass == TRIP_REF && label.oprval.tref->opcode == OC_COMMARG) return TRUE; if (TK_CIRCUMFLEX != TREF(window_token)) { /* Routine not specified, assume current routine */ if (!run_time) routine = put_str(routine_name.addr, routine_name.len); else routine = put_tref(newtriple(OC_CURRTN)); } else { advancewindow(); switch (TREF(window_token)) { case TK_IDENT: # ifdef GTM_TRIGGER if (TK_HASH == TREF(director_token)) /* Coagulate tokens as necessary (and available) to allow '#' in the rtn name */ advwindw_hash_in_mname_allowed(); # endif routine = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); advancewindow(); break; case TK_ATSIGN: if (!indirection(&routine)) return FALSE; break; default: stx_error(ERR_RTNNAME); return FALSE; } } if (!cancel && (TK_COLON == TREF(window_token))) { advancewindow(); if (TK_COLON == TREF(window_token)) { is_count = TRUE; action = put_str("B",1); } else { if (EXPR_FAIL == expr(&action, MUMPS_STR)) return FALSE; is_count = (TK_COLON == TREF(window_token)); } if (is_count) { advancewindow(); if (EXPR_FAIL == expr(&count, MUMPS_INT)) return FALSE; } } } ref = newtriple(OC_SETZBRK); ref->operand[0] = label; next = newtriple(OC_PARAMETER); ref->operand[1] = put_tref(next); next->operand[0] = offset; ref = newtriple(OC_PARAMETER); next->operand[1] = put_tref(ref); ref->operand[0] = routine; next = newtriple(OC_PARAMETER); ref->operand[1] = put_tref(next); next->operand[0] = action; ref = newtriple(OC_PARAMETER); next->operand[1] = put_tref(ref); ref->operand[0] = count; return TRUE; } fis-gtm-V6.0-003/sr_port/m_zcompile.c0000644000032200000250000000145112201176160016331 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "cmd.h" int m_zcompile(void) { triple *triptr; oprtype x; if(EXPR_FAIL == expr(&x, MUMPS_STR)) return FALSE; triptr = newtriple(OC_ZCOMPILE); triptr->operand[0] = x; triptr->operand[1] = put_ilit(FALSE); /* ignore_dollar_zcompile arg */ return TRUE; } fis-gtm-V6.0-003/sr_port/m_zcontinue.c0000644000032200000250000000115512201176160016526 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "cmd.h" int m_zcontinue(void) { oprtype x; newtriple(OC_ZCONT); return TRUE; } fis-gtm-V6.0-003/sr_port/m_zdeallocate.c0000644000032200000250000000271212201176160016777 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "iotimer.h" #include "indir_enum.h" #include "advancewindow.h" #include "cmd.h" error_def(ERR_RPARENMISSING); int m_zdeallocate(void) { oprtype indopr; triple *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; newtriple(OC_LKINIT); switch(TREF(window_token)) { case TK_EOL: case TK_SPACE: break; case TK_ATSIGN: if (!indirection(&indopr)) return FALSE; ref = newtriple(OC_COMMARG); ref->operand[0] = indopr; ref->operand[1] = put_ilit((mint)indir_zdeallocate); return TRUE; break; case TK_LPAREN: do { advancewindow(); if (EXPR_FAIL == nref()) return FALSE; } while (TK_COMMA == TREF(window_token)); if (TK_RPAREN != TREF(window_token)) { stx_error(ERR_RPARENMISSING); return FALSE; } advancewindow(); break; default: if (EXPR_FAIL == nref()) return FALSE; break; } ref = newtriple(OC_ZDEALLOCATE); ref->operand[0] = put_ilit(NO_M_TIMEOUT); return EXPR_GOOD; } fis-gtm-V6.0-003/sr_port/m_zedit.c0000644000032200000250000000302612201176160015626 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "svnames.h" #include "advancewindow.h" #include "cmd.h" int m_zedit(void) { int rval; oprtype file,opts; triple *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if ((TK_EOL == TREF(window_token)) || (TK_SPACE == TREF(window_token)) || (TK_COLON == TREF(window_token))) { ref = newtriple(OC_SVGET); ref->operand[0] = put_ilit(SV_ZSOURCE); file = put_tref(ref); if (TK_COLON == TREF(window_token)) { advancewindow(); if (EXPR_FAIL == expr(&opts, MUMPS_STR)) return FALSE; } else opts = put_str("",0); } else { if (EXPR_FAIL == (rval = expr(&file, MUMPS_STR))) /* NOTE assignment */ return FALSE; if (TK_COLON != TREF(window_token)) { if (EXPR_INDR == rval) { make_commarg(&file,indir_zedit); return TRUE; } opts = put_str("",0); } else { advancewindow(); if (EXPR_FAIL == expr(&opts, MUMPS_STR)) return FALSE; } } ref = newtriple(OC_ZEDIT); ref->operand[0] = file; ref->operand[1] = opts; return TRUE; } fis-gtm-V6.0-003/sr_port/m_zgoto.c0000644000032200000250000000633012201176160015652 0ustar librarygtc/**************************************************************** * * * Copyright 2010, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "mdq.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "mmemory.h" #include "advancewindow.h" #include "cmd.h" error_def(ERR_COLON); int m_zgoto(void) { int rval; oprtype *cr, quits; triple *obp, *oldchain, *ref0, *ref1, tmpchain, *triptr; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; dqinit(&tmpchain, exorder); oldchain = setcurtchain(&tmpchain); if ((TK_EOL == TREF(window_token)) || (TK_SPACE == TREF(window_token))) { /* Default zgoto level is 1 */ quits = put_ilit(1); rval = EXPR_GOOD; } else if (EXPR_FAIL == (rval = expr(&quits, MUMPS_INT))) /* NOTE assignment */ { setcurtchain(oldchain); return FALSE; } if ((EXPR_INDR != rval) && ((TK_EOL == TREF(window_token)) || (TK_SPACE == TREF(window_token)))) { /* Only level parm supplied (no entry ref) - job for op_zg1 */ setcurtchain(oldchain); obp = oldchain->exorder.bl; dqadd(obp, &tmpchain, exorder); /* this is a violation of info hiding */ ref0 = newtriple(OC_ZG1); ref0->operand[0] = quits; return TRUE; } if (TK_COLON != TREF(window_token)) { /* First arg parsed, not ending in ":". Better have been indirect */ setcurtchain(oldchain); if (EXPR_INDR != rval) { stx_error(ERR_COLON); return FALSE; } make_commarg(&quits, indir_zgoto); obp = oldchain->exorder.bl; dqadd(obp, &tmpchain, exorder); /* this is a violation of info hiding */ return TRUE; } advancewindow(); if (TK_COLON != TREF(window_token)) { if (!entryref(OC_NOOP, OC_PARAMETER, (mint)indir_goto, FALSE, FALSE, TRUE)) { setcurtchain(oldchain); return FALSE; } ref0 = maketriple(OC_ZGOTO); ref0->operand[0] = quits; ref0->operand[1] = put_tref(tmpchain.exorder.bl); ins_triple(ref0); setcurtchain(oldchain); } else { ref0 = maketriple(OC_ZG1); ref0->operand[0] = quits; ins_triple(ref0); setcurtchain(oldchain); } if (TK_COLON == TREF(window_token)) { /* post conditional expression */ advancewindow(); cr = (oprtype *)mcalloc(SIZEOF(oprtype)); if (!bool_expr(FALSE, cr)) return FALSE; if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { triptr = newtriple(OC_GVRECTARG); triptr->operand[0] = put_tref(TREF(expr_start)); } obp = oldchain->exorder.bl; dqadd(obp, &tmpchain, exorder); /* this is a violation of info hiding */ if ((TREF(expr_start) != TREF(expr_start_orig)) && (OC_NOOP != (TREF(expr_start))->opcode)) { ref0 = newtriple(OC_JMP); ref1 = newtriple(OC_GVRECTARG); ref1->operand[0] = put_tref(TREF(expr_start)); *cr = put_tjmp(ref1); tnxtarg(&ref0->operand[0]); } else tnxtarg(cr); return TRUE; } obp = oldchain->exorder.bl; dqadd(obp, &tmpchain, exorder); /* this is a violation of info hiding */ return TRUE; } fis-gtm-V6.0-003/sr_port/m_zhalt.c0000644000032200000250000000261212201176160015631 0ustar librarygtc/**************************************************************** * * * Copyright 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "cmd.h" #include "compiler.h" #include "indir_enum.h" #include "opcode.h" #include "toktyp.h" LITREF mval literal_zero; /* Halt the process similar to op_halt but allow a return code to be specified. If no return code * is specified, return code 0 is used as a default (making it identical to op_halt). */ int m_zhalt(void) { triple *triptr; oprtype ot; int status; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; /* Let m_halt() handle the case of the missing return code */ if ((TK_SPACE == TREF(window_token)) || (TK_EOL == TREF(window_token))) return m_halt(); switch (status = expr(&ot, MUMPS_NUM)) /* NOTE assignment */ { case EXPR_FAIL: return FALSE; case EXPR_GOOD: triptr = newtriple(OC_ZHALT); triptr->operand[0] = ot; return TRUE; case EXPR_INDR: make_commarg(&ot, indir_zhalt); return TRUE; default: GTMASSERT; } return FALSE; /* This should never get executed, added to make compiler happy */ } fis-gtm-V6.0-003/sr_port/m_zhelp.c0000644000032200000250000000266712201176160015643 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "advancewindow.h" #include "cmd.h" int m_zhelp (void) { int rval; oprtype lib, text; triple *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if ((TK_EOL == TREF(window_token)) || (TK_SPACE == TREF(window_token)) || (TK_COLON == TREF(window_token))) { text = put_str("",0); if (TK_COLON == TREF(window_token)) { advancewindow(); if (EXPR_FAIL == expr(&lib, MUMPS_STR)) return FALSE; } else lib = put_str("",0); } else { if (EXPR_FAIL == (rval = expr(&text, MUMPS_STR))) /* NOTE asignment */ return FALSE; if (TK_COLON != TREF(window_token)) { if (EXPR_INDR == rval) { make_commarg(&text,indir_zhelp); return TRUE; } lib = put_str("",0); } else { advancewindow(); if (EXPR_FAIL == expr(&lib, MUMPS_STR)) return FALSE; } } ref = newtriple(OC_ZHELP); ref->operand[0] = text; ref->operand[1] = lib; return TRUE; } fis-gtm-V6.0-003/sr_port/m_zinvcmd.c0000644000032200000250000000257412201176160016170 0ustar librarygtc/**************************************************************** * * * Copyright 2011, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "advancewindow.h" #include "cmd.h" #include "error.h" error_def(ERR_INVCMD); /* Consume and ignore the arguments, and insert an INVCMD error triple. * Previously, we raised an error immediately when the invalid command was * detected, but since a false postconditional may skip the error and * continue executing the line, we need to parse it properly. */ int m_zinvcmd(void) { triple *triptr; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; while ((TK_EOL != TREF(window_token)) && (TK_SPACE != TREF(window_token)) && (TK_ERROR != TREF(window_token))) advancewindow(); if (TK_ERROR == TREF(window_token)) return FALSE; triptr = newtriple(OC_RTERROR); triptr->operand[0] = put_ilit(MAKE_MSG_TYPE(ERR_INVCMD, ERROR)); /* switch from warning to error */ triptr->operand[1] = put_ilit(FALSE); /* not a subroutine reference */ return TRUE; } fis-gtm-V6.0-003/sr_port/m_zlink.c0000644000032200000250000000327112201176160015640 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "svnames.h" #include "advancewindow.h" #include "cmd.h" int m_zlink(void) { int rval; oprtype file, quals; triple *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if ((TK_EOL == TREF(window_token)) || (TK_SPACE == TREF(window_token)) || (TK_COLON == TREF(window_token))) { ref = newtriple(OC_SVGET); ref->operand[0] = put_ilit(SV_ZSOURCE); file = put_tref(ref); if (TK_COLON == TREF(window_token)) { advancewindow(); if (EXPR_FAIL == expr(&quals, MUMPS_STR)) return FALSE; } else { ref = newtriple(OC_SVGET); ref->operand[0] = put_ilit(SV_ZCOMPILE); quals = put_tref(ref); } } else { if (EXPR_FAIL == (rval = expr(&file, MUMPS_STR))) /* NOTE assignment */ return FALSE; if (TK_COLON != TREF(window_token)) { if (EXPR_INDR == rval) { make_commarg(&file, indir_zlink); return TRUE; } ref = newtriple(OC_SVGET); ref->operand[0] = put_ilit(SV_ZCOMPILE); quals = put_tref(ref); } else { advancewindow(); if (EXPR_FAIL == expr(&quals, MUMPS_STR)) return FALSE; } } ref = newtriple(OC_ZLINK); ref->operand[0] = file; ref->operand[1] = quals; return TRUE; } fis-gtm-V6.0-003/sr_port/m_zmessage.c0000644000032200000250000000250512201176160016326 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "advancewindow.h" #include "cmd.h" int m_zmessage (void) { int count; oprtype code, arg; triple *ref0, *ref1; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; switch (expr(&code, MUMPS_INT)) { case EXPR_FAIL: return FALSE; case EXPR_INDR: if (TK_COLON != TREF(window_token)) make_commarg (&code, indir_zmess); } ref0 = newtriple(OC_PARAMETER); ref0->operand[0] = code; ref1 = ref0; for (count = 1; TK_COLON == TREF(window_token); count++) { advancewindow(); if (EXPR_FAIL == expr(&arg, MUMPS_EXPR)) return FALSE; ref1->operand[1] = put_tref(newtriple(OC_PARAMETER)); ref1 = ref1->operand[1].oprval.tref; ref1->operand[0] = arg; } ref1 = newtriple(OC_ZMESS); ref1->operand[0] = put_ilit(count); ref1->operand[1] = put_tref(ref0); return TRUE; } fis-gtm-V6.0-003/sr_port/m_zprint.c0000644000032200000250000000540612201176160016041 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "advancewindow.h" #include "cmd.h" GBLREF boolean_t run_time; GBLREF mident routine_name; LITREF mident zero_ident; error_def(ERR_LABELEXPECTED); error_def(ERR_RTNNAME); int m_zprint(void) { boolean_t got_some; oprtype lab1, lab2, off1, off2, rtn; triple *next, *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; got_some = FALSE; lab1 = put_str(zero_ident.addr, zero_ident.len); off1 = put_ilit(0); if ((TK_EOL != TREF(window_token)) && (TK_SPACE != TREF(window_token)) && !lref(&lab1, &off1, TRUE, indir_zprint, TRUE, &got_some)) return FALSE; if ((TRIP_REF == lab1.oprclass) && (OC_COMMARG == lab1.oprval.tref->opcode)) return TRUE; if (TK_CIRCUMFLEX != TREF(window_token)) { /* Routine not specified, use current routine */ if (!run_time) rtn = put_str(routine_name.addr, routine_name.len); else rtn = put_tref(newtriple(OC_CURRTN)); } else { got_some = TRUE; advancewindow(); switch (TREF(window_token)) { case TK_IDENT: # ifdef GTM_TRIGGER if (TK_HASH == TREF(director_token)) /* Coagulate tokens as necessary (and available) to allow '#' in the rtn name */ advwindw_hash_in_mname_allowed(); # endif rtn = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); advancewindow(); break; case TK_ATSIGN: if (!indirection(&rtn)) return FALSE; break; default: stx_error(ERR_RTNNAME); return FALSE; } } if (TK_COLON == TREF(window_token)) { if (!got_some) { stx_error(ERR_LABELEXPECTED); return FALSE; } lab2 = put_str(zero_ident.addr, zero_ident.len); off2 = put_ilit(0); advancewindow(); if (!lref(&lab2, &off2, TRUE, indir_zprint, FALSE, &got_some)) return FALSE; if (!got_some) { stx_error(ERR_LABELEXPECTED); return FALSE; } } else { lab2 = lab1; off2 = off1; } ref = newtriple(OC_ZPRINT); ref->operand[0] = rtn; next = newtriple(OC_PARAMETER); ref->operand[1] = put_tref(next); next->operand[0] = lab1; ref = newtriple(OC_PARAMETER); next->operand[1] = put_tref(ref); ref->operand[0] = off1; next = newtriple(OC_PARAMETER); ref->operand[1] = put_tref(next); next->operand[0] = lab2; ref = newtriple(OC_PARAMETER); next->operand[1] = put_tref(ref); ref->operand[0] = off2; return TRUE; } fis-gtm-V6.0-003/sr_port/m_zshow.c0000644000032200000250000000551112201176160015662 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "mlkdef.h" #include "zshow.h" #include "advancewindow.h" #include "cmd.h" error_def(ERR_VAREXPECTED); int m_zshow(void) { static readonly char def_str[]="S"; int code, rval; oprtype func, output; triple *lvar, *outtype, *r; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if ((TK_SPACE == TREF(window_token)) || (TK_EOL == TREF(window_token)) || (TK_COLON == TREF(window_token))) code = ZSHOW_NOPARM; else { code = ZSHOW_DEVICE; switch (expr(&func, MUMPS_STR)) { case EXPR_FAIL: return FALSE; case EXPR_GOOD: break; case EXPR_INDR: make_commarg(&func,indir_zshow); return TRUE; default: GTMASSERT; } } if (TK_COLON == TREF(window_token)) { advancewindow(); switch (TREF(window_token)) { case TK_CIRCUMFLEX: if (!gvn()) return FALSE; r = maketriple(OC_ZSHOW); outtype = newtriple(OC_PARAMETER); r->operand[1] = put_tref(outtype); if (code == ZSHOW_NOPARM) r->operand[0] = put_str(&def_str[0], (SIZEOF(def_str) - 1)); else r->operand[0] = func; outtype->operand[0] = put_ilit(ZSHOW_GLOBAL); ins_triple(r); return TRUE; case TK_IDENT: if (!lvn(&output, OC_PUTINDX, 0)) { stx_error(ERR_VAREXPECTED); return FALSE; } r = maketriple(OC_ZSHOWLOC); outtype = newtriple(OC_PARAMETER); r->operand[1] = put_tref(outtype); if (code == ZSHOW_NOPARM) r->operand[0] = put_str(&def_str[0], (SIZEOF(def_str) - 1)); else r->operand[0] = func; lvar = newtriple(OC_PARAMETER); outtype->operand[1] = put_tref(lvar); lvar->operand[0] = output; outtype->operand[0] = put_ilit(ZSHOW_LOCAL); ins_triple(r); return TRUE; case TK_ATSIGN: if (!indirection(&output)) { stx_error(ERR_VAREXPECTED); return FALSE; } r = newtriple(OC_INDRZSHOW); if (code == ZSHOW_NOPARM) r->operand[0] = put_str(&def_str[0], (SIZEOF(def_str) - 1)); else r->operand[0] = func; r->operand[1] = output; return TRUE; default: stx_error(ERR_VAREXPECTED); return FALSE; } } r = maketriple(OC_ZSHOW); outtype = newtriple(OC_PARAMETER); r->operand[1] = put_tref(outtype); if (code == ZSHOW_NOPARM) r->operand[0] = put_str(&def_str[0], (SIZEOF(def_str) - 1)); else r->operand[0] = func; outtype->operand[0] = put_ilit(ZSHOW_DEVICE); ins_triple(r); return TRUE; } fis-gtm-V6.0-003/sr_port/m_zstep.c0000644000032200000250000000401712201176160015655 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "zstep.h" #include "toktyp.h" #include "nametabtyp.h" #include "mdq.h" #include "advancewindow.h" #include "cmd.h" #include "namelook.h" GBLREF short int source_column; error_def(ERR_INVZSTEP); error_def(ERR_ZSTEPARG); static readonly nametabent zstep_names[] = { { 1, "I"}, { 4, "INTO"} ,{ 2,"OU" }, { 5,"OUTOF" } ,{ 2,"OV" }, { 4,"OVER" } }; static readonly unsigned char zstep_index[27] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2 ,2, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6 ,6, 6, 6 }; static readonly char zstep_type[]={ ZSTEP_INTO, ZSTEP_INTO, ZSTEP_OUTOF, ZSTEP_OUTOF, ZSTEP_OVER, ZSTEP_OVER }; int m_zstep(void) { char type; int x; oprtype action; opctype op; triple *head; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert((SIZEOF(zstep_names) / SIZEOF(nametabent)) == zstep_index[26]); op = OC_ZSTEP; switch (TREF(window_token)) { case TK_SPACE: case TK_EOL: type = ZSTEP_OVER; break; case TK_IDENT: if (0 > (x = namelook(zstep_index, zstep_names, (TREF(window_ident)).addr, (TREF(window_ident)).len))) { /* NOTE assignment above*/ stx_error(ERR_INVZSTEP); return FALSE; } type = zstep_type[x]; advancewindow(); break; default: stx_error(ERR_ZSTEPARG); return FALSE; break; } if (TK_COLON == TREF(window_token)) { advancewindow(); if (EXPR_FAIL == expr(&action, MUMPS_EXPR)) return FALSE; op = OC_ZSTEPACT; } head = maketriple(op); head->operand[0] = put_ilit(type); if (OC_ZSTEPACT == op) head->operand[1] = action; ins_triple(head); return TRUE; } fis-gtm-V6.0-003/sr_port/m_zsystem.c0000644000032200000250000000220512201176160016223 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "cmd.h" int m_zsystem(void) { oprtype x; triple *triptr; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if ((TK_EOL == TREF(window_token)) || (TK_SPACE == TREF(window_token))) { triptr = newtriple(OC_ZSYSTEM); triptr->operand[0] = put_str("",0); return TRUE; } else switch (expr(&x, MUMPS_STR)) { case EXPR_FAIL: return FALSE; case EXPR_GOOD: triptr = newtriple(OC_ZSYSTEM); triptr->operand[0] = x; return TRUE; case EXPR_INDR: make_commarg(&x, indir_zsystem); return TRUE; } return FALSE; /* This will never get executed, added to make compiler happy */ } fis-gtm-V6.0-003/sr_port/m_ztcommit.c0000644000032200000250000000163412201176160016360 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "cmd.h" int m_ztcommit(void) { triple *head; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; head = maketriple(OC_ZTCOMMIT); if ((TK_EOL == TREF(window_token)) || (TK_SPACE == TREF(window_token))) { head->operand[0] = put_ilit(1); ins_triple(head); return TRUE; } if (EXPR_FAIL == expr(&head->operand[0], MUMPS_INT)) return FALSE; ins_triple(head); return TRUE; } fis-gtm-V6.0-003/sr_port/m_ztstart.c0000644000032200000250000000145012201176160016221 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "toktyp.h" #include "cmd.h" error_def(ERR_SPOREOL); int m_ztstart(void) { DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if ((TK_EOL != TREF(window_token)) && (TK_SPACE != TREF(window_token))) { stx_error(ERR_SPOREOL); return FALSE; } newtriple(OC_ZTSTART); return TRUE; } fis-gtm-V6.0-003/sr_port/m_zwatch.c0000644000032200000250000000534512201176160016015 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "advancewindow.h" #include "cmd.h" #define CANCEL_ONE -1 #define CANCEL_ALL -2 LITREF mident zero_ident; error_def(ERR_VAREXPECTED); int m_zwatch(void) { boolean_t is_count; opctype op; oprtype count, name,action; triple *next, *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; if (TK_MINUS == TREF(window_token)) { advancewindow(); switch (TREF(window_token)) { case TK_ASTERISK: name = put_str(zero_ident.addr, zero_ident.len); count = put_ilit(CANCEL_ALL); advancewindow(); break; case TK_IDENT: name = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); count = put_ilit(CANCEL_ONE); advancewindow(); break; case TK_ATSIGN: if (!indirection(&name)) return FALSE; count = put_ilit(CANCEL_ONE); break; default: stx_error(ERR_VAREXPECTED); return FALSE; } action = put_str("",0); op = OC_WATCHREF; } else { if (TK_EQUAL == TREF(window_token)) { advancewindow(); op = OC_WATCHMOD; } else op = OC_WATCHREF; switch (TREF(window_token)) { case TK_IDENT: name = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); advancewindow(); break; case TK_ATSIGN: if (!indirection(&name)) return FALSE; if ((OC_WATCHREF == op) && (TK_COLON != TREF(window_token))) { ref = maketriple(OC_COMMARG); ref->operand[0] = name; ref->operand[1] = put_ilit((mint) indir_zwatch); ins_triple(ref); return TRUE; } break; default: stx_error(ERR_VAREXPECTED); return FALSE; } if (TK_COLON != TREF(window_token)) { action = put_str("",0); count = put_ilit(0); } else { advancewindow(); if (TK_COLON == TREF(window_token)) { is_count = TRUE; action = put_str("", 0); } else { if (EXPR_FAIL == expr(&action, MUMPS_STR)) return FALSE; is_count = (TK_COLON == TREF(window_token)); } if (is_count) { advancewindow(); if (EXPR_FAIL == expr(&count, MUMPS_INT)) return FALSE; } else count = put_ilit(0); } } ref = newtriple(op); ref->operand[0] = name; next = newtriple(OC_PARAMETER); ref->operand[1] = put_tref(next); next->operand[0] = action; next->operand[1] = count; return TRUE; } fis-gtm-V6.0-003/sr_port/m_zwithdraw.c0000644000032200000250000000235612201176160016537 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "indir_enum.h" #include "toktyp.h" #include "cmd.h" error_def(ERR_VAREXPECTED); int m_zwithdraw(void) { oprtype tmparg; triple *ref; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; switch (TREF(window_token)) { case TK_IDENT: if (!lvn(&tmparg,OC_SRCHINDX,0)) return FALSE; ref = newtriple(OC_LVZWITHDRAW); ref->operand[0] = tmparg; break; case TK_CIRCUMFLEX: if (!gvn()) return FALSE; ref = newtriple(OC_GVZWITHDRAW); break; case TK_ATSIGN: if (!indirection(&tmparg)) return FALSE; ref = maketriple(OC_COMMARG); ref->operand[0] = tmparg; ref->operand[1] = put_ilit((mint) indir_zwithdraw); ins_triple(ref); return TRUE; default: stx_error(ERR_VAREXPECTED); return FALSE; } return TRUE; } fis-gtm-V6.0-003/sr_port/m_zwrite.c0000644000032200000250000002046212201176160016036 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "mdq.h" #include "opcode.h" #include "nametabtyp.h" #include "indir_enum.h" #include "gdsroot.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "zwrite.h" #include "toktyp.h" #include "svnames.h" #include "funsvn.h" #include "advancewindow.h" #include "cmd.h" #include "compile_pattern.h" #include "mvalconv.h" #include "namelook.h" GBLREF short int source_column; GBLREF uint4 pat_everything[]; GBLREF mstr_len_t sizeof_pat_everything; error_def(ERR_COMMA); error_def(ERR_INVSVN); error_def(ERR_RPARENMISSING); error_def(ERR_SVNEXPECTED); error_def(ERR_VAREXPECTED); error_def(ERR_ZWRSPONE); LITREF unsigned char svn_index[]; LITREF nametabent svn_names[]; LITREF svn_data_type svn_data[]; /****** CAUTION !!! ****** * All occurrences of put_lit should be replaced by put_ilit. In order to maintain object * code compatibility, however, this replacement has been preempted by preceding put_lit * with n2s. * -no runtime module looks at anything but nm, so call to n2s is dispensed with. -mwm */ int m_zwrite(void) { boolean_t parse_warn, pat; char c; int index; int4 pcount; /* parameter count */ triple *count, *head, *last, *ref, *ref1; mint code, subscount; mval mv; opctype op; oprtype limit, name; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; subscount = 0; count = 0; pat = FALSE; if (TK_CIRCUMFLEX == TREF(window_token)) { advancewindow(); op = OC_GVZWRITE; } else op = OC_LVZWRITE; switch (TREF(window_token)) { case TK_SPACE: case TK_EOL: if (OC_GVZWRITE == op) { stx_error(ERR_VAREXPECTED); return FALSE; } op = OC_LVPATWRITE; head = maketriple(op); head->operand[0] = put_ilit((mint)3); /* count */ ref1 = newtriple(OC_PARAMETER); head->operand[1] = put_tref(ref1); ref1->operand[0] = put_ilit(0); /* shows not from zshow */ ref = newtriple(OC_PARAMETER); ref1->operand[1] = put_tref(ref); ref->operand[0] = put_str((char *)pat_everything, sizeof_pat_everything); MV_FORCE_MVAL(&mv, ZWRITE_ASTERISK) ; ref->operand[1] = put_lit(&mv); ins_triple(head); return TRUE; case TK_IDENT: name = put_str((TREF(window_ident)).addr, (TREF(window_ident)).len); advancewindow(); break; case TK_DOLLAR: advancewindow(); if ((TK_IDENT != TREF(window_token)) || (OC_GVZWRITE == op)) { stx_error(ERR_SVNEXPECTED); return FALSE; } parse_warn = FALSE; index = namelook(svn_index, svn_names, (TREF(window_ident)).addr, (TREF(window_ident)).len); if (0 > index) { STX_ERROR_WARN(ERR_INVSVN); /* sets "parse_warn" to TRUE */ } else { if (!VALID_SVN(index)) { STX_ERROR_WARN(ERR_FNOTONSYS); /* sets "parse_warn" to TRUE */ } } advancewindow(); switch (TREF(window_token)) { case TK_SPACE: case TK_EOL: case TK_COMMA: if (!parse_warn) { assert(SV_NUM_SV > svn_data[index].opcode); ref = maketriple(OC_ZWRITESVN); ref->operand[0] = put_ilit(svn_data[index].opcode); ins_triple(ref); } else { /* OC_RTERROR triple would have been inserted in curtchain by ins_errtriple * (invoked by stx_error). No need to do anything else. */ assert(OC_RTERROR == (TREF(curtchain))->exorder.bl->exorder.bl->exorder.bl->opcode); } return TRUE; default: stx_error(ERR_SVNEXPECTED); return FALSE; } break; case TK_LPAREN: if (OC_GVZWRITE != op) /* naked reference */ { stx_error(ERR_VAREXPECTED); return FALSE; } name = put_str((TREF(window_ident)).addr, 0); break; case TK_ATSIGN: if (!indirection(&name)) return FALSE; if ((OC_LVZWRITE == op) && (TK_LPAREN != TREF(window_token))) { ref = maketriple(OC_COMMARG); ref->operand[0] = name; ref->operand[1] = put_ilit(indir_zwrite); ins_triple(ref); return TRUE; } ref = newtriple(OC_INDPAT); ref->operand[0] = name; name = put_tref(ref); break; case TK_QUESTION: advancewindow(); source_column = TREF(last_source_column); if (!compile_pattern(&name, FALSE)) return FALSE; if (op == OC_LVZWRITE) op = OC_LVPATWRITE; pat = TRUE; break; default: stx_error(ERR_VAREXPECTED); return FALSE; } head = maketriple(op); last = newtriple(OC_PARAMETER); head->operand[1] = put_tref(last); pcount = 1; if ((OC_LVPATWRITE == op) || (OC_GVZWRITE == op)) { pcount++; last->operand[0] = put_ilit(((OC_GVZWRITE == op)? pat : 0)); ref = newtriple(OC_PARAMETER); last->operand[1] = put_tref(ref); last = ref; if (OC_GVZWRITE == op) { pcount++; count = last; ref = newtriple(OC_PARAMETER); last->operand[1] = put_tref(ref); last = ref; } } last->operand[0] = name; if (TK_LPAREN != TREF(window_token)) { pcount++; if (pat) { MV_FORCE_MVAL(&mv, ZWRITE_END); } else { subscount++ ; MV_FORCE_MVAL(&mv, ZWRITE_ASTERISK); } last->operand[1] = put_lit(&mv); head->operand[0] = put_ilit(pcount); if (count) count->operand[0] = put_ilit(subscount); ins_triple(head); return TRUE; } advancewindow(); for(;;) { ref = newtriple(OC_PARAMETER); last->operand[1] = put_tref(ref); switch (TREF(window_token)) { case TK_RPAREN: dqdel(ref,exorder); advancewindow(); MV_FORCE_MVAL(&mv, ZWRITE_END); last->operand[1] = put_lit(&mv); pcount++; head->operand[0] = put_ilit((mint)pcount); if (count) count->operand[0] = put_ilit(subscount); ins_triple(head); return TRUE; case TK_ASTERISK: dqdel(ref,exorder); advancewindow(); if (TK_RPAREN != TREF(window_token)) { stx_error(ERR_RPARENMISSING); return FALSE; } advancewindow(); MV_FORCE_MVAL(&mv, ZWRITE_ASTERISK); last->operand[1] = put_lit(&mv); pcount++; subscount++; head->operand[0] = put_ilit((mint)pcount); if (count) count->operand[0] = put_ilit(subscount); ins_triple(head); return TRUE; case TK_QUESTION: advancewindow(); source_column = TREF(last_source_column); if (!compile_pattern(&limit, FALSE)) return FALSE; if ((TK_COMMA != TREF(window_token)) && (TK_RPAREN != TREF(window_token))) { stx_error(ERR_ZWRSPONE); return FALSE; } if (TK_COMMA == TREF(window_token)) advancewindow(); subscount++; MV_FORCE_MVAL(&mv, ZWRITE_PATTERN); ref->operand[0] = put_lit(&mv); pcount++; ref1 = newtriple(OC_PARAMETER); ref->operand[1] = put_tref(ref1); ref1->operand[0] = limit; last = ref1; pcount++; continue; case TK_COLON: if (TK_RPAREN != (c = TREF(director_token))) /* NOTE assignment */ { if (TK_COMMA != c) { advancewindow(); MV_FORCE_MVAL(&mv, ZWRITE_UPPER); ref->operand[0] = put_lit(&mv); pcount++; subscount++; break; } advancewindow(); } /* caution: fall through */ case TK_COMMA: advancewindow(); MV_FORCE_MVAL(&mv, ZWRITE_ALL); ref->operand[0] = put_lit(&mv); pcount++; subscount++; last = ref; continue; default: if (EXPR_FAIL == expr(&limit, MUMPS_EXPR)) return FALSE; subscount++; last = newtriple(OC_PARAMETER); ref->operand[1] = put_tref(last); last->operand[0] = limit; pcount++; if (TK_COLON == (c = TREF(window_token))) /* NOTE assignment */ { code = ZWRITE_LOWER; advancewindow(); c = TREF(window_token); } else code = ZWRITE_VAL; switch (c) { case TK_COMMA: advancewindow(); /* caution: fall through */ case TK_RPAREN: MV_FORCE_MVAL(&mv, code) ; ref->operand[0] = put_lit(&mv); pcount++; continue; default: if (code == ZWRITE_VAL) { stx_error(ERR_COMMA); return FALSE; } MV_FORCE_MVAL(&mv, ZWRITE_BOTH) ; ref->operand[0] = put_lit(&mv); pcount++; ref = last; break; } break; } if (EXPR_FAIL == expr(&limit, MUMPS_EXPR)) return FALSE; last = newtriple(OC_PARAMETER); ref->operand[1] = put_tref(last); last->operand[0] = limit; pcount++; if (TK_COMMA == TREF(window_token)) advancewindow(); } } fis-gtm-V6.0-003/sr_port/main_pragma.h0000644000032200000250000000153012201176160016451 0ustar librarygtc/**************************************************************** * * * Copyright 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef MAIN_PRAGMA_included #define MAIN_PRAGMA_included #ifdef __MVS__ #pragma runopts(ENVAR(_BPXK_AUTOCVT=ON)) #pragma runopts(FILETAG(AUTOCVT,AUTOTAG)) #endif #endif /* MAIN_PRAGMA_included */ fis-gtm-V6.0-003/sr_port/make_commarg.c0000644000032200000250000000201112201176160016606 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "opcode.h" #include "mdq.h" #ifdef DEBUG LITREF octabstruct oc_tab[]; #endif void make_commarg(oprtype *x,mint ind) { triple *ref; assert(x->oprclass == TRIP_REF); ref = x->oprval.tref; if (ref->opcode != OC_INDGLVN) { assert(ref->opcode == OC_COMVAL || ref->opcode == OC_COMINT || ref->opcode == OC_COBOOL); dqdel(ref,exorder); assert(ref->operand[0].oprclass == TRIP_REF); ref = ref->operand[0].oprval.tref; assert(ref->opcode == OC_INDGLVN); } ref->opcode = OC_COMMARG; ref->operand[1] = put_ilit(ind); return; } fis-gtm-V6.0-003/sr_port/make_gvsubsc.c0000644000032200000250000000226612201176160016651 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "stringpool.h" #include "gdsroot.h" #include "gdsblk.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "mvalconv.h" GBLREF spdesc stringpool; oprtype make_gvsubsc(mval *v) { mval w; gv_key *gp; ENSURE_STP_FREE_SPACE(MAX_SRCLINE + SIZEOF(gv_key)); if ((INTPTR_T)stringpool.free & 1) stringpool.free++; /* word align key for structure refs */ gp = (gv_key *) stringpool.free; gp->top = MAX_SRCLINE; gp->end = gp->prev = 0; mval2subsc(v,gp); w.mvtype = MV_STR | MV_SUBLIT; w.str.addr = (char *) gp->base; w.str.len = gp->end + 1; stringpool.free = &gp->base[gp->end + 1]; assert(stringpool.free <= stringpool.top); return put_lit(&w); } fis-gtm-V6.0-003/sr_port/maketriple.c0000644000032200000250000000145312201176160016332 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "compiler.h" #include "mdq.h" #include "mmemory.h" GBLREF short int source_line,source_column; triple *maketriple(opctype op) { triple *x; x = (triple *)mcalloc(SIZEOF(triple)); x->opcode = op; x->src.line = source_line; x->src.column = source_column; dqinit(&(x->backptr), que); dqinit(&(x->jmplist), que); return x; } fis-gtm-V6.0-003/sr_port/matchc.c0000644000032200000250000001501612201176160015434 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "matchc.h" #define RETURN_NOMATCH \ { \ *res = 0; \ assert(0 < numpcs_unmatched); \ *numpcs = numpcs_unmatched; \ return src_top; \ } #define RETURN_YESMATCH(RET) \ { \ *res = RET; \ assert(0 == numpcs_unmatched); \ *numpcs = 0; \ return src_ptr; \ } /* * ----------------------------------------------- * Pseudo equivalent of VAX matchc instruction * * Arguments: * del_len - delimiter length * del_str - pointer to delimiter string * src_len - length of source string * src_str - pointer to source string * res - pointer to the result * numpcs - pointer to the number of pieces that are desired to be matched. * * Return: * pointer to next character after match substring * in the source string, if found. Otherwise src_str + src_len. * * Side effects: * set res arg to: * 0 - if match not found * 1 + char_len - if match found, where char_len is the position * of the next character after the match substring. * set numpcs arg to # of pieces that could not be matched (because end of source string was reached before then) * ----------------------------------------------- */ #ifdef UNICODE_SUPPORTED #include "gtm_utf8.h" GBLREF boolean_t gtm_utf8_mode; GBLREF boolean_t badchar_inhibit; /* multi-byte character-oriented substring matching */ unsigned char *matchc(int del_len, unsigned char *del_str, int src_len, unsigned char *src_str, int *res, int *numpcs) { unsigned char *src_ptr, *src_top, *src_next, *del_ptr, *del_top, *del_next, *del_next1, *restart_ptr; wint_t src_cp, del_cp, del_cp1; /* code points for the source and delimiter characters */ int char_len, restart_char_len, del_charlen, bytelen, numpcs_unmatched; if (!gtm_utf8_mode) return matchb(del_len, del_str, src_len, src_str, res, numpcs); assert(0 <= del_len); assert(0 < *numpcs); if (0 == del_len) { /* always matches a null string */ *numpcs = 0; *res = 1; return src_str; } src_ptr = src_str; src_top = src_str + src_len; del_top = del_str + del_len; /* Check UTF8 byte sequence validity of delimiter string. The following code is very similar to utf8_len() but * we dont invoke the function here for performance reasons as this piece of code is used by heavy hitters like $piece. * Also, the code below can be forked off into two cases depending on the value of "badchar_inhibit". This is a * performance enhancement that can be done later if this is found to be a bottleneck. */ if (!badchar_inhibit) { for (del_charlen = 0, del_ptr = del_str; del_ptr < del_top; del_charlen++, del_ptr += bytelen) { if (!UTF8_VALID(del_ptr, del_top, bytelen)) utf8_badchar(0, del_ptr, del_top, 0, NULL); } } numpcs_unmatched = *numpcs; /* note down # of pieces left to match */ /* compute the code point of the 1st delimiter char */ del_next1 = UTF8_MBTOWC(del_str, del_top, del_cp1); assert((WEOF != del_cp1) || badchar_inhibit); for (char_len = 0; (src_ptr < src_top) && (src_top - src_ptr) >= del_len; ) { src_next = src_ptr; do { /* find the occurrence of 1st delimiter char in the source */ src_ptr = src_next; src_next = UTF8_MBTOWC(src_ptr, src_top, src_cp); if ((WEOF == src_cp) && !badchar_inhibit) utf8_badchar(0, src_ptr, src_top, 0, NULL); ++char_len; /* maintain the source character position */ } while ((src_next < src_top) && ((src_cp != del_cp1) || ((WEOF == src_cp) && (*src_ptr != *del_str)))); if ((src_cp != del_cp1) || (WEOF == src_cp) && (*src_ptr != *del_str)) { /* could not find the 1st delimiter char in the source */ RETURN_NOMATCH; } /* 1st delimiter character match found. match the other delimiter characters */ del_ptr = del_next1; /* advance past the 1st delimiter character */ restart_ptr = src_ptr = src_next; /* advance past the 1st source character */ restart_char_len = char_len; for ( ; (src_ptr < src_top) && (del_ptr < del_top); src_ptr = src_next, del_ptr = del_next, ++char_len) { src_next = UTF8_MBTOWC(src_ptr, src_top, src_cp); if ((WEOF == src_cp) && !badchar_inhibit) utf8_badchar(0, src_ptr, src_top, 0, NULL); del_next = UTF8_MBTOWC(del_ptr, del_top, del_cp); if ((src_cp != del_cp) || ((WEOF == src_cp) && *src_ptr != *del_ptr)) { /* match lost. restart the search skipping the first delimiter character */ src_ptr = restart_ptr; char_len = restart_char_len; break; } } if (del_ptr >= del_top) { /* Match found : Return success if no more pieces to match else continue with scan */ assert(del_top == del_ptr); assert(0 < numpcs_unmatched); if (0 == --numpcs_unmatched) RETURN_YESMATCH(1 + char_len); } } RETURN_NOMATCH; } #endif /* UNICODE_SUPPORTED */ /* byte-oriented substring matching */ unsigned char *matchb(int del_len, unsigned char *del_str, int src_len, unsigned char *src_str, int *res, int *numpcs) { unsigned char *src_ptr, *pdel, *src_base, *src_top, *del_top; int src_cnt, numpcs_unmatched; boolean_t match_found; assert(0 <= del_len); assert(0 < *numpcs); if (0 == del_len) { /* always matches a null string */ *numpcs = 0; *res = 1; return src_str; } numpcs_unmatched = *numpcs; /* note down # of pieces to be matched */ src_ptr = src_base = src_str; src_top = src_ptr + src_len; if (src_len < del_len) /* Input string is shorter than delimiter string so no match possible */ RETURN_NOMATCH; del_top = del_str + del_len; pdel = del_str; while (src_ptr < src_top) { /* Quick Find 1st delimiter char */ while (*src_ptr != *pdel) { src_ptr = ++src_str; if (src_ptr == src_top) RETURN_NOMATCH; } match_found = FALSE; /* Found delimiter */ while (*src_ptr++ == *pdel++) { if (pdel == del_top) { /* Found matching piece. */ match_found = TRUE; break; } if (src_ptr == src_top) RETURN_NOMATCH; } if (match_found) { /* Return success if no more pieces to match else continue with scan */ assert(0 < numpcs_unmatched); if (0 == --numpcs_unmatched) RETURN_YESMATCH(INTCAST(1 + (src_ptr - src_base))); src_str = src_ptr; } else src_ptr = ++src_str; /* Match lost, goto next source character */ pdel = del_str; } RETURN_NOMATCH; } fis-gtm-V6.0-003/sr_port/matchc.h0000644000032200000250000000150712201176160015441 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef MATCHC_INCLUDED #define MATCHC_INCLUDED /* Character oriented match call */ unsigned char *matchc(int del_len, unsigned char *del_str, int src_len, unsigned char *src_str, int *res, int *numpcs); /* Byte oriented match call */ unsigned char *matchb(int del_len, unsigned char *del_str, int src_len, unsigned char *src_str, int *res, int *numpcs); #endif /* MATCHC_INCLUDED */ fis-gtm-V6.0-003/sr_port/mcalloc.c0000644000032200000250000000430612201176160015607 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "mmemory.h" #include "min_max.h" GBLREF int mcavail; GBLREF mcalloc_hdr *mcavailptr, *mcavailbase; char *mcalloc(unsigned int n) { mcalloc_hdr *hdr, *nxt, *ptr; int new_size, rel_size; /* Choice of char_ptr_t made because it is a 64 bit pointer on Tru64 which * is the alignment we need there, or any other 64 bit platforms we support * in the future. */ n = ROUND_UP2(n, SIZEOF(char_ptr_t)); if (n > mcavail) { /* No sufficient space in the current block. Follow the link and check if the next block has sufficient * space. There is no next block or the next one doesn't have enough space, allocate a new block with * the requested size and insert it after the current block. */ hdr = mcavailptr->link; if (NULL == hdr || n > hdr->size) { if (NULL != hdr) { /* i.e. the next block doesn't have sufficient space for n. Release as many small blocks as * necessary to make up for the space that we are allocating for the large block. * By release several small blocks and replacing them with a large block ensures that total * memory footprint is not increased due to a rare occurence of large routine compilation. */ rel_size = 0; for (nxt = hdr; NULL != nxt && (rel_size += nxt->size) < n; nxt = ptr) { ptr = nxt->link; free(nxt); } } else nxt = NULL; new_size = (int)MAX(MC_DSBLKSIZE, (n + MCALLOC_HDR_SZ)); hdr = (mcalloc_hdr *)malloc(new_size); hdr->link = nxt; hdr->size = (int4)(new_size - MCALLOC_HDR_SZ); mcavailptr->link = hdr; } assert(n <= hdr->size); memset(&hdr->data[0], 0, hdr->size); mcavailptr = hdr; mcavail = hdr->size; } mcavail -= n; assert(mcavail >= 0); return &mcavailptr->data[mcavail]; } fis-gtm-V6.0-003/sr_port/mcfree.c0000644000032200000250000000175112201176160015437 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "mmemory.h" GBLREF int mcavail; GBLREF mcalloc_hdr *mcavailptr, *mcavailbase; /* This routine doesn't actually release memory at the end of compilation. For efficiency sake * (esp. during indirect code compilation), it just resets the mcavail* pointers to the beginning * of the list so that the allocated area will be reused for the next compilation. */ void mcfree(void) { mcavailptr = mcavailbase; assert((NULL != mcavailptr) || !mcavail); mcavail = (NULL != mcavailptr) ? mcavailptr->size : 0; return; } fis-gtm-V6.0-003/sr_port/mdb_condition_handler.c0000644000032200000250000014312512201176177020515 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "gtm_stdlib.h" #include "gtm_inet.h" /* Required for gtmsource.h */ #include "gtm_stdio.h" #ifdef VMS # include /* required for gtmsource.h */ # include #endif #ifdef UNIX # include # include #endif #include "ast.h" #include "gdsroot.h" #include "gdsbt.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsblk.h" #include "gdsfhead.h" #include "gdscc.h" #include "gdskill.h" #include "gt_timer.h" #include "filestruct.h" #include "gtmdbglvl.h" #include "error.h" #include "hashtab_mname.h" #include "io.h" #include "io_params.h" #include "jnl.h" #include "lv_val.h" #include #include "mv_stent.h" #include "outofband.h" #include "stack_frame.h" #include "stringpool.h" #include "hashtab_int4.h" /* needed for tp.h */ #include "buddy_list.h" /* needed for tp.h */ #include "tp.h" #include "tp_frame.h" #include "xfer_enum.h" #include "mlkdef.h" #include "repl_msg.h" #include "gtmsource.h" #include "zwrite.h" #include "cache.h" #include "cache_cleanup.h" #include "objlabel.h" #include "op.h" #include "dpgbldir.h" #include "preemptive_db_clnup.h" #include "compiler.h" /* needed for MAX_SRCLINE */ #include "show_source_line.h" #include "trans_code_cleanup.h" #include "dm_setup.h" #include "util.h" #include "tp_restart.h" #include "dollar_zlevel.h" #include "error_trap.h" #include "golevel.h" #include "send_msg.h" #include "jobinterrupt_process_cleanup.h" #include "fix_xfer_entry.h" #include "change_reg.h" #include "tp_change_reg.h" #include "alias.h" #include "create_fatal_error_zshow_dmp.h" #include "have_crit.h" #ifdef UNIX # include "iormdef.h" # include "ftok_sems.h" # include "gtm_putmsg_list.h" #endif #ifdef GTM_TRIGGER # include "gv_trigger.h" # include "gtm_trigger.h" #endif GBLREF spdesc stringpool, rts_stringpool, indr_stringpool; GBLREF volatile int4 outofband; GBLREF volatile bool std_dev_outbnd; GBLREF unsigned char *restart_pc; GBLREF unsigned char *restart_ctxt; GBLREF unsigned char *stackwarn, *tpstackwarn; GBLREF unsigned char *stacktop, *tpstacktop; GBLREF unsigned char *msp, *tp_sp; GBLREF mv_stent *mv_chain; GBLREF stack_frame *frame_pointer, *zyerr_frame, *error_frame; GBLREF tp_frame *tp_pointer; GBLREF io_desc *active_device; GBLREF lv_val *active_lv; GBLREF io_pair io_std_device, io_curr_device; GBLREF mval dollar_ztrap; GBLREF volatile bool neterr_pending; GBLREF xfer_entry_t xfer_table[]; GBLREF unsigned short proc_act_type; GBLREF int mumps_status; GBLREF mstr *err_act; GBLREF tp_region *tp_reg_list; /* Chained list of regions used in this transaction not cleared on tp_restart */ GBLREF uint4 gtmDebugLevel; /* Debug level */ GBLREF uint4 process_id; GBLREF jnlpool_addrs jnlpool; GBLREF boolean_t pool_init; GBLREF boolean_t created_core; GBLREF boolean_t dont_want_core; GBLREF mval dollar_zstatus, dollar_zerror; GBLREF mval dollar_etrap; GBLREF volatile int4 gtmMallocDepth; GBLREF int4 exi_condition; GBLREF inctn_opcode_t inctn_opcode; #ifdef VMS GBLREF struct chf$signal_array *tp_restart_fail_sig; GBLREF boolean_t tp_restart_fail_sig_used; #endif GBLREF int merge_args; GBLREF lvzwrite_datablk *lvzwrite_block; GBLREF volatile boolean_t dollar_zininterrupt; GBLREF boolean_t ztrap_explicit_null; /* whether $ZTRAP was explicitly set to NULL in this frame */ GBLREF dollar_ecode_type dollar_ecode; /* structure containing $ECODE related information */ GBLREF boolean_t in_gvcst_incr; GBLREF gv_namehead *gv_target; GBLREF gd_region *gv_cur_region; GBLREF gv_key *gv_currkey; GBLREF sgmnt_addrs *cs_addrs; GBLREF sgmnt_data_ptr_t cs_data; GBLREF sgm_info *first_sgm_info; GBLREF dollar_stack_type dollar_stack; GBLREF mval *alias_retarg; #ifdef UNIX GBLREF jnl_gbls_t jgbl; #endif GBLREF io_desc *gtm_err_dev; #ifdef GTM_TRIGGER GBLREF int tprestart_state; /* When triggers restart, multiple states possible. See tp_restart.h */ GBLREF int4 gtm_trigger_depth; #endif #ifdef DEBUG GBLREF boolean_t donot_INVOKE_MUMTSTART; #endif error_def(ERR_ASSERT); error_def(ERR_CTRAP); error_def(ERR_CTRLC); error_def(ERR_CTRLY); error_def(ERR_GTMASSERT); error_def(ERR_GTMASSERT2); error_def(ERR_GTMCHECK); error_def(ERR_GTMERREXIT); error_def(ERR_JOBINTRRETHROW); error_def(ERR_JOBINTRRQST); error_def(ERR_LABELMISSING); error_def(ERR_MEMORY); error_def(ERR_NOEXCNOZTRAP); error_def(ERR_NOTPRINCIO); error_def(ERR_OUTOFSPACE); error_def(ERR_REPEATERROR); error_def(ERR_RESTART); error_def(ERR_RTSLOC); error_def(ERR_SRCLOCUNKNOWN); error_def(ERR_STACKCRIT); error_def(ERR_STACKOFLOW); error_def(ERR_TLVLZERO); error_def(ERR_TPRETRY); error_def(ERR_TPRESTNESTERR); error_def(ERR_TPSTACKCRIT); error_def(ERR_TPSTACKOFLOW); error_def(ERR_TPTIMEOUT); error_def(ERR_UNSOLCNTERR); error_def(ERR_VMSMEMORY); boolean_t clean_mum_tstart(void); void setup_error(sgmnt_addrs *csa, int argcnt, ...); #ifdef UNIX /* When we restart generated code after handling an error, verify that we are not in the frame or one created on its * behalf that invoked a trigger or spanning node and caused a dynamic TSTART to be done on its behalf. This can happen * for example if a trigger is invoked for the first time but gets a compilation or link failure error or if a spanning * node fetch or update drives an error. In the trigger case, the relevant error is thrown from gtm_trigger() while no * trigger based error handling is in effect so no rollback of the dynamic frame occurs which results in unhandled TPQUIT * errors, perhaps interminably. In both the trigger and spanning-node cases, the MUM_TSTART we are about to execute unrolls * the C stack preventing any return to the C frame that did the implicit tstart and prevents it from being committed so * it must be rolled back. */ #define MUM_TSTART_FRAME_CHECK \ { \ if (GTMTRIG_ONLY((0 == gtm_trigger_depth) &&) tp_pointer && tp_pointer->implicit_tstart) \ { \ DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE); \ OP_TROLLBACK(-1); /* Unroll implicit TP frame */ \ } \ } #else #define MUM_TSTART_FRAME_CHECK #endif /* We ignore errors in the $ZYERROR routine. When an error occurs, we unwind all stack frames upto and including * zyerr_frame. MUM_TSTART then transfers control to the $ZTRAP frame. */ boolean_t clean_mum_tstart(void) { stack_frame *save_zyerr_frame, *fp, *fpprev; boolean_t save_check_flag; if (NULL != zyerr_frame) { while ((NULL != frame_pointer) && (NULL != zyerr_frame)) { GOFRAMES(1, TRUE, FALSE); } assert(NULL != frame_pointer); proc_act_type = 0; if (indr_stringpool.base == stringpool.base) { /* switch to run time stringpool */ indr_stringpool = stringpool; stringpool = rts_stringpool; } return TRUE; } return (NULL != err_act); } #ifdef UNIX /* Routine to setup an error in util_outbuff as if rts_error had put it there. Used when we morph ERR_TPRETRY * to ERR_TPRESTNESTERR. Requires a va_list var containing the args so do this in this separate routine. */ void setup_error(sgmnt_addrs *csa, int argcnt, ...) { va_list var; VAR_START(var, argcnt); gtm_putmsg_list(csa, argcnt, var); va_end(var); } #endif CONDITION_HANDLER(mdb_condition_handler) { unsigned char *cp, *context, *sp_base; boolean_t dm_action; /* did the error occur on a action from direct mode */ boolean_t trans_action; /* did the error occur during "transcendental" code */ char src_line[MAX_ENTRYREF_LEN]; mstr src_line_d; io_desc *err_dev; tp_region *tr; gd_region *reg_top, *reg_save, *reg_local; gd_addr *addr_ptr; sgmnt_addrs *csa; stack_frame *fp; boolean_t error_in_zyerror; boolean_t repeat_error, etrap_handling, reset_mpc; int level, rc; lv_val *lvptr; boolean_t reserve_sock_dev = FALSE; # ifdef UNIX unix_db_info *udi; stack_frame *lcl_error_frame; mv_stent *mvst; # endif START_CH; DBGEHND((stderr, "mdb_condition_handler: Entered with SIGNAL=%d frame_pointer=0x"lvaddr"\n", SIGNAL, frame_pointer)); if (NULL != gtm_err_dev) { /* It is possible that we entered here from a bad compile of the OPEN exception handler * for a device. If gtm_err_dev is still set from the previous mdb_condition_handler * invocation that drove the error handler that occurred during the OPEN command, then its * structures should be released now. */ if (gtmsocket == gtm_err_dev->type) iosocket_destroy(gtm_err_dev); # ifdef UNIX else remove_rms(gtm_err_dev); # endif gtm_err_dev = NULL; } if (repeat_error = (ERR_REPEATERROR == SIGNAL)) /* assignment and comparison */ SIGNAL = dollar_ecode.error_last_ecode; preemptive_db_clnup(SEVERITY); if (NULL != alias_retarg) { /* An error has occurred while an alias return arg was in-flight. Delivery won't happen now * so we need to remove the extra counts that were added in unw_retarg() and dis-enchant * the alias container itself. */ assert(alias_retarg->mvtype & MV_ALIASCONT); if (alias_retarg->mvtype & MV_ALIASCONT) { /* Protect the refs were are about to make in case ptr got banged up somehow */ lvptr = (lv_val *)alias_retarg->str.addr; assert(LV_IS_BASE_VAR(lvptr)); DECR_CREFCNT(lvptr); DECR_TREFCNT(lvptr); } alias_retarg->mvtype = 0; /* Kill the temp var (no longer a container) */ alias_retarg = NULL; /* .. and no more in-flight return argument */ } if ((int)ERR_UNSOLCNTERR == SIGNAL) { /* This is here for linking purposes. We want to delay the receipt of * network errors in gtm until we are ready to deal with them. Hence * the transfer table hijinx. To avoid doing this in the gvcmz routine, * we signal the error and do it here */ neterr_pending = TRUE; FIX_XFER_ENTRY(xf_linefetch, op_fetchintrrpt); FIX_XFER_ENTRY(xf_linestart, op_startintrrpt); FIX_XFER_ENTRY(xf_forchk1, op_startintrrpt); FIX_XFER_ENTRY(xf_forloop, op_forintrrpt); CONTINUE; } MDB_START; assert(FALSE == in_gvcst_incr); /* currently there is no known case where this can be TRUE at this point */ in_gvcst_incr = FALSE; /* reset this just in case gvcst_incr/gvcst_put failed to do a good job of resetting */ /* Ideally merge should have a condition handler to reset followings, but generated code can call other routines * during MERGE command (MERGE command invokes multiple op-codes depending on source vs target). So it is not * easy to establish a condition handler there. Easy solution is following one line code. */ merge_args = 0; TREF(in_zwrite) = FALSE; inctn_opcode = inctn_invalid_op; if ((SUCCESS != SEVERITY) && (INFO != SEVERITY)) { if (lvzwrite_block) /* If lvzwrite_block does not (yet) exist, no harm, no foul */ lvzwrite_block->curr_subsc = lvzwrite_block->subsc_count = 0; } if ((int)ERR_TPRETRY == SIGNAL) { # ifdef UNIX lcl_error_frame = error_frame; if ((NULL == lcl_error_frame) && dollar_zininterrupt) { /* We are in a $zininterrupt handler AND have a restart request. See if we were in error processing * when we started the interrupt. We can locate this in the zinterrupt mv_stent. Note this loop * does not process the last mv_stent on the stack but since that is the MVST_STORIG entry, this is ok * as we expect to find a ZINTRupt entry long before that. */ for (mvst = mv_chain; 0 != mvst->mv_st_next; mvst = (mv_stent *)(mvst->mv_st_next + (char *)mvst)) { if (MVST_ZINTR == mvst->mv_st_type) break; } assertpro(MVST_ZINTR == mvst->mv_st_type); /* No zinterrupt block, big problemo */ lcl_error_frame = mvst->mv_st_cont.mvs_zintr.error_frame_save; } if (NULL == lcl_error_frame) # endif { VMS_ONLY(assert(FALSE == tp_restart_fail_sig_used)); # ifdef GTM_TRIGGER /* Assert that we never end up invoking the MUM_TSTART macro handler in case of an implicit tstart restart. * See GBLDEF of skip_INVOKE_RESTART and donot_INVOKE_MUMTSTART in gbldefs.c for more information. * Note that it is possible for this macro to be invoked from generated code in a trigger frame (in which * case gtm_trigger/tp_restart ensure control passed to mdb_condition_handler only until the outermost * implicit tstart in which case they return). Assert accordingly. */ assert(!donot_INVOKE_MUMTSTART || gtm_trigger_depth); TRIGGER_BASE_FRAME_UNWIND_IF_NOMANSLAND; # endif rc = tp_restart(1, TP_RESTART_HANDLES_ERRORS); DBGEHND((stderr, "mdb_condition_handler: tp_restart returned with rc=%d. state=%d, and SIGNAL=%d\n", rc, GTMTRIG_ONLY(tprestart_state) NON_GTMTRIG_ONLY(0), error_condition)); # ifdef GTM_TRIGGER if (0 != rc) { /* The only time "tp_restart" will return non-zero is if the error needs to be * rethrown. To accomplish that, we will unwind this handler which will return to * the inner most initiating dm_start() with the return code set to whatever mumps_status * is set to. */ assert(TPRESTART_STATE_NORMAL != tprestart_state); assert(rc == SIGNAL); assertpro((SFT_TRIGR & frame_pointer->type) && (0 < gtm_trigger_depth)); mumps_status = rc; DBGEHND((stderr, "mdb_condition_handler: Unwind-return to caller (gtm_trigger)\n")); UNWIND(NULL, NULL); } /* "tp_restart" has succeeded so we have unwound back to the return point but check if the * transaction was initiated by an implicit trigger TSTART. This can occur if an error was * encountered in a trigger before the trigger base-frame was setup. It can occur at any trigger * level if a triggered update is preceeded by a TROLLBACK. */ if (!(SFT_TRIGR & frame_pointer->type) && tp_pointer && tp_pointer->implicit_tstart) { mumps_status = rc; DBGEHND((stderr, "mdb_condition_handler: Returning to implicit TSTART originator\n")); UNWIND(NULL, NULL); } assert(!donot_INVOKE_MUMTSTART); # endif # ifdef UNIX if (ERR_TPRETRY == SIGNAL) /* (signal value undisturbed) */ # elif defined VMS if (!tp_restart_fail_sig_used) /* If tp_restart ran clean */ # endif { /* Set mumps program counter back tstart level 1 */ MUM_TSTART; } # ifdef VMS else { /* Otherwise tp_restart had a signal that we must now deal with -- replace the TPRETRY * information with that saved from tp_restart. * Assert that we have room for these arguments - the array malloc is in tp_restart */ assert(TPRESTART_ARG_CNT >= tp_restart_fail_sig->chf$is_sig_args); memcpy(sig, tp_restart_fail_sig, (tp_restart_fail_sig->chf$l_sig_args + 1) * SIZEOF(int)); tp_restart_fail_sig_used = FALSE; } # endif } # ifdef UNIX else { if (0 == dollar_tlevel) SIGNAL = ERR_TLVLZERO; /* TPRESTART specified but not in TP */ else SIGNAL = ERR_TPRESTNESTERR; /* Only if actually in TP */ /* TPRETRY encountered or requested during error handling - treat as nested error to prevent issues * with errors being rethrown during a TP restart. Change the error from TPRETRY to either TLVLZERO or * TPRESTNESTERR as appropriate so we don't give internal use only error name to user and let error * continue through regular processing (both treated as nested error since error_frame non-NULL). */ setup_error(gv_target ? gv_target->gd_csa : NULL, VARLSTCNT(1) SIGNAL); } # endif } /* Ensure gv_target and cs_addrs are in sync. If not, make them so. */ if (NULL != gv_target) { csa = gv_target->gd_csa; if (NULL != csa) { if (csa != cs_addrs) { assert(0 < csa->regcnt); /* If csa->regcnt is > 1, it is possible that csa->region is different from the actual gv_cur_region * (before we encountered the runtime error). This is a case of two regions mapping to the same csa. * The only issue with this is that some user-level error messages that have the region name (as * opposed to the database file name) could print incorrect values. But other than that there should * be no issues since finally the csa (corresponding to the physical database file) is what matters * and that is the same for both the regions. Given that the region mismatch potential exists only * until the next global reference which is different from $REFERENCE, we consider this acceptable. */ gv_cur_region = csa->region; assert(gv_cur_region->open); assert((dba_mm == gv_cur_region->dyn.addr->acc_meth) || (dba_bg == gv_cur_region->dyn.addr->acc_meth)); /* The above assert is needed to ensure that change_reg/tp_change_reg (invoked below) * will set cs_addrs, cs_data etc. to non-zero values. */ if (NULL != first_sgm_info) change_reg(); /* updates "cs_addrs", "cs_data", "sgm_info_ptr" and maybe "first_sgm_info" */ else { /* We are either inside a non-TP transaction or a TP transaction that has done NO database * references. In either case, we do NOT want to setting sgm_info_ptr or first_sgm_info. * Hence use tp_change_reg instead of change_reg below. */ tp_change_reg(); /* updates "cs_addrs", "cs_data" */ } assert(cs_addrs == csa); assert(cs_data == csa->hdr); assert(NULL != cs_data); } /* Fix gv_currkey to null-str in case gv_target points to dir_tree (possible in case of name-level-$order). * This is similar to how we fix gv_currkey for a successful name-level-$order operation (see op_gvorder.c). * Do same in case gv_target points to cs_addrs->hasht_tree so we dont take the fast path in op_gvname * when gv_target is clearly not GVT of a user-visible global. */ if ((gv_target == csa->dir_tree) GTMTRIG_ONLY(|| (gv_target == csa->hasht_tree))) { gv_currkey->end = 0; gv_currkey->base[0] = 0; } } } DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE); if (DUMPABLE) { /* Certain conditions we don't want to attempt to create the M-level ZSHOW dump. * 1) Unix: If gtmMallocDepth > 0 indicating memory manager was active and could be reentered. * 2) Unix: If we have a SIGBUS or SIGSEGV (could be likely to occur again * in the local variable code which would cause immediate shutdown with * no cleanup). * 3) VMS: If we got an ACCVIO for the same as reason (2). * Note that we will bypass checks 2 and 3 if GDL_ZSHOWDumpOnSignal debug flag is on */ SET_PROCESS_EXITING_TRUE; /* So zshow doesn't push stuff on stack to "protect" it when * we potentially already have a stack overflow */ cancel_timer(0); /* No interruptions now that we are dying */ if (!repeat_error UNIX_ONLY(&& (0 == gtmMallocDepth))) { src_line_d.addr = src_line; /* Setup entry point buffer for set_zstatus() */ src_line_d.len = 0; SET_ZSTATUS(NULL); } /* Create the ZSHOW dump file if it can be created */ create_fatal_error_zshow_dmp(SIGNAL, repeat_error); /* If we are about to core/exit on a stack over flow, only do the core part if a debug * flag requests this behaviour. Otherwise, supress the core and just exit. * 2006-03-07 se: If a stack overflow occurs on VMS, it has happened that the stack is no * longer well formed so attempting to unwind it as it does in MUMPS_EXIT causes things * to really become screwed up. For this reason, this niceness of avoiding a dump on a * stack overflow on VMS is being disabled. The dump can be controlled wih set proc/dump * (or not) as desired. * 2008-01-29 (se): Added fatal MEMORY error so we no longer generate a core for it by * default unless the DumpOnStackOFlow flag is turned on. Since this flag is not a user-exposed * interface, I'm avoiding renaming it for now. Note the core avoidance applies to both UNIX * and VMS since stack formation is not at issue in this sort of memory request. * Finally note that in UNIX, ch_cond_core (called by DRIVECH macro which invoked this condition * handler has likely already created the core and set the created_core flag which will prevent * this process from creating another core for the same SIGNAL. We leave this code in here in * case methods exist in the future for this module to be driven without invoking cond_core_ch * first. */ if (!(GDL_DumpOnStackOFlow & gtmDebugLevel) && VMS_ONLY((int)ERR_VMSMEMORY == SIGNAL) UNIX_ONLY(((int)ERR_STACKOFLOW == SIGNAL || (int)ERR_STACKOFLOW == arg || (int)ERR_MEMORY == SIGNAL || (int)ERR_MEMORY == arg))) { # ifdef VMS /* Inside this ifdef, we are definitely here because of ERR_VMSMEMORY. If the conditions * of the above if change, revisit these assmuptions. * For VMSMEMORY error, we have to send the message to the operator log and to the * console ourselves because the MUMP_EXIT method of exiting on a fatal error does * not preserve the substitution parameters for the message making it useless. After * sending the message change the status code so we exit with something other than the * duplicate message. */ assert(ERR_VMSMEMORY == SIGNAL); send_msg(VARLSTCNT(4) ERR_VMSMEMORY, 2, *(int **)(&sig->chf$is_sig_arg1 + 1), /* BYPASSOK - send_msg */ *(int **)(&sig->chf$is_sig_arg1 + 2)); gtm_putmsg(VARLSTCNT(4) ERR_VMSMEMORY, 2, *(int **)(&sig->chf$is_sig_arg1 + 1), /* BYPASSOK - gtm_putmsg */ *(int **)(&sig->chf$is_sig_arg1 + 2)); SIGNAL = ERR_GTMERREXIT; /* Override reason for "stop" */ # endif MUMPS_EXIT; /* Do a clean exit rather than messy core exit */ } gtm_dump(); TERMINATE; } # ifdef GTM_TRIGGER assertpro(TPRESTART_STATE_NORMAL == tprestart_state); /* Can't leave half-restarted transaction around - out of design */ # endif if (active_lv) { if (!LV_IS_VAL_DEFINED(active_lv) && !LV_HAS_CHILD(active_lv)) op_kill(active_lv); active_lv = (lv_val *)0; } /* * If error is at least severity "WARNING", do some cleanups. Note: crit is no longer unconditionally * released here. It is now released if NOT in TP (any retry) or if in TP but NOT in the final retry. * But we still cleanup the replication instance file lock and the replication crit lock. We do this * because when starting the final retry GTM only holds the grab_crit locks but not the grab_lock or * ftok_sem_lock locks. The grab_lock is done only at commit time (at which point there cannot be any * programmatic runtime errors possible). Errors inside jnlpool_init (which cause the ftok-sem-lock * to be held) can never be programmatically caused. * * On the other hand, while running in the final retry holding crit, a program can cause an arbitrary * error (e.g. 1/0 error or similar). Hence the distinction. The reasoning is that any of these could * potentially take an arbitrary amount of time and we don't want to be holding critical locks while * doing these. But one can argue that the error trap is nothing but an extension of the transaction * and that if GT.M is fine executing arbitrary application M code in the final retry holding crit, * it should be fine doing the same for the error trap M code as well. So the entire point of not * releasing crit is to avoid indefinite TP retries due to runtime errors. But this means the error * trap should be well coded (i.e. not have any long running commands etc.) to avoid crit hangs * and/or deadlocks. */ if ((SUCCESS != SEVERITY) && (INFO != SEVERITY)) { ENABLE_AST; if ((0 == dollar_tlevel) || (CDB_STAGNATE > t_tries)) { /* Only release crit if we are NOT in TP *or* if we are in TP, we aren't in final retry */ for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr)) { for (reg_local = addr_ptr->regions, reg_top = reg_local + addr_ptr->n_regions; reg_local < reg_top; reg_local++) { if (reg_local->open && !reg_local->was_open) { csa = (sgmnt_addrs *)&FILE_INFO(reg_local)->s_addrs; if (csa && csa->now_crit) { assert(!csa->hold_onto_crit UNIX_ONLY(|| jgbl.onlnrlbk)); if (csa->hold_onto_crit) csa->hold_onto_crit = FALSE; /* Fix it in pro */ rel_crit(reg_local); } } } } } # ifdef UNIX /* Release FTOK lock on the replication instance file if holding it (possible if error in jnlpool_init) */ assert((NULL == jnlpool.jnlpool_dummy_reg) || jnlpool.jnlpool_dummy_reg->open || !pool_init); if ((NULL != jnlpool.jnlpool_dummy_reg) && jnlpool.jnlpool_dummy_reg->open) { udi = FILE_INFO(jnlpool.jnlpool_dummy_reg); assert(NULL != udi); if (NULL != udi) { if (udi->grabbed_ftok_sem) ftok_sem_release(jnlpool.jnlpool_dummy_reg, FALSE, FALSE); assert(!udi->grabbed_ftok_sem); } } # endif /* Release crit lock on journal pool if holding it */ if (pool_init) /* atleast one region replicated and we have done jnlpool init */ { csa = (sgmnt_addrs *)&FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs; if (csa && csa->now_crit) rel_lock(jnlpool.jnlpool_dummy_reg); } TREF(in_op_fnnext) = FALSE; /* in case we were in $NEXT */ /* Global values that may need cleanups */ if (INTRPT_OK_TO_INTERRUPT != intrpt_ok_state) ENABLE_INTERRUPTS(intrpt_ok_state); /* If interrupts were deferred, re-enable them now */ } # ifdef GTM_TRIGGER /* At this point, we are past the point where the frame pointer is allowed to be resting on a trigger frame * (this is possible in a TPRETRY situation where gtm_trigger must return to gtm_trigger() signaling a * restart is necessary). If we are on a trigger base frame, unwind it so the error is recognized in * the invoker's frame. */ if (SFT_TRIGR & frame_pointer->type) { /* Better be an error in here info or success messages want to continue, not be unwound but * we cannot go past this point in a trigger frame or the frame_pointer back reference below * will fail. */ assert((SUCCESS != SEVERITY) && (INFO != SEVERITY)); /* These outofband conditions depend on saving the current stack frame info in restart_pc which * is of course no longer valid once the frame is unrolled so they must be avoided. At the time * of this writing, there are no conditions that these should validly be called in this * situation so this check is more for the future. */ assert(((int)ERR_CTRLY != SIGNAL) && ((int)ERR_CTRLC != SIGNAL) && ((int)ERR_CTRAP != SIGNAL) && ((int)ERR_JOBINTRRQST != SIGNAL) && ((int)ERR_JOBINTRRETHROW != SIGNAL)); gtm_trigger_fini(TRUE, FALSE); DBGEHND((stderr, "mdb_condition_handler: Current trigger frame unwound so error is thrown" " on trigger invoker's frame instead.\n")); } # endif err_dev = active_device; active_device = (io_desc *)NULL; dm_action = (frame_pointer->old_frame_pointer->type & SFT_DM) || (TREF(compile_time) && (frame_pointer->type & SFT_DM)); /* The errors are said to be transcendental when they occur during compilation/execution * of the error trap ({z,e}trap, device exception) or $zinterrupt. The errors in other * indirect code frames (zbreak, zstep, xecute etc.) aren't defined to be trancendental * and will be treated as if they occured in a regular code frame. */ trans_action = proc_act_type || (frame_pointer->type & SFT_ZTRAP) || (frame_pointer->type & SFT_DEV_ACT); src_line_d.addr = src_line; src_line_d.len = 0; flush_pio(); if ((int)ERR_CTRLY == SIGNAL) { outofband_clear(); /* Verify not indirect or that context is unchanged before reset context */ assert(NULL != restart_pc); assert((!(SFF_INDCE & frame_pointer->flags)) || (restart_ctxt == frame_pointer->ctxt)); DBGEHND((stderr, "mdb_condition_handler(1): Resetting frame 0x"lvaddr" mpc/context with restart_pc/ctxt " "0x"lvaddr"/0x"lvaddr" - frame has type 0x%04lx\n", frame_pointer, restart_pc, restart_ctxt, frame_pointer->type)); frame_pointer->mpc = restart_pc; frame_pointer->ctxt = restart_ctxt; MUM_TSTART; } else if ((int)ERR_CTRLC == SIGNAL) { outofband_clear(); if (!trans_action && !dm_action) { /* Verify not indirect or that context is unchanged before reset context */ assert(NULL != restart_pc); assert((!(SFF_INDCE & frame_pointer->flags)) || (restart_ctxt == frame_pointer->ctxt)); DBGEHND((stderr, "mdb_condition_handler(2): Resetting frame 0x"lvaddr" mpc/context with restart_pc/ctxt " "0x"lvaddr"/0x"lvaddr" - frame has type 0x%04lx\n", frame_pointer, restart_pc, restart_ctxt, frame_pointer->type)); frame_pointer->mpc = restart_pc; frame_pointer->ctxt = restart_ctxt; frame_pointer->flags &= SFF_IMPLTSTART_CALLD_OFF; /* Frame enterable now with mpc reset */ GTMTRIG_ONLY( DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_IMPLTSTART_CALLD_OFF (1) in frame " "0x"lvaddr"\n", frame_pointer))); if (!(frame_pointer->type & SFT_DM)) dm_setup(); } else if (frame_pointer->type & SFT_DM) { frame_pointer->ctxt = GTM_CONTEXT(call_dm); frame_pointer->mpc = CODE_ADDRESS(call_dm); frame_pointer->flags &= SFF_IMPLTSTART_CALLD_OFF; /* Frame enterable now with mpc reset */ GTMTRIG_ONLY( DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_IMPLTSTART_CALLD_OFF (1) in frame " "0x"lvaddr"\n", frame_pointer))); } else { /* Do cleanup on indirect frames prior to reset */ IF_INDR_FRAME_CLEANUP_CACHE_ENTRY_AND_UNMARK(frame_pointer); frame_pointer->ctxt = GTM_CONTEXT(pseudo_ret); frame_pointer->mpc = CODE_ADDRESS(pseudo_ret); frame_pointer->flags &= SFF_IMPLTSTART_CALLD_OFF; /* Frame enterable now with mpc reset */ GTMTRIG_ONLY( DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_IMPLTSTART_CALLD_OFF (1) in frame " "0x"lvaddr"\n", frame_pointer))); } PRN_ERROR; if (io_curr_device.out != io_std_device.out) dec_err(VARLSTCNT(4) ERR_NOTPRINCIO, 2, io_curr_device.out->trans_name->len, io_curr_device.out->trans_name->dollar_io); MUM_TSTART; } else if ((int)ERR_CTRAP == SIGNAL) { if (!repeat_error) /* This has already been done if we are re-throwing the error */ outofband_clear(); if (!trans_action && !dm_action && !(frame_pointer->type & SFT_DM)) { sp_base = stringpool.base; if (sp_base != rts_stringpool.base) { indr_stringpool = stringpool; /* update indr_stringpool */ stringpool = rts_stringpool; /* change for set_zstatus */ } if (!repeat_error) { dollar_ecode.error_last_b_line = SET_ZSTATUS(NULL); } if (sp_base != rts_stringpool.base) { rts_stringpool = stringpool; /* update rts_stringpool */ stringpool = indr_stringpool; /* change back */ } assert(NULL != dollar_ecode.error_last_b_line); /* Only (re)set restart_pc if we are in the original frame. This is needed to restart execution at the * beginning of the line but only happens when $ZTRAP is in effect. If $ETRAP is in control, control * naturally returns to the caller unless the $ECODE value is not set. In that case, the CTRAP error * will be rethrown one level down as $ETRAP normally does. Note in case of a rethrow, we avoid resetting * mpc/ctxt as those values are only appropriate for the level in which they were saved. */ if (!repeat_error && ((0 != dollar_ztrap.str.len) || ztrap_explicit_null)) { /* Verify not indirect or that context is unchanged before reset context */ assert(NULL != restart_pc); assert((!(SFF_INDCE & frame_pointer->flags)) || (restart_ctxt == frame_pointer->ctxt)); DBGEHND((stderr, "mdb_condition_handler(3): Resetting frame 0x"lvaddr" mpc/context with restart_pc/" "ctxt 0x"lvaddr"/0x"lvaddr" - frame has type 0x%04lx\n", frame_pointer, restart_pc, restart_ctxt, frame_pointer->type)); frame_pointer->mpc = restart_pc; frame_pointer->ctxt = restart_ctxt; } err_act = NULL; dollar_ecode.error_last_ecode = SIGNAL; if (std_dev_outbnd && io_std_device.in && (tt == io_std_device.in->type) && io_std_device.in->error_handler.len) { proc_act_type = SFT_DEV_ACT; err_act = &io_std_device.in->error_handler; } else if (!std_dev_outbnd && err_dev && (tt == err_dev->type) && err_dev->error_handler.len) { proc_act_type = SFT_DEV_ACT; err_act = &err_dev->error_handler; } else if (NULL != error_frame) { /* a primary error occurred already. irrespective of whether ZTRAP or ETRAP is active now, * we need to consider this as a nested error and trigger nested error processing. */ goerrorframe(); /* unwind back to error_frame */ proc_act_type = 0; } else if ((0 != dollar_etrap.str.len) || (0 != dollar_ztrap.str.len)) { assert(!ztrap_explicit_null); proc_act_type = SFT_ZTRAP; err_act = (0 != dollar_etrap.str.len) ? &dollar_etrap.str : &dollar_ztrap.str; } else { /* Either $ETRAP is empty-string or ztrap_explicit_null is set * * If ztrap_explicit_null is FALSE * - Use empty-string $ETRAP for error-handling * * If ztrap_explicit_null is TRUE * - unwind as many frames as possible until we see a frame where ztrap_explicit_null is * FALSE and $ZTRAP is not NULL (i.e. we find a $ETRAP handler). In that frame, use $ETRAP * for error-handling. If no such frame is found, exit after printing the error. */ etrap_handling = TRUE; if (ztrap_explicit_null) { assert(0 == dollar_etrap.str.len); for (level = dollar_zlevel() - 1; level > 0; level--) { GOLEVEL(level, FALSE); assert(level == dollar_zlevel()); if (ETRAP_IN_EFFECT) break; } if (0 >= level) { assert(0 == level); etrap_handling = FALSE; DBGEHND((stderr, "mdb_condition_handler: Unwound to stack start - exiting\n")); } /* Note that trans_code will set error_frame appropriately for this condition */ } if (SFF_CI & frame_pointer->flags) { /* Unhandled errors from called-in routines should return to gtm_ci() with error status */ mumps_status = SIGNAL; MUM_TSTART_FRAME_CHECK; MUM_TSTART; } else if (etrap_handling) { proc_act_type = SFT_ZTRAP; err_act = &dollar_etrap.str; } else { PRN_ERROR; rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOEXCNOZTRAP); } } if (clean_mum_tstart()) { MUM_TSTART_FRAME_CHECK; MUM_TSTART; } } else if (frame_pointer->type & SFT_DM) { frame_pointer->ctxt = GTM_CONTEXT(call_dm); frame_pointer->mpc = CODE_ADDRESS(call_dm); frame_pointer->flags &= SFF_IMPLTSTART_CALLD_OFF; /* Frame enterable now with mpc reset */ GTMTRIG_ONLY(DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_IMPLTSTART_CALLD (2) in frame 0x" lvaddr"\n", frame_pointer))); } else { /* Do cleanup on indirect frames prior to reset */ IF_INDR_FRAME_CLEANUP_CACHE_ENTRY_AND_UNMARK(frame_pointer); frame_pointer->ctxt = GTM_CONTEXT(pseudo_ret); frame_pointer->mpc = CODE_ADDRESS(pseudo_ret); frame_pointer->flags &= SFF_IMPLTSTART_CALLD_OFF; /* Frame enterable now with mpc reset */ GTMTRIG_ONLY(DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_IMPLTSTART_CALLD (3) in frame 0x" lvaddr"\n", frame_pointer))); } PRN_ERROR; if (io_curr_device.out != io_std_device.out) { dec_err(VARLSTCNT(4) ERR_NOTPRINCIO, 2, io_curr_device.out->trans_name->len, io_curr_device.out->trans_name->dollar_io); } MUM_TSTART_FRAME_CHECK; MUM_TSTART; } else if ((int)ERR_JOBINTRRQST == SIGNAL) { /* Verify not indirect or that context is unchanged before reset context */ assert(NULL != restart_pc); assert((!(SFF_INDCE & frame_pointer->flags)) || (restart_ctxt == frame_pointer->ctxt)); DBGEHND((stderr, "mdb_condition_handler(4): Resetting frame 0x"lvaddr" mpc/context with restart_pc/ctxt " "0x"lvaddr"/0x"lvaddr" - frame has type 0x%04lx\n", frame_pointer, restart_pc, restart_ctxt, frame_pointer->type)); frame_pointer->mpc = restart_pc; frame_pointer->ctxt = restart_ctxt; assert(!dollar_zininterrupt); dollar_zininterrupt = TRUE; /* Note done before outofband is cleared to prevent nesting */ outofband_clear(); proc_act_type = SFT_ZINTR | SFT_COUNT; /* trans_code will invoke jobinterrupt_process for us */ MUM_TSTART; } else if ((int)ERR_JOBINTRRETHROW == SIGNAL) { /* Job interrupt is rethrown from TC/TRO */ assert(!dollar_zininterrupt); dollar_zininterrupt = TRUE; proc_act_type = SFT_ZINTR | SFT_COUNT; /* trans_code will invoke jobinterrupt_process for us */ MUM_TSTART; } else if ((int)ERR_STACKCRIT == SIGNAL) { assert(msp > stacktop); assert(stackwarn > stacktop); cp = stackwarn; stackwarn = stacktop; push_stck(cp, 0, (void **)&stackwarn, MVST_STCK_SP); } if (!repeat_error) dollar_ecode.error_last_b_line = NULL; /* Error from direct mode actions does not set $ZSTATUS and is not restarted (dollar_ecode.error_last_b_line = NULL); * Error from transcendental code does set $ZSTATUS but does not restart the line. */ if (!dm_action) { sp_base = stringpool.base; if (sp_base != rts_stringpool.base) { indr_stringpool = stringpool; /* update indr_stringpool */ stringpool = rts_stringpool; /* change for set_zstatus */ } if (!repeat_error) dollar_ecode.error_last_b_line = SET_ZSTATUS(&context); assert(NULL != dollar_ecode.error_last_b_line); if (sp_base != rts_stringpool.base) { rts_stringpool = stringpool; /* update rts_stringpool */ stringpool = indr_stringpool; /* change back */ } } if ((SUCCESS == SEVERITY) || (INFO == SEVERITY)) { PRN_ERROR; CONTINUE; } /* Error from direct mode actions or "transcendental" code does not invoke MUMPS error handling routines */ if (!dm_action && !trans_action) { DBGEHND((stderr, "mdb_condition_handler: Handler to dispatch selection checks\n")); err_act = NULL; dollar_ecode.error_last_ecode = SIGNAL; reset_mpc = FALSE; if (err_dev && err_dev->error_handler.len && ((int)ERR_TPTIMEOUT != SIGNAL)) { proc_act_type = SFT_DEV_ACT; err_act = &err_dev->error_handler; reserve_sock_dev = TRUE; /* Reset mpc to beginning of the current line (to retry after processing the IO exception handler) */ reset_mpc = TRUE; DBGEHND((stderr, "mdb_condition_handler: dispatching device error handler [%.*s]\n", err_act->len, err_act->addr)); } else if (NULL != error_frame) { /* A primary error occurred already. irrespective of whether ZTRAP or ETRAP is active now, we need to * consider this as a nested error and trigger nested error processing. */ goerrorframe(); /* unwind upto error_frame */ proc_act_type = 0; DBGEHND((stderr, "mdb_condition_handler: Have unwound to error frame via goerrorframe() and am " "re-dispatching error frame\n")); MUM_TSTART_FRAME_CHECK; MUM_TSTART; /* unwind the current C-stack and restart executing from the top of the current M-stack */ } else if ((0 != dollar_etrap.str.len) || (0 != dollar_ztrap.str.len)) { assert(!ztrap_explicit_null); proc_act_type = SFT_ZTRAP; err_act = (0 != dollar_etrap.str.len) ? &dollar_etrap.str : &dollar_ztrap.str; DBGEHND((stderr, "mdb_condition_handler: Dispatching %s error handler [%.*s]\n", (0 != dollar_etrap.str.len) ? "$ETRAP" : "$ZTRAP", err_act->len, err_act->addr)); /* Reset mpc to beginning of the current line (to retry after invoking $ZTRAP) */ if (0 != dollar_ztrap.str.len) reset_mpc = TRUE; } else { /* Either $ETRAP is empty string or ztrap_explicit_null is set. * * If ztrap_explicit_null is FALSE * - Use empty-string $ETRAP for error-handling * * If ztrap_explicit_null is TRUE * - Unwind as many frames as possible until we see a frame where ztrap_explicit_null is FALSE and * $ZTRAP is *not* NULL (i.e. we found an $ETRAP). In that frame, use $ETRAP for error-handling. * If no such frame is found, exit after printing the error. */ etrap_handling = TRUE; if (ztrap_explicit_null) { GTMTRIG_ONLY(assert(0 == gtm_trigger_depth)); /* Should never happen in a trigger */ DBGEHND((stderr, "mdb_condition_handler: ztrap_explicit_null set - unwinding till find handler\n")); assert(0 == dollar_etrap.str.len); for (level = dollar_zlevel() - 1; level > 0; level--) { GOLEVEL(level, FALSE); assert(level == dollar_zlevel()); if (ETRAP_IN_EFFECT) /* Break if found an $ETRAP covered frame */ break; } if (0 >= level) { assert(0 == level); etrap_handling = FALSE; DBGEHND((stderr, "mdb_condition_handler: Unwound to stack start - exiting\n")); } /* note that trans_code will set error_frame appropriately for this condition */ } if (SFF_CI & frame_pointer->flags) { /* Unhandled errors from called-in routines should return to gtm_ci() with error status */ mumps_status = SIGNAL; DBGEHND((stderr, "mdb_condition_handler: Call in base frame found - returnning to callins\n")); MUM_TSTART_FRAME_CHECK; MUM_TSTART; } else if (etrap_handling) { proc_act_type = SFT_ZTRAP; err_act = &dollar_etrap.str; DBGEHND((stderr, "mdb_condition_handler: $ETRAP handler being dispatched [%.*s]\n", err_act->len, err_act->addr)); } } /* if the err_act points to the address err_dev->errro_handler, we cannot destroy socket here */ if (err_dev && (gtmsocket == err_dev->type) && err_dev->newly_created && !reserve_sock_dev) { assert(err_dev->state != dev_open); iosocket_destroy(err_dev); err_dev = NULL; } if (reset_mpc) { /* Reset the mpc such that * (a) If the current frame is a counted frame, the error line is retried after the error is handled, * (b) If the current frame is "transcendental" code, set frame to return. * * If we are in $ZYERROR, we don't care about restarting the line that errored since we will * unwind all frames upto and including zyerr_frame. * * If this is a rethrown error (ERR_REPEATERROR) from a child frame, do NOT reset mpc of the current * frame in that case. We do NOT want to retry the current line (after the error has been * processed) because the error did not occur in this line and therefore re-executing the same * line could cause undesirable effects at the M-user level. We will resume normal execution * once the error is handled. Not that it matters, but note that in the case of a rethrown error * (repeat_error is TRUE), we would NOT have noted down dollar_ecode.error_last_b_line so cannot * use that to reset mpc anyways. */ if ((NULL == zyerr_frame) && !repeat_error) { DBGEHND((stderr, "mdb_condition_handler: reset_mpc triggered\n")); for (fp = frame_pointer; fp; fp = fp->old_frame_pointer) { /* See if this is a $ZINTERRUPT frame. If yes, we want to restart *this* line * at the beginning. Since it is always an indirect frame, we can use the context * pointer to start over. $ETRAP does things somewhat differently in that the current * frame is always returned from. */ if (SFT_ZINTR & fp->type) { assert(SFF_INDCE & fp->flags); fp->mpc = fp->ctxt; fp->flags &= SFF_IMPLTSTART_CALLD_OFF; /* Frame enterable now with mpc reset */ GTMTRIG_ONLY( DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_IMPLTSTART_CALLD" " (4) in frame 0x"lvaddr"\n", frame_pointer))); break; } /* Do cleanup on indirect frames prior to reset */ IF_INDR_FRAME_CLEANUP_CACHE_ENTRY_AND_UNMARK(fp); /* mpc points to PTEXT */ if (ADDR_IN_CODE(fp->mpc, fp->rvector)) { /* GT.M specific error trapping retries the line with the error */ fp->mpc = dollar_ecode.error_last_b_line; fp->ctxt = context; fp->flags &= SFF_IMPLTSTART_CALLD_OFF; /* Frame enterable now with mpc reset */ GTMTRIG_ONLY( DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_IMPLTSTART_CALLD" " (5) in frame 0x"lvaddr"\n", frame_pointer))); break; } else { fp->ctxt = GTM_CONTEXT(pseudo_ret); fp->mpc = CODE_ADDRESS(pseudo_ret); fp->flags &= SFF_IMPLTSTART_CALLD_OFF; /* Frame enterable now with mpc reset */ GTMTRIG_ONLY( DBGTRIGR((stderr, "mdb_condition_handler: turning off SFF_IMPLTSTART_CALLD" " (6) in frame 0x"lvaddr"\n", frame_pointer))); } } } } if (clean_mum_tstart()) { if (err_dev) { # ifdef UNIX /* On z/OS, if opening a fifo which is not read only we need to fix the err_dev type to rm */ # ifdef __MVS__ if ((dev_open != err_dev->state) && (ff == err_dev->type)) { assert(NULL != err_dev->pair.out); if (rm == err_dev->pair.out->type) { /* Have to massage the device so remove_rms will cleanup the partially * created fifo. Refer to io_open_try.c for creation of split fifo device. */ err_dev->newly_created = 1; err_dev->type = rm; err_dev->dev_sp = err_dev->pair.out->dev_sp; err_dev->pair.out->dev_sp = NULL; } } # endif if ((dev_open != err_dev->state) && (rm == err_dev->type)) { gtm_err_dev = err_dev; /* structures pointed to by err_dev were freed so make sure it's not used again */ err_dev = NULL; } # endif if (err_dev && (gtmsocket == err_dev->type) && err_dev->newly_created) { assert(err_dev->state != dev_open); assert(reserve_sock_dev); gtm_err_dev = err_dev; err_dev = NULL; } } MUM_TSTART_FRAME_CHECK; MUM_TSTART; } else { /* err_act is null, we can remove the socket device */ if (err_dev && (gtmsocket == err_dev->type) && err_dev->newly_created && !reserve_sock_dev) { assert(err_act == NULL); assert(err_dev->state != dev_open); iosocket_destroy(err_dev); err_dev = NULL; } DBGEHND((stderr, "mdb_condition_handler: clean_mum_tstart returned FALSE\n")); } } else { DBGEHND((stderr, "mdb_condition_handler: Transient or direct mode frame -- bypassing handler dispatch\n")); if (err_dev) { # ifdef UNIX /* Executed from the direct mode so do the rms check and cleanup if necessary. On z/OS, if opening a fifo * which is not read only we need to fix the type for the err_dev to rm. */ # ifdef __MVS__ if ((dev_open != err_dev->state) && (ff == err_dev->type)) { assert(NULL != err_dev->pair.out); if (rm == err_dev->pair.out->type) { /* Have to massage the device so remove_rms will cleanup the partially created fifo */ err_dev->newly_created = 1; err_dev->type = rm; err_dev->dev_sp = err_dev->pair.out->dev_sp; err_dev->pair.out->dev_sp = NULL; } } # endif if ((dev_open != err_dev->state) && (rm == err_dev->type)) { remove_rms(err_dev); err_dev = NULL; } # endif if (err_dev && (gtmsocket == err_dev->type) && err_dev->newly_created) { assert(err_dev->state != dev_open); iosocket_destroy(err_dev); err_dev = NULL; } } } if (((SFT_ZINTR | SFT_COUNT) != proc_act_type) || (0 == dollar_ecode.error_last_b_line)) { /* No user console error for $zinterrupt compile problems and if not direct mode. Accomplish * this by bypassing the code inside this if which *will* be executed for most cases */ DBGEHND((stderr, "mdb_condition_handler: Printing error status\n")); /* If we have a transcendental frame, we won't have driven an error handler but neither do we want to * push this error out at this point. The call to trans_code_cleanup() below will null this frame and * any other up to the next counted frame out by changing their mpc to pseudo_ret and will rethrow the * error we have here so there is no need to push this error out here for anything but direct mode. */ UNIX_ONLY(if (dm_action)) { PRN_ERROR; if (TREF(compile_time) && (((int)ERR_LABELMISSING) != SIGNAL)) show_source_line(TRUE); } } /* Slight divergence in how we handle otherwise unhandled errors on UNIX and VMS. UNIX now has a strict no-unsolicited * output from error messages policy unless dealing with a direct mode frame. This has a dependency on a robust * error_return() routine which VMS does not presently have. Consequently the previous way of doing things still * exists on VMS while on UNIX, a new cleaner (from an unsolicited console output) viewpoint is in place. Note that * while it would be possible to extract out the common code between the two below versions, the result is nowhere * near as clean looking. In this routine, clarity rules the roost. */ # ifdef UNIX if (trans_action || dm_action) { /* If true transcendental, do trans_code_cleanup(). If our counted frame is * masquerading as a transcendental frame, run jobinterrupt_process_cleanup(). */ DBGEHND((stderr, "mdb_condition_handler: trans_code_cleanup() or jobinterrupt_process_cleanup being " "dispatched\n")); if (!(SFT_ZINTR & proc_act_type)) trans_code_cleanup(); else jobinterrupt_process_cleanup(); MUM_TSTART_FRAME_CHECK; MUM_TSTART; } # elif VMS /* VMS only */ if (!dm_action && !trans_action && (0 != src_line_d.len)) { if (MSG_OUTPUT) dec_err(VARLSTCNT(4) ERR_RTSLOC, 2, src_line_d.len, src_line_d.addr); } else { if (trans_action || dm_action) { /* If true transcendental, do trans_code_cleanup(). If our counted frame is * masquerading as a transcendental frame, run jobinterrupt_process_cleanup(). */ DBGEHND((stderr, "mdb_condition_handler: trans_code_cleanup() or jobinterrupt_process_cleanup being " "dispatched\n")); if (!(SFT_ZINTR & proc_act_type)) trans_code_cleanup(); else jobinterrupt_process_cleanup(); MUM_TSTART_FRAME_CHECK; MUM_TSTART; } else if (MSG_OUTPUT) { /* If a message about the location is needed, it should be possible to pull the location * out of the $STACK array. If it exists, use it instead. */ if ((NULL != dollar_stack.array) && (0 < dollar_stack.index)) { /* Error entry exists */ src_line_d = dollar_stack.array[dollar_stack.index - 1].place_str; assert(src_line_d.len); assert(src_line_d.addr); dec_err(VARLSTCNT(4) ERR_RTSLOC, 2, src_line_d.len, src_line_d.addr); } else dec_err(VARLSTCNT(1) ERR_SRCLOCUNKNOWN); } } # else # error "Unsupported platform" # endif DBGEHND((stderr, "mdb_condition_handler: Condition not handled -- defaulting to process exit\n")); MUMPS_EXIT; } fis-gtm-V6.0-003/sr_port/mdef.h0000644000032200000250000022555712201176177015142 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef MDEF_included #define MDEF_included /* mstr needs to be defined before including "mdefsp.h". */ typedef int mstr_len_t; #ifndef __vms typedef struct { unsigned int char_len; /* Character length */ mstr_len_t len; char *addr; } mstr; # define MSTR_CONST(name, string) mstr name = {0, LEN_AND_LIT(string)} # define MSTR_DEF(name, length, string) mstr name = {0, length, string} # define MIDENT_CONST(name, string) mident name = {0, LEN_AND_LIT(string)} # define MIDENT_DEF(name, length, string) mident name = {0, length, string} #else typedef struct { mstr_len_t len; /* Byte length */ char *addr; } mstr; # define MSTR_CONST(name, string) mstr name = {LEN_AND_LIT(string)} # define MSTR_DEF(name, length, string) mstr name = {length, string} # define MIDENT_CONST(name, string) mident name = {LEN_AND_LIT(string)} # define MIDENT_DEF(name, length, string) mident name = {length, string} #endif #define GET_MSTR_LEN(X, Y) GET_ULONG(X, Y) #define PUT_MSTR_LEN(X, Y) PUT_ULONG(X, Y) #define MEMVCMP(STR1, STR1LEN, STR2, STR2LEN, RESULT) \ { \ int lcl_str1Len, lcl_str2Len; \ int lcl_minLen, lcl_retVal, lcl_retVal2; \ \ lcl_str1Len = STR1LEN; \ lcl_str2Len = STR2LEN; \ if (lcl_str1Len < lcl_str2Len) \ { \ lcl_minLen = lcl_str1Len; \ lcl_retVal = -1; \ } else if (lcl_str1Len > lcl_str2Len) \ { \ lcl_minLen = lcl_str2Len; \ lcl_retVal = 1; \ } else \ { \ lcl_minLen = lcl_str1Len; \ lcl_retVal = 0; \ } \ RESULT = (0 == (lcl_retVal2 = memcmp(STR1, STR2, lcl_minLen))) ? lcl_retVal : lcl_retVal2; \ } /* There are 2 MSTR*CMP macros. One is if the parameters are available as MSTRs and another if the parameters * are available as MSTR pointers. Use whichever is appropriate as it saves cycles. */ #define MSTRP_CMP(x, y, result) MEMVCMP((x)->addr, (x)->len, (y)->addr, (y)->len, result) #define MSTR_CMP(x, y, result) MEMVCMP((x).addr, (x).len, (y).addr, (y).len, result) #define MSTR_EQ(x, y) (((x)->len == (y)->len) && !memcmp((x)->addr, (y)->addr, (x)->len)) #include typedef int int4; /* 4-byte signed integer */ typedef unsigned int uint4; /* 4-byte unsigned integer */ #define sssize_t size_t /* If ever the following macro (SHMDT) is expanded to a multi-line macro, care should be taken to save the errno immediately after * the "shmdt" system call invocation to avoid errno from being mutated by subsequent system calls. */ #define SHMDT(X) shmdt((void *)(X)) /* constant needed for FIFO - OS390 redefines in mdefsp.h */ #define FIFO_PERMISSION 010666 /* fifo with RW permissions for owner, group, other */ #include #include "mdefsa.h" #include "gtm_common_defs.h" #include #include "gtm_sizeof.h" #include "gtm_threadgbl.h" /* Anchor for thread-global structure rather than individual global vars */ GBLREF void *gtm_threadgbl; /* Accessed through TREF macro in gtm_threadgbl.h */ #ifdef DEBUG error_def(ERR_ASSERT); # define assert(x) ((x) ? 1 : rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_ASSERT, 5, LEN_AND_LIT(__FILE__), __LINE__, \ (SIZEOF(#x) - 1), (#x))) # ifdef UNIX # define GTMDBGFLAGS_ENABLED # endif #else # define assert(x) #endif #ifdef GTM64 # define lvaddr "%016lx" #else # define lvaddr "%08lx" #endif /* Define GT.M interlude functions for open, close, pipe, creat and dup system calls. This lets GT.M trace through all file * descriptor activity (needed for D9I11-002714). Do this on all Unix platforms. Note that only the macro GTM_FD_TRACE is * defined here. gtm_unistd.h and gtm_fcntl.h define the actual GT.M interlude functions based on this macro. */ #if defined(UNIX) # define GTM_FD_TRACE # define GTM_FD_TRACE_ONLY(X) X #else # define GTM_FD_TRACE_ONLY(X) #endif /* Define what is an invalid file descriptor in Unix and VMS. */ #if defined(UNIX) # define FD_INVALID -1 /* fd of -1 is invalid in Unix posix calls */ # define FD_INVALID_NONPOSIX FD_INVALID #else # define FD_INVALID -1 /* fd of -1 is invalid in VMS if using POSIX interface (open/close etc.) */ # define FD_INVALID_NONPOSIX 0 /* fd of 0 is invalid in VMS if using RMS sys$open calls (non-posix interface) */ #endif #if defined(UNIX) # define USE_POLL # define POLL_ONLY(X) X # define SELECT_ONLY(X) #else # define USE_SELECT # define POLL_ONLY(X) # define SELECT_ONLY(X) X #endif /* INTPTR_T is an integer that has the same length as a pointer on each platform. Its basic use is for arithmetic * or generic parameters. For all platforms except Tru64/VMS (alpha platforms), the [U]INTPTR_T types will be * equivalenced to [u]intptr_t. But since this type is used for alignment and other checking, and since Tru64/VMS * (implemented as a 32 bit platform) unconditionally sets this type to its 8 char variant, on Tru64/VMS we will * explicitly make [U]INTPTR_T a 4 byte creature. */ #if !defined(__alpha) typedef intptr_t INTPTR_T; typedef uintptr_t UINTPTR_T; #else typedef int INTPTR_T; typedef unsigned int UINTPTR_T; #endif /* The intszofptr_t type is defined to be basically the same size as an address on the platforms it runs on. So it is the same size as INTPTR_T without the connotation of being a pointer. This is used in places where size_t or ssize_t would normally be used except they can't be used because they are the wrong size on Alpha systems. Classic usage is in places where need consistant integer and pointer sized elements like constructed parameter lists or other arrays. */ typedef INTPTR_T intszofptr_t; typedef UINTPTR_T uintszofptr_t; #ifdef GTM64 # define USER_STACK_SIZE 8192 # define VA_ARG_TYPE long # define VA_ARG_TYPE_BOOL int # define GTM_IS_64BIT TRUE # define GTM_BITNESS_THIS "64-bit" # define GTM_BITNESS_OTHER "32-bit" #else # define USER_STACK_SIZE 4096 # define VA_ARG_TYPE int # define VA_ARG_TYPE_BOOL int # define GTM_IS_64BIT FALSE # define GTM_BITNESS_THIS "32-bit" # define GTM_BITNESS_OTHER "64-bit" #endif /* GTM64 */ #ifdef __CYGWIN__ # define CYGWIN_ONLY(X) X #else # define CYGWIN_ONLY(X) #endif #ifdef __linux__ # define LINUX_ONLY(X) X # define NON_LINUX_ONLY(X) #else # define LINUX_ONLY(X) # define NON_LINUX_ONLY(X) X #endif #ifdef __MVS__ # define ZOS_ONLY(X) X #else # define ZOS_ONLY(X) #endif #ifdef Linux390 # define Linux390_ONLY(X) X #else # define Linux390_ONLY(X) #endif #if !defined(__alpha) && !defined(__sparc) && !defined(__hpux) && !defined(mips) && !defined(__ia64) # define UNALIGNED_ACCESS_SUPPORTED #endif #if defined(__i386) || defined(__x86_64__) || defined(_AIX) || defined (__sun) # define GTM_PTHREAD # define GTM_PTHREAD_ONLY(X) X #else # define GTM_PTHREAD_ONLY(X) #endif #if defined(__ia64) # define IA64_ONLY(X) X # define NON_IA64_ONLY(X) # ifdef DEBUG # define IA64_DEBUG_ONLY(X) X # else # define IA64_DEBUG_ONLY(X) # endif /* DEBUG */ #else # define IA64_ONLY(X) # define NON_IA64_ONLY(X) X # define IA64_DEBUG_ONLY(X) #endif/* __ia64 */ /* macro to check that the OFFSET & SIZE of TYPE1.MEMBER1 is identical to that of TYPE2.MEMBER2 */ #define IS_OFFSET_AND_SIZE_MATCH(TYPE1, MEMBER1, TYPE2, MEMBER2) \ (SIZEOF(((TYPE1 *)NULL)->MEMBER1) == SIZEOF(((TYPE2 *)NULL)->MEMBER2)) \ && (OFFSETOF(TYPE1, MEMBER1) == OFFSETOF(TYPE2, MEMBER2)) #define IS_OFFSET_MATCH(TYPE1, MEMBER1, TYPE2, MEMBER2) (OFFSETOF(TYPE1, MEMBER1) == OFFSETOF(TYPE2, MEMBER2)) #ifdef __x86_64__ #define X86_64_ONLY(x) x #define NON_X86_64_ONLY(x) #else #define X86_64_ONLY(x) #define NON_X86_64_ONLY(x) x #endif /* __x86_64__ */ #if defined(__i386) || defined(__x86_64__) || defined(__ia64) || defined(__MVS__) || defined(Linux390) #define NON_RISC_ONLY(x) x #define RISC_ONLY(x) #elif defined(__sparc) || defined(_AIX) || defined(__hppa) || defined(__alpha) #define RISC_ONLY(x) x #define NON_RISC_ONLY(x) #endif #ifdef _AIX # define AIX_ONLY(X) X #else # define AIX_ONLY(X) #endif #ifdef __sparc # define SPARC_ONLY(X) X #else #define SPARC_ONLY(X) #endif #define BITS_PER_UCHAR 8 /* note, C does not require this to be 8, see for definitions of CHAR_BIT and UCHAR_MAX */ #define MAXPOSINT4 ((int4)0x7fffffff) #define MAX_DIGITS_IN_INT 10 /* maximum number of decimal digits in a 4-byte integer */ #define MAX_DIGITS_IN_INT8 20 /* maximum number of decimal digits in an 8-byte integer */ #define MAX_HEX_DIGITS_IN_INT 8 /* maximum number of hexadecimal digits in a 4-byte integer */ #define MAX_HEX_DIGITS_IN_INT8 16 /* maximum number of hexadecimal digits in an 8-byte integer */ #define MAX_DIGITS_IN_EXP 2 /* maximum number of decimal digits in an exponent */ #define MAX_HOST_NAME_LEN 256 #define MAX_LONG_IN_DOUBLE 0xFFFFFFFFFFFFF /*Max Fraction part in IEEE double format*/ #ifndef _AIX # ifndef __sparc typedef int boolean_t; # endif #endif typedef char bool; typedef unsigned char mreg; typedef int4 mint; #define PRE_V5_MAX_MIDENT_LEN 8 /* Maximum length of an mident/mname before GT.M V5.0 */ typedef struct { /* The old mident structure used before V50FT01 */ char c[PRE_V5_MAX_MIDENT_LEN]; } pre_v5_mident; #define MAX_MIDENT_LEN 31 /* Maximum length of an mident/mname */ typedef mstr mident; typedef struct { /* Although we use 31 chars, the extra byte is to keep things aligned AND to keep a null terminator byte for places that care */ char c[MAX_MIDENT_LEN + 1]; } mident_fixed; #define mid_len(name) strlen(&(name)->c[0]) /* callers of mid_len should include gtm_string.h as well */ #define MIDENT_CMP(x,y,result) MSTRP_CMP(x, y, result) #define MIDENT_EQ(x,y) MSTR_EQ(x, y) #ifdef INT8_NATIVE # define NATIVE_WSIZE 8 #else # define NATIVE_WSIZE 4 #endif /* Maximum length of entry reference of the form "label+offset^routine" */ #define MAX_ENTRYREF_LEN (2 * MAX_MIDENT_LEN + MAX_DIGITS_IN_INT + STR_LIT_LEN("+^")) /* M name entry used in various structures - variable table (rtnhdr.h), hash table (hashtab_def.h) and * global variable (gv_namehead in gdsfhead.h) */ typedef struct { mident var_name; /* var_name.addr points to the actual variable name */ uint4 hash_code; /* hash (scrambled) value of the variable name text */ boolean_t marked; /* Used when in hashtable entry for xkill (at least) */ } mname_entry; /* The M stack frame on all platforms that follow pv-based linkage model (alpha model) * contains a pointer to the base of routine's literal section. All such platforms * must define HAS_LITERAL_SECT so that the routines that create a new stack frame * initialize literal_ptr field apppropriately. * */ #if defined(__alpha) || defined(_AIX) || defined(__hpux) || defined(__sparc) || defined(__MVS__) || (defined(__linux__) && \ (defined(__ia64) || defined(__x86_64__) || defined(__s390__))) # define HAS_LITERAL_SECT #endif typedef long ulimit_t; /* NOT int4; the Unix ulimit function returns a value of type long */ /* Bit definitions for mval type (mvtype) */ #define MV_NM 1 /* 0x0001 */ #define MV_INT 2 /* 0x0002 * Note: this bit is set for integers and non-integers with <= 3 digits after the decimal point */ #define MV_NUM_MASK 3 /* 0x0003 (MV_NM | MV_INT) */ #define MV_STR 4 /* 0x0004 */ #define MV_NUM_APPROX 8 /* 0x0008 */ /* bit set implies value is guaranteed to be part number, part string */ #define MV_CANONICAL 16 /* 0x0010 * Note: this bit is set currently only for mvals corresponding to local variable subscripts * in lv_tree.c/lv_tree.h. This bit should not be examined/relied-upon anywhere outside lv_tree.c */ #define MV_SYM 32 /* 0x0020 */ #define MV_SUBLIT 64 /* 0x0040 */ #define MV_RETARG 128 /* 0x0080 */ #define MV_UTF_LEN 256 /* 0x0100 */ #define MV_ALIASCONT 512 /* 0x0200 */ #define MV_INT_OFF ~(MV_INT) /* Mask to turn off MV_INT */ #define MV_STR_OFF ~(MV_STR) /* Mask to turn off MV_STR */ #define MV_CANONICAL_OFF ~(MV_CANONICAL) /* Mask to turn off MV_CANONICAL */ #define MV_UTF_LEN_OFF ~(MV_UTF_LEN) /* Mask to turn off MV_UTF_LEN */ #define MV_EXT_NUM_MASK (MV_NM | MV_INT | MV_CANONICAL) /* Special definition used when an xnew'd lv_val is moved from a popped symtab to an earlier * one so it can be preserved. This flag marks the lv_val as a pointer to the new symtab so * multiple references to it can be resolved. */ #define MV_LVCOPIED 0xf000 /* A few more special definitions */ #define MV_LV_TREE 0xf001 /* An "lvTree" structure has its "ident" field set to this special value */ #define MV_XBIAS 62 #define MV_XZERO 0 #define MV_BIAS 1000 #define MV_BIAS_PWR 3 #define NR_REG 16 #define NUL 0x00 #define SP 0x20 #define DEL 0x7f #define MAX_STRLEN_32K 32767 /* MAX_STRLEN for local variable is changed from 32767 to 1048576 (1 MB) */ #define MAX_STRLEN (1 * 1024 * 1024) /*maximum GT.M string size (1 MB)*/ #define MAX_DBSTRLEN (32 * 1024 - 1) /* Maximum database string size */ /* Initial buffer size allocated for a GT.M string which can geometrically be increased upto the size enough to fit in MAX_STRLEN */ #define MAX_STRBUFF_INIT (32 * 1024) #define MAX_NUM_SIZE 64 #define MAX_FORM_NUM_SUBLEN 128 /* this is enough to hold the largest numeric subscript */ #define PERIODIC_FLUSH_CHECK_INTERVAL (30 * 1000) #ifndef __sparc # define MAX_ARGS 256 /* in formallist */ #else /* Sparc super frame has room for 256 args, but functions or concatenate are limited to somewhat fewer */ # define MAX_ARGS 242 #endif #ifdef UNIX # define MAX_KEY_SZ 1023 /* maximum database key size */ #else # define MAX_KEY_SZ 255 #endif # define OLD_MAX_KEY_SZ 255 /* For V5 and earlier, when only 1 byte was used for compression count */ /* The macro ZWR_EXP_RATIO returns the inflated length when converting the internal subscript * representation (byte) length to ZWR representation. * In "M" mode, * Worst case is every other character is non-graphic. e.g. $C(128)_"A"_$C(128). * In "UTF-8" mode, * Worst case is with a non-graphic character and every other character is an illegal * character. Here are the expansion ratios for different ranges of characters. * ------------------------------------------------------------------------------ * Byte pattern max. expanded input byte ratio * output length length * ------------------------------------------------------------------------------ * $C(129)_$ZCH(128)_ 18 2 9 * $C(1536)_$ZCH(128)_ 19 3 7 * $C(65279)_$ZCH(128)_ 20 4 5 * $C(917585)_$ZCH(128)_ 21 5 6 * $C(1114111)_$ZCH(128)_ 22 5 6 * ------------------------------------------------------------------------------ * To cover cases of odd numbers of characters, add some buffer. * * MAX_ZWR_KEY_SZ, on the other hand, needs to be a compile-time constant since it's used in * temporary allocation on the stack */ GBLREF boolean_t gtm_utf8_mode; #ifdef UNICODE_SUPPORTED # define ZWR_EXP_RATIO(X) ((!gtm_utf8_mode) ? (((X) * 6 + 7)) : ((X) * 9 + 11)) # define MAX_ZWR_KEY_SZ (MAX_KEY_SZ * 9 + 11) # define MAX_ZWR_EXP_RATIO 9 #else # define ZWR_EXP_RATIO(X) ((X) * 6 + 7) # define MAX_ZWR_KEY_SZ (MAX_KEY_SZ * 6 + 7) # define MAX_ZWR_EXP_RATIO 6 #endif #define MAX_SYSERR 1000000 unsigned char *n2s(mval *mv_ptr); char *s2n(mval *u); mval *underr (mval *start, ...); mval *underr_strict(mval *start, ...); #ifdef DEBUG # define DBG_ASSERT(X) assert(X), #else # define DBG_ASSERT(X) #endif /* Use the "D" format of these MV_FORCE macros only in those places where there is no possibility of the input being undefined */ #define MV_FORCE_STR(X) (MV_FORCE_DEFINED(X), MV_FORCE_STRD(X)) #define MV_FORCE_STRD(X) (DBG_ASSERT(MV_DEFINED(X)) (0 == ((X)->mvtype & MV_STR)) ? n2s(X) : NULL) #define MV_FORCE_NUM(X) (MV_FORCE_DEFINED(X), MV_FORCE_NUMD(X)) #define MV_FORCE_NUMD(X) (DBG_ASSERT(MV_DEFINED(X)) (0 == ((X)->mvtype & MV_NM )) ? s2n(X) : NULL) #define MV_FORCE_BOOL(X) (MV_FORCE_NUM(X), (X)->m[1] ? TRUE : FALSE) #define MV_FORCE_INT(M) (MV_FORCE_DEFINED(M), MV_FORCE_INTD(M)) #define MV_FORCE_INTD(M) (DBG_ASSERT(MV_DEFINED(M)) (M)->mvtype & MV_INT ? (M)->m[1]/MV_BIAS : mval2i(M)) #define MV_FORCE_UMVAL(M,I) (((I) >= 1000000) ? i2usmval((M),(int)(I)) : \ (void)( (M)->mvtype = MV_NM | MV_INT , (M)->m[1] = (int)(I)*MV_BIAS )) #define MV_FORCE_MVAL(M,I) (((I) >= 1000000 || (I) <= -1000000) ? i2mval((M),(int)(I)) : \ (void)( (M)->mvtype = MV_NM | MV_INT , (M)->m[1] = (int)(I)*MV_BIAS )) #ifdef GTM64 #define MV_FORCE_ULMVAL(M,L) (((L) >= 1000000) ? ui82mval((M),(gtm_uint64_t)(L)) : \ (void)( (M)->mvtype = MV_NM | MV_INT , (M)->m[1] = (int)(L)*MV_BIAS )) #define MV_FORCE_LMVAL(M,L) (((L) >= 1000000 || (L) <= -1000000) ? i82mval((M),(gtm_int64_t)(L)) : \ (void)( (M)->mvtype = MV_NM | MV_INT , (M)->m[1] = (int)(L)*MV_BIAS )) #else #define MV_FORCE_ULMVAL MV_FORCE_UMVAL #define MV_FORCE_LMVAL MV_FORCE_MVAL #endif #define MV_FORCE_DEFINED(X) ((!MV_DEFINED(X)) ? (X) = underr(X) : (X)) /* Note MV_FORCE_CANONICAL currently only used in op_add() when vars are known to be defined so no MV_FORCE_DEFINED() macro has been added. If uses are added, this needs to be revisited. 01/2008 se */ #define MV_FORCE_CANONICAL(X) ((((X)->mvtype & MV_NM) == 0 ? s2n(X) : 0 ) \ ,((X)->mvtype & MV_NUM_APPROX ? (X)->mvtype &= MV_NUM_MASK : 0 )) #define MV_IS_NUMERIC(X) (((X)->mvtype & MV_NM) != 0) #define MV_IS_INT(X) (((X)->mvtype & MV_INT) != 0) /* returns TRUE if input has MV_INT bit set */ #define MV_IS_TRUEINT(X, INTVAL_P) (isint(X, INTVAL_P)) /* returns TRUE if input is a true integer (no fractions) */ #define MV_IS_STRING(X) (((X)->mvtype & MV_STR) != 0) #define MV_DEFINED(X) (((X)->mvtype & (MV_STR | MV_NM)) != 0) #define MV_IS_CANONICAL(X) (((X)->mvtype & MV_NM) ? (((X)->mvtype & MV_NUM_APPROX) == 0) : (boolean_t)val_iscan(X)) #define MV_INIT(X) ((X)->mvtype = 0, (X)->fnpc_indx = 0xff) #define MV_INIT_STRING(X, LEN, ADDR) ((X)->mvtype = MV_STR, (X)->fnpc_indx = 0xff, \ (X)->str.len = INTCAST(LEN), (X)->str.addr = (char *)ADDR) /* The MVTYPE_IS_* macros are similar to the MV_IS_* macros except that the input is an mvtype instead of an "mval *". * In the caller, use appropriate macro depending on available input. Preferable to use the MVTYPE_IS_* variant to avoid * the (X)->mvtype dereference */ #define MVTYPE_IS_NUMERIC(X) (0 != ((X) & MV_NM)) #define MVTYPE_IS_INT(X) (0 != ((X) & MV_INT)) #define MVTYPE_IS_NUM_APPROX(X) (0 != ((X) & MV_NUM_APPROX)) #define MVTYPE_IS_STRING(X) (0 != ((X) & MV_STR)) /* DEFINE_MVAL_LITERAL is intended to be used to define a string mval where the string is a literal or defined with type * "readonly". In other words, the value of the string does not change. Since we expect all callers of this macro to use * ASCII literals, the MV_UTF_LEN bit is set in the type, and the character length is set to the same value as the byte length. */ #define DEFINE_MVAL_LITERAL(TYPE, EXPONENT, SIGN, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH) \ DEFINE_MVAL_COMMON(TYPE | MV_UTF_LEN, EXPONENT, SIGN, LENGTH, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH) /* DEFINE_MVAL_STRING is intended to be used to define a string mval where the value of the string can change */ #define DEFINE_MVAL_STRING(TYPE, EXPONENT, SIGN, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH) \ DEFINE_MVAL_COMMON(TYPE, EXPONENT, SIGN, 0, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH) #ifdef VMS #define DEFINE_MVAL_COMMON(TYPE, EXPONENT, SIGN, UTF_LEN, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH) \ {TYPE, EXPONENT, SIGN, 0xff, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH} #else #ifdef BIGENDIAN #ifdef UNICODE_SUPPORTED #define DEFINE_MVAL_COMMON(TYPE, EXPONENT, SIGN, UTF_LEN, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH) \ {TYPE, SIGN, EXPONENT, 0xff, MANT_LOW, MANT_HIGH, UTF_LEN, LENGTH, ADDRESS} #else #define DEFINE_MVAL_COMMON(TYPE, EXPONENT, SIGN, UTF_LEN, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH) \ {TYPE, SIGN, EXPONENT, 0xff, MANT_LOW, MANT_HIGH, LENGTH, ADDRESS} #endif #else /* BIGENDIAN */ #ifdef UNICODE_SUPPORTED #define DEFINE_MVAL_COMMON(TYPE, EXPONENT, SIGN, UTF_LEN, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH) \ {TYPE, EXPONENT, SIGN, 0xff, MANT_LOW, MANT_HIGH, UTF_LEN, LENGTH, ADDRESS} #else #define DEFINE_MVAL_COMMON(TYPE, EXPONENT, SIGN, UTF_LEN, LENGTH, ADDRESS, MANT_LOW, MANT_HIGH) \ {TYPE, EXPONENT, SIGN, 0xff, MANT_LOW, MANT_HIGH, LENGTH, ADDRESS} #endif /* UNICODE */ #endif /* BIGENDIAN */ #endif /* VMS */ #define ASCII_MAX (unsigned char)0x7F #define IS_ASCII(X) ((uint4)(X) <= ASCII_MAX) /* X can be greater than 255 hence the typecast to uint4 */ #ifdef UNICODE_SUPPORTED # define MV_FORCE_LEN(X) ((!((X)->mvtype & MV_UTF_LEN)) \ ? (utf8_len(&(X)->str), ((X)->mvtype |= MV_UTF_LEN), (X)->str.char_len) \ : (X)->str.char_len) /* MV_FORCE_LEN_STRICT() is used to ensure that mval is valid in addition to computing the char_len. * Note that the validation is always forced even if MV_UTF_LEN is set since the previously computed * char_len might have been evaluated in VIEW "NOBADCHAR" setting. */ # define MV_FORCE_LEN_STRICT(X) (((X)->str.char_len = UTF8_LEN_STRICT((X)->str.addr, (X)->str.len)), \ ((X)->mvtype |= MV_UTF_LEN), (X)->str.char_len) # define MV_IS_SINGLEBYTE(X) (((X)->mvtype & MV_UTF_LEN) && ((X)->str.len == (X)->str.char_len)) #else # define MV_FORCE_LEN(X) ((X)->str.len) # define MV_FORCE_LEN_STRICT(X) ((X)->str.len) # define MV_IS_SINGLEBYTE(X) (TRUE) /* all characters are single-byte in non-Unicode platforms */ #endif #define DISK_BLOCK_SIZE 512 #define LOG2_DISK_BLOCK_SIZE 9 #ifdef DEBUG # define CHECKPOT(MODULUS) ((MODULUS) & ((MODULUS) - 1)) ? GTMASSERT, 0 : # define BREAK_IN_PRO__CONTINUE_IN_DBG continue # define DEBUG_ONLY(statement) statement # define DEBUG_ONLY_COMMA(statement) statement, # define PRO_ONLY(statement) #else # define CHECKPOT(MODULUS) # define BREAK_IN_PRO__CONTINUE_IN_DBG break # define DEBUG_ONLY(statement) # define DEBUG_ONLY_COMMA(statement) # define PRO_ONLY(statement) statement #endif /* These are the analogs of the preceding, but are more efficient when the MODULUS is a Power Of Two. * One thing to watch for is that VALUE could be 8-byte and MODULUS could be 4-bytes. In that case, we * want to return an 8-byte value. So need to typecast MODULUS to 8-bytes before we do "& ~(MODULUS -1)" * or else that will be a 4-byte value and cause a bitwise & with an 8-byte value resulting in a truncated * 8-byte return value (loss of high order bits). We choose sm_long_t to reflect that type as it is 8-bytes * on the 64-bit platforms and 4-bytes on the 32-bit platforms. Choosing gtm_uint64_t unconditionally will * make it 8-bytes on the 32-bit platforms too and result in warnings due to the 8-byte value eventually being * truncated to 4-bytes by the caller after the return from the below macro. */ #define ROUND_UP2(VALUE, MODULUS) (CHECKPOT(MODULUS) ((VALUE) + ((MODULUS) - 1)) & ~(((sm_long_t)MODULUS) - 1)) #define ROUND_DOWN2(VALUE, MODULUS) (CHECKPOT(MODULUS) (VALUE) & ~(((sm_long_t)MODULUS) - 1)) /* Length needed to pad out to a given power of 2 boundary */ #define PADLEN(value, bndry) (int)(ROUND_UP2((sm_long_t)(value), bndry) - (sm_long_t)(value)) /* LOG2_OF_INTEGER returns the ceiling of log (base 2) of number */ #define LOG2_OF_INTEGER(number, log2_of_number) \ { \ int temp = (number) - 1; \ for (log2_of_number = 0; 0 < temp; log2_of_number++) \ temp = (temp) >> 1; \ } #define CALLFROM LEN_AND_LIT(__FILE__), __LINE__ void gtm_assert(int file_name_len, char file_name[], int line_no); int gtm_assert2(int condlen, char *condtext, int file_name_len, char file_name[], int line_no); #define GTMASSERT (gtm_assert(CALLFROM)) #define assertpro(x) ((x) ? 1 : gtm_assert2((SIZEOF(#x) - 1), (#x), CALLFROM)) #ifdef UNIX #ifdef DEBUG /* The below debug only macros are always used in pairs to indicate a window where the code doesn't expect rts_errors to happen. * One reason why the code doesn't expect rts_errors is if the logic is complicated enough that having a condition handler for * the window is tricky and will not undo the state of various global variables that were modified. An example of such a window * is in gvcst_init. If an rts_error happens in this window, an assert will trip in rts_error at which point, the window as well * as the rts_error can be re-examined to see whether the rts_error can be removed or the range of the window can be changed. */ #define DBG_MARK_RTS_ERROR_USABLE { assert(TREF(rts_error_unusable)); TREF(rts_error_unusable) = FALSE; } #define DBG_MARK_RTS_ERROR_UNUSABLE { assert(!TREF(rts_error_unusable)); TREF(rts_error_unusable) = TRUE; } #else #define DBG_MARK_RTS_ERROR_USABLE #define DBG_MARK_RTS_ERROR_UNUSABLE #endif int rts_error(int argcnt, ...); int rts_error_csa(void *csa, int argcnt, ...); /* Use CSA_ARG(CSA) for portability */ #define CSA_ARG(CSA) (CSA), void dec_err(uint4 argcnt, ...); #elif defined(VMS) #define rts_error_csa rts_error #define CSA_ARG(CSA) /* no csa arg on VMS */ void dec_err(int4 msgnum, ...); #else #error unsupported platform #endif void stx_error(int in_error, ...); void ins_errtriple(int4 in_error); int4 timeout2msec(int4 timeout); /* the RTS_ERROR_TEXT macro will stay till all existing references to it have been renamed to RTS_ERROR_{LITERAL,STRING} */ #define RTS_ERROR_TEXT(STRING) LENGTH_AND_STRING(STRING) /* for those who prefer not remembering the order of the length and the literal/string in the rts_error command line */ #define RTS_ERROR_LITERAL(LITERAL) LENGTH_AND_LITERAL(LITERAL) #define RTS_ERROR_STRING(STRING) LENGTH_AND_STRING(STRING) #define SET_PROCESS_EXITING_TRUE \ { \ GBLREF int process_exiting; \ \ process_exiting = TRUE; \ } /* *********************************************************************************************************** */ /* Frequently used len + str combinations in macro form. */ /* *********************************************************************************************************** */ #define DB_STR_LEN(reg) (reg)->dyn.addr->fname, (reg)->dyn.addr->fname_len #define DB_LEN_STR(reg) (reg)->dyn.addr->fname_len, (reg)->dyn.addr->fname #define REG_STR_LEN(reg) (reg)->rname, (reg)->rname_len #define REG_LEN_STR(reg) (reg)->rname_len, (reg)->rname #define JNL_STR_LEN(csd) (csd)->jnl_file_name, (csd)->jnl_file_len #define JNL_LEN_STR(csd) (csd)->jnl_file_len, (csd)->jnl_file_name #define FAB_LEN_STR(fab) (fab)->fab$b_fns, (fab)->fab$l_fna /* *********************************************************************************************************** */ #ifdef DEBUG /* Original debug code has been removed since it was superfluous and did not work on all platforms. SE 03/01 */ # define SET_TRACEABLE_VAR(var,value) var = value; #else # define SET_TRACEABLE_VAR(var,value) var = value; #endif /* If this is unix, we have a faster sleep for short sleeps ( < 1 second) than doing a hiber start. * Take this chance to define UNIX_ONLY and VMS_ONLY macros. */ int m_usleep(int useconds); #ifdef UNIX # define SHORT_SLEEP(x) {assert(1000 > (x)); m_usleep((x) * 1000);} #else # define SHORT_SLEEP(x) hiber_start(x); #endif #ifdef UNIX # define UNIX_ONLY(X) X # define UNIX_ONLY_COMMA(X) X, #else # define UNIX_ONLY(X) # define UNIX_ONLY_COMMA(X) #endif /* HP-UX on PA-RISC and z/OS are not able to have dynamic file extensions while running in MM access mode * HP-UX: * All HP-UX before v3 (PA-RISC and 11i v1 and v2) have distinct memory map buffers and file system buffers with no simple * way to map between them. To get around this problem the "Unified File Cache" was implemented in v3 for both Itanium * and PA-RISC which solves things. The only way around the limitation in v1 and v2 would be to strategically place calls * to "msync" throughout the code to keep the memory maps and file cache buffers in sync. This is too onerous a price * to pay. * z/OS: * If multiple processes are accessing the same mapped file, and one process needs to extend/remap the file, * all the other processes must also unmap the file. * * This same comment is in the test framework in set_gtm_machtype.csh. If this comment is updated, also update the other. */ #ifdef UNIX # if !defined(__hppa) && !defined(__MVS__) # define MM_FILE_EXT_OK # else # undef MM_FILE_EXT_OK # endif #endif #ifdef VMS # define VMS_ONLY(X) X # define VMS_ONLY_COMMA(X) X, #else # define VMS_ONLY(X) # define VMS_ONLY_COMMA(X) #endif #if (defined(UNIX) || defined(VMS)) # define UNSUPPORTED_PLATFORM_CHECK #else # define UNSUPPORTED_PLATFORM_CHECK #error UNSUPPORTED PLATFORM #endif /* Note the macros below refer to the UNIX Shared Binary Support. Because the support is *specifically* for the Unix platform, "NON_USHBIN_ONLY()" will also be true for VMS even though that platform does have shared binary support (but it does not have Unix Shared Binary support). Use "NON_USHBIN_UNIX_ONLY()" for UNIX platforms that do not support Shared Binaries. */ #ifdef USHBIN_SUPPORTED # define USHBIN_ONLY(X) X # define NON_USHBIN_ONLY(X) # define NON_USHBIN_UNIX_ONLY(X) #else # define USHBIN_ONLY(X) # define NON_USHBIN_ONLY(X) X # ifdef UNIX # define NON_USHBIN_UNIX_ONLY(X) X # else # define NON_USHBIN_UNIX_ONLY(X) # endif #endif /* Unicode. Although most (all?) Unix platforms currently support Unicode, that may not always be the case so a separate contingent is defined. */ #ifdef UNICODE_SUPPORTED # define UNICODE_ONLY(X) X # define NON_UNICODE_ONLY(X) #else # define UNICODE_ONLY(X) # define NON_UNICODE_ONLY(X) X #endif /* Note: LONG_SLEEP *MUST*NOT* be the sleep() function because use of the sleep() function in GT.M causes problems with GT.M's timers on some platforms. Specifically, the sleep() function causes the SIGARLM handler to be silently deleted on Solaris systems (through Solaris 9 at least). This leads to lost timer pops and has the potential for system hangs. */ #define LONG_SLEEP(x) hiber_start((x) * 1000) #define OS_PAGE_SIZE gtm_os_page_size #define OS_PAGE_SIZE_DECLARE GBLREF int4 gtm_os_page_size; #ifdef VMS # define MAX_IO_BLOCK_SIZE DISK_BLOCK_SIZE #else # define MAX_IO_BLOCK_SIZE 65536 #endif #ifndef GTM_INT64T_DEFINED #define GTM_INT64T_DEFINED typedef uint64_t gtm_uint64_t; typedef int64_t gtm_int64_t; #endif typedef INTPTR_T sm_off_t; /* HPPA latches (used by load_and_clear) must be 16 byte aligned. * By allocating 16 bytes, the routines and macros used to access the latch can do the alignment. * Since nothing else should follow to avoid cache threshing, this doesn't really waste space. * Note that the additional space for this latch is only allocated on HPPA. All other platforms * have a "sensible" compare-and-swap type lock using the first two words in the latch. */ typedef struct { union { gtm_uint64_t pid_imgcnt; /* Combined atomic (unique) process id used on VMS */ struct { volatile int4 latch_pid; /* (Usually) Process id of latch holder or LOCK_AVAILABLE. On VMS this word may have other values. */ volatile int4 latch_word; /* Extra word associated with lock (sometimes bci lock or image cnt for VMS) */ } parts; } u; #if defined __hppa volatile int4 hp_latch_space[4]; /* Used for HP load_and_clear locking instructions per HP whitepaper on spinlocks */ #endif } global_latch_t; #define latch_image_count latch_word #define GLOBAL_LATCH_HELD_BY_US(latch) (process_id == (latch)->u.parts.latch_pid \ VMS_ONLY(&& image_count == (latch)->u.parts.latch_image_count)) typedef struct compswap_time_field_struct { /* This structure is used where we want to do a compare-n-swap (CAS) on a time value. The CAS interfaces * need an instance of global_latch_t to operate on. We will utilize the "latch_pid" field to hold the * time and the latch_word is unused except on VMS where it will hold 0. Since this structure must be of * a constant size (size of global_latch_t varies), pad the latch with sufficient space to match the * size of global_latch_t's largest size (on HPUX). */ global_latch_t time_latch; #ifndef __hppa int4 hp_latch_space[4]; /* padding only on non-hpux systems */ #endif } compswap_time_field; /* takes value of time() but needs to be 4 byte so can use compswap on it. Not using time_t, as that is an indeterminate size on * various platforms. Value is time (in seconds) in a compare/swap updated field so only one process performs a given task in a * given interval */ #define cas_time time_latch.u.parts.latch_pid typedef union gtm_time8_struct { time_t ctime; /* For current GTM code sem_ctime field corresponds to creation time */ int4 filler[2]; /* Filler to ensure size is 2 words on all platforms */ } gtm_time8; typedef uint4 gtm_time4_t; typedef struct { sm_off_t fl; /* forward link - relative offset from beginning of this element to next element in queue */ sm_off_t bl; /* backward link - relative offset from beginning of this element to previous element in queue */ } que_ent; /* this structure is intended to be identical to the first two items in a cache_que_head */ typedef struct { sm_off_t fl; /* forward link - relative offset from beginning of this element to next element in queue */ sm_off_t bl; /* backward link - relative offset from beginning of this element to previous element in queue */ global_latch_t latch; /* required for platforms without atomic operations to modify both fl and bl concurrently; * unused on platforms with such instructions. */ } que_head, cache_que_head; #define IS_PTR_ALIGNED(ptr, ptr_base, elemSize) \ (0 == ((((sm_uc_ptr_t)(ptr)) - ((sm_uc_ptr_t)(ptr_base))) % elemSize)) #define IS_PTR_IN_RANGE(ptr, ptr_lo, ptr_hi) \ (((sm_uc_ptr_t)(ptr) >= (sm_uc_ptr_t)(ptr_lo)) && ((sm_uc_ptr_t)(ptr) < (sm_uc_ptr_t)(ptr_hi))) #define IS_PTR_2BYTE_ALIGNED(ptr) (0 == (((uintszofptr_t)ptr) % 2)) #define IS_PTR_4BYTE_ALIGNED(ptr) (0 == (((uintszofptr_t)ptr) % 4)) #define IS_PTR_8BYTE_ALIGNED(ptr) (0 == (((uintszofptr_t)ptr) % 8)) #ifdef DB64 # ifdef __osf__ # pragma pointer_size(save) # pragma pointer_size(long) # else # error UNSUPPORTED PLATFORM # endif #endif typedef que_ent * que_ent_ptr_t; typedef que_head * que_head_ptr_t; #ifdef DB64 # ifdef __osf__ # pragma pointer_size(restore) # endif #endif /* Define 8-bytes as a structure containing 2-byte array of uint4s. Overlay this structure upon an 8 byte quantity for easy * access to the lower or upper 4 bytes using lsb_index and msb_index respectively. */ typedef struct { uint4 value[2]; } non_native_uint8; # define BIG_ENDIAN_MARKER 'B' /* to denote BIG-ENDIAN machine */ # define LITTLE_ENDIAN_MARKER 'L' /* to denote LITTLE-ENDIAN machine */ #ifdef BIGENDIAN # define msb_index 0 # define lsb_index 1 # define NODE_ENDIANNESS BIG_ENDIAN_MARKER # define ENDIANTHIS "BIG" # define ENDIANOTHER "LITTLE" # define ENDIANTHISJUSTIFY " BIG" /* right justified */ # define GTM_IS_LITTLE_ENDIAN FALSE # define BIGENDIAN_ONLY(X) X # define LITTLEENDIAN_ONLY(X) #else # define msb_index 1 # define lsb_index 0 # define NODE_ENDIANNESS LITTLE_ENDIAN_MARKER # define ENDIANTHIS "LITTLE" # define ENDIANOTHER "BIG" # define ENDIANTHISJUSTIFY "LITTLE" /* right justified */ # define GTM_IS_LITTLE_ENDIAN TRUE # define BIGENDIAN_ONLY(X) # define LITTLEENDIAN_ONLY(X) X #endif #ifdef INT8_SUPPORTED typedef gtm_uint64_t qw_num; typedef gtm_uint64_t seq_num; /* Define 8-byte sequence number */ typedef gtm_uint64_t token_num; /* Define 8-byte token number */ typedef gtm_uint64_t qw_off_t; /* quad-word offset */ # define DWASSIGNQW(A,B) (A)=(uint4)(B) # define QWASSIGN(A,B) (A)=(B) # define QWASSIGNDW(A,B) QWASSIGN((A),(gtm_uint64_t)(B)) # define QWASSIGN2DW(A,B,C) QWASSIGN((A),(gtm_uint64_t)(B) << 32 | (C)) # define QWADD(A,B,C) (A)=(B)+(C) # define QWSUB(A,B,C) (A)=(B)-(C) # define QWADDDW(A,B,C) (A)=(B)+(gtm_uint64_t)(C) # define QWSUBDW(A,B,C) (A)=(B)-(gtm_uint64_t)(C) # define QWINCRBY(A,B) (A)+=(B) # define QWDECRBY(A,B) (A)-=(B) # define QWINCRBYDW(A,B) (A)+=(gtm_uint64_t)(B) # define QWDECRBYDW(A,B) (A)-=(gtm_uint64_t)(B) # define QWMULBYDW(A,B,C) (A)=(B)*(C) # define QWDIVIDEBYDW(A,B,Q,R) {(R)=(int)((A)%(B)); (Q)=(A)/(B);} # define QWMODDW(A,B) ((A)%(B)) # define QWLE(A,B) ((A)<=(B)) # define QWLT(A,B) ((A)<(B)) # define QWGE(A,B) ((A)>=(B)) # define QWGT(A,B) ((A)>(B)) # define QWEQ(A,B) ((A)==(B)) # define QWNE(A,B) ((A)!=(B)) # define INT8_PRINT(x) x # define INT8_PRINTX(x) x # define INT8_ONLY(x) x #else typedef struct non_native_uint8 qw_num; typedef struct non_native_uint8 seq_num; typedef struct non_native_uint8 token_num; typedef struct non_native_uint8 qw_off_t; # define DWASSIGNQW(A,B) (A)=(B).value[lsb_index] # define QWASSIGN(A,B) (A)=(B) # define QWASSIGNDW(A,B) {(A).value[msb_index]=0; (A).value[lsb_index]=B;} # define QWASSIGN2DW(A,B,C) {(A).value[msb_index]=B; (A).value[lsb_index]=C;} # define QWADD(A,B,C) { \ uint4 temp; \ temp = (B).value[lsb_index]; \ (A).value[lsb_index]=(B).value[lsb_index]+(C).value[lsb_index]; \ (A).value[msb_index]=(B).value[msb_index]+(C).value[msb_index]; \ if ((A).value[lsb_index] < temp) (A).value[msb_index]++; \ } # define QWSUB(A,B,C) { \ uint4 temp; \ temp = (B).value[lsb_index]; \ (A).value[lsb_index]=(B).value[lsb_index]-(C).value[lsb_index]; \ (A).value[msb_index]=(B).value[msb_index]-(C).value[msb_index]; \ if ((A).value[lsb_index] > temp) (A).value[msb_index]--; \ } # define QWADDDW(A,B,C) { \ uint4 temp; \ temp = (B).value[lsb_index]; \ (A).value[lsb_index]=(B).value[lsb_index]+C; \ (A).value[msb_index]=(B).value[msb_index]; \ if ((A).value[lsb_index] < temp) (A).value[msb_index]++; \ } # define QWSUBDW(A,B,C) { \ uint4 temp; \ temp = (B).value[lsb_index]; \ (A).value[lsb_index]=(B).value[lsb_index]-(C); \ (A).value[msb_index]=(B).value[msb_index]; \ if ((A).value[lsb_index] > temp) (A).value[msb_index]--; \ } # define QWINCRBY(A,B) QWADD(A,A,B) # define QWDECRBY(A,B) QWSUB(A,A,B) # define QWINCRBYDW(A,B) QWADDDW(A,A,B) # define QWDECRBYDW(A,B) QWSUBDW(A,A,B) /* B should be less than 64K for the QWDIDIVEBYDW, QWMODDW macros to work correctly */ # define QWMULBYDW(A,B,C) { \ uint4 bh, bl, ch, cl, temp, temp1, temp2; \ (A).value[msb_index] = (B).value[msb_index] * (C); \ bl = (B).value[lsb_index] & 0x0000ffff; \ bh = ((B).value[lsb_index] & 0xffff0000) >> 16; \ cl = (C) & 0x0000ffff; \ ch = ((C) & 0xffff0000) >> 16; \ (A).value[msb_index] += bh * ch; \ (A).value[lsb_index] = bl * cl; \ temp = temp1 = bh * cl; \ temp += bl * ch; \ if (temp1 > temp) \ (A).value[msb_index] += 0x00010000; \ temp2 = (A).value[lsb_index]; \ (A).value[lsb_index] += (temp & 0x0000ffff) << 16; \ if ((A).value[lsb_index] < temp2) \ (A).value[msb_index] ++; \ (A).value[msb_index] += (temp & 0xffff0000) >> 16; \ } # define QWDIVIDEBYDW(A,B,Q,R) { \ uint4 msbr, lsbq, twoq, twor; \ (R) = (A).value[lsb_index] % (B); \ lsbq = (A).value[lsb_index] / (B); \ msbr = A.value[msb_index] % B; \ (Q).value[msb_index] = (A).value[msb_index] / (B); \ twoq = ((uint4)-1) / (B); \ twor = (((uint4)-1) % (B) + 1) % (B); \ if (0 == twor) \ twoq++; \ (Q).value[lsb_index] = lsbq; \ (Q).value[lsb_index] += twoq * msbr; \ if ((Q).value[lsb_index] < lsbq) \ (Q).value[msb_index]++; \ (R) = (R) + (twor * msbr) % (B); \ lsbq = (Q).value[lsb_index]; \ (Q).value[lsb_index] += (twor * msbr) / (B); \ if ((R) > (B)) \ { \ (R) -= (B); \ (Q).value[lsb_index]++; \ } \ if ((Q).value[lsb_index] < lsbq) \ (Q).value[msb_index]++; \ } # define QWMODDW(A,B) ((((A).value[msb_index] % (B)) * (((uint4)-1) % (B) + 1) \ + (A).value[lsb_index]) % (B)) # define QWLE(A,B) ((A).value[msb_index] < (B).value[msb_index] || \ ((A).value[msb_index] == (B).value[msb_index] \ && (A).value[lsb_index] <= (B).value[lsb_index])) # define QWLT(A,B) ((A).value[msb_index] < (B).value[msb_index] || \ ((A).value[msb_index] == (B).value[msb_index] \ && (A).value[lsb_index] < (B).value[lsb_index])) # define QWGE(A,B) ((A).value[msb_index] > (B).value[msb_index] || \ ((A).value[msb_index] == (B).value[msb_index] \ && (A).value[lsb_index] >= (B).value[lsb_index])) # define QWGT(A,B) ((A).value[msb_index] > (B).value[msb_index] || \ ((A).value[msb_index] == (B).value[msb_index] \ && (A).value[lsb_index] > (B).value[lsb_index])) # define QWEQ(A,B) ((A).value[msb_index] == (B).value[msb_index] \ && (A).value[lsb_index] == (B).value[lsb_index]) # define QWNE(A,B) ((A).value[msb_index] != (B).value[msb_index] \ || (A).value[lsb_index] != (B).value[lsb_index]) # define INT8_FMT "%s" # define INT8_FMTX "[0x%s]" # define INT8_PRINT(x) (seq_num_ptr = i2ascl(seq_num_str, x), \ seq_num_str[seq_num_ptr - &seq_num_str[0]] = '\0', seq_num_str) # define INT8_PRINTX(x) (seq_num_ptrx = i2asclx(seq_num_strx, x), \ seq_num_strx[seq_num_ptrx - &seq_num_strx[0]] = '\0', seq_num_strx) # define INT8_ONLY(x) #endif #define MAX_SEQNO ((seq_num)-1) /* actually 0xFFFFFFFFFFFFFFFF (max possible seqno) */ /* The HPUX Itanium compiler is giving warnings whenever a cast is being done and there is a potential alignment change */ /* The RECAST macro will eliminate these warnings by first casting to (void *) before the doing the ultimate cast */ #define RECAST(type) (type)(void_ptr_t) /* Define some basic types for shared memory (sm) access depending on whether the platform we are */ /* using is capable of supporting 32 or 64 bit pointers or not. */ #if defined(DB64) || defined(GTM64) # if defined(__osf__) && defined(__alpha) # pragma pointer_size(save) # pragma pointer_size(long) # endif typedef char *char_ptr_t; /* Define 64 bit pointer to char */ typedef unsigned char *uchar_ptr_t; /* Define 64 bit pointer to unsigned char */ typedef short *short_ptr_t; /* Define 64 bit pointer to short */ typedef unsigned short *ushort_ptr_t; /* Define 64 bit pointer to unsigned short */ typedef int4 *int_ptr_t; /* Define 64 bit pointer to int */ typedef volatile int4 *vint_ptr_t; /* Define 64 bit pointer to volatile int */ typedef uint4 *uint_ptr_t; /* Define 64 bit pointer to uint */ typedef volatile uint4 *vuint_ptr_t; /* Define 64 bit pointer to volatile uint */ typedef void *void_ptr_t; /* Define 64 bit pointer to void */ typedef qw_num *qw_num_ptr_t; /* Define 64 bit pointer to qw_num */ typedef latch_t *latch_ptr_t; /* Define 64 bit pointer to latch_t */ typedef ulatch_t *ulatch_ptr_t; /* Define 64 bit pointer to ulatch_t */ /* Shared memory connotation */ typedef char_ptr_t sm_c_ptr_t; /* Define 64 bit pointer to char */ typedef uchar_ptr_t sm_uc_ptr_t; /* Define 64 bit pointer to unsigned char */ typedef short_ptr_t sm_short_ptr_t; /* Define 64 bit pointer to short */ typedef ushort_ptr_t sm_ushort_ptr_t; /* Define 64 bit pointer to unsigned short */ typedef int_ptr_t sm_int_ptr_t; /* Define 64 bit pointer to int */ typedef vint_ptr_t sm_vint_ptr_t; /* Define 64 bit pointer to volatile int */ typedef uint_ptr_t sm_uint_ptr_t; /* Define 64 bit pointer to uint */ typedef vuint_ptr_t sm_vuint_ptr_t; /* Define 64 bit pointer to volatile uint */ typedef gtm_int64_t sm_long_t; /* Define 64 bit integer type */ typedef gtm_uint64_t sm_ulong_t; /* Define 64 bit unsigned integer type */ typedef global_latch_t *sm_global_latch_ptr_t; /* Define 64 bit pointer to hp_latch */ # ifdef __osf__ # pragma pointer_size(restore) # endif /* The macro FILL8DCL (explained below) is simple on a 64 bit system since all 64 bits will be declared and used. */ # define FILL8DCL(type,name,fillnum) type name #else typedef char *char_ptr_t; /* Define 32 bit pointer to char */ typedef unsigned char *uchar_ptr_t; /* Define 32 bit pointer to unsigned char */ typedef short *short_ptr_t; /* Define 32 bit pointer to short */ typedef unsigned short *ushort_ptr_t; /* Define 32 bit pointer to unsigned short */ typedef int4 *int_ptr_t; /* Define 32 bit pointer to int */ typedef volatile int4 *vint_ptr_t; /* Define 32 bit pointer to volatile int */ typedef uint4 *uint_ptr_t; /* Define 32 bit pointer to uint */ typedef volatile uint4 *vuint_ptr_t; /* Define 32 bit pointer to volatile uint */ typedef void *void_ptr_t; /* Define 32 bit pointer to void */ typedef qw_num *qw_num_ptr_t; /* Define 32 bit pointer to qw_num */ typedef latch_t *latch_ptr_t; /* Define 32 bit pointer to latch_t */ typedef ulatch_t *ulatch_ptr_t; /* Define 32 bit pointer to ulatch_t */ /* Shared memory connotation */ typedef char_ptr_t sm_c_ptr_t; /* Define 32 bit pointer to char */ typedef uchar_ptr_t sm_uc_ptr_t; /* Define 32 bit pointer to unsigned char */ typedef short_ptr_t sm_short_ptr_t; /* Define 32 bit pointer to short */ typedef ushort_ptr_t sm_ushort_ptr_t; /* Define 32 bit pointer to unsigned short */ typedef int_ptr_t sm_int_ptr_t; /* Define 32 bit pointer to int */ typedef vint_ptr_t sm_vint_ptr_t; /* Define 32 bit pointer to volatile int */ typedef uint_ptr_t sm_uint_ptr_t; /* Define 32 bit pointer to uint */ typedef vuint_ptr_t sm_vuint_ptr_t; /* Define 32 bit pointer to volatile uint */ typedef INTPTR_T sm_long_t; /* Define 32 bit integer type */ typedef UINTPTR_T sm_ulong_t; /* Define 32 bit unsigned integer type */ typedef global_latch_t *sm_global_latch_ptr_t; /* Define 32 bit pointer to hp_latch */ /* The macro FILL8DCL is used (on a 32 bit system) to provide a filler area of 32 bits and the actual 32 bit declared area. Whether the high order word or the low order word of the 64 bit area should be filler depends on the endian mode of the machine. This macro will be defined to take care of that for us. */ # ifdef BIGENDIAN # define FILL8DCL(type,name,fillnum) type fill##fillnum,name # else # define FILL8DCL(type,name,fillnum) type name,fill##fillnum # endif #endif /* Need to define a type for storing pointer differences */ typedef INTPTR_T ptroff_t; /* Need to define a consistently sized off_t type. Some platforms it is 4 bytes, others it is 4 or 8 bytes depending on flags. The following OFF_T macro is setup to allow the size of the variable declared by it to always take up 8 bytes for alignment purposes. If the OFF_T_LONG value is set, we will expect the size of 'off_t' to be 8 bytes. An assert will be placed in gtm.c to verify this. */ #ifdef OFF_T_LONG # define OFF_T(name,fillnum) off_t name #else # define OFF_T(name,fillnum) FILL8DCL(off_t,name,fillnum) #endif /* Type for offsets in journal files. VMS uses uint4 to get a full 32 bit offset for large journal files (OK since doesn't use lseek/etc. for IO.) */ #ifdef OFF_T_LONG # define JNL_OFF_T(name,fillnum) off_t name #else # ifdef VMS # define JNL_OFF_T(name,fillnum) FILL8DCL(uint4,name,fillnum) # else # define JNL_OFF_T(name,fillnum) FILL8DCL(off_t,name,fillnum) # endif #endif /* Need to define a consistently sized counter that is controlled by interlocks. The counter will occupy 4 bytes in the file header but on some platforms (currently VAX and AXP VMS), these counters need to be shorts whereas other platforms would realize a performance improvement if they were 32 bits long. So we create another macro in the spirit of the FILL8DCL macro above which will always give us a 32 byte entity but will pad a 2 byte addressable entity if necessary. If not specified, the default is for 'short' counters. */ # ifdef CNTR_WORD_32 # define FILL4DCL(type,name,fillnum) type name # define CNTR4DCL(name,fillnum) int4 name # else # ifdef BIGENDIAN # define FILL4DCL(type,name,fillnum) type fill##fillnum,name # else # define FILL4DCL(type,name,fillnum) type name,fill##fillnum # endif # define CNTR4DCL(name,fillnum) FILL4DCL(short,name,fillnum) # endif /* For machines with a cache line dependency for locks and such, define a macro that can be used to generate padding such that fields are in separate cache lines. Note that this macro should *NOT* be used in the fileheader as its length expansion is platform specific. It should only be used in internal shared memory structures that are NOT otherwise placement sensitive. A ; is included in the definition instead of when used since an extra ; in a structure is not accepted by some compilers. */ #ifdef CACHELINE_SIZE # define CACHELINE_PAD(fieldSize, fillnum) char fill_cacheline##fillnum[CACHELINE_SIZE - (fieldSize)]; #else # define CACHELINE_PAD(fieldSize, fillnum) #endif /* In certain cases we need to conditionally do a CACHELINE pad. For those platforms that have load-locked/store-conditional logic, counters that are incremented under interlock need to have spacing so they do not interfere with each other. But platforms that do NOT have this capability need the spacing on the actual latch used instead. Hence this form of padding is conditional. */ #if defined(__alpha) || defined(_AIX) # define CACHELINE_PAD_COND(fieldSize, fillnum) CACHELINE_PAD(fieldSize, fillnum) #else # define CACHELINE_PAD_COND(fieldSize, fillnum) #endif #define MEMCP(dst,src,start,count,limit){ \ if (start+count > limit) \ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CPBEYALLOC); \ else \ memcpy(dst+start,src,count); \ } #ifndef USING_ICONV typedef enum { NO_XLAT = 0, EBCDIC_TO_ASCII, ASCII_TO_EBCDIC } gtm_iconv_t; #define iconv_t gtm_iconv_t #endif #ifdef _AIX # define VSIG_ATOMIC_T sig_atomic_t #else # define VSIG_ATOMIC_T volatile sig_atomic_t #endif /* For copying va_list items - Linux/390 needs __va_copy */ #ifndef VAR_COPY #define VAR_COPY(dst, src) dst = src #endif #define NOLICENSE /* cheap way to obsolete it */ /* integer conversion functions */ void i2hex(UINTPTR_T val, uchar_ptr_t dest, int len); void i2hexl(qw_num val, uchar_ptr_t dest, int len); void i2hex_blkfill(int num, uchar_ptr_t addr, int len); void i2hexl_blkfill(qw_num num, uchar_ptr_t addr, int len); int i2hex_nofill(int num, uchar_ptr_t addr, int len); int i2hexl_nofill(qw_num num, uchar_ptr_t addr, int len); uchar_ptr_t i2ascl(uchar_ptr_t p, qw_num n); uchar_ptr_t i2asclx(uchar_ptr_t p, qw_num n); uchar_ptr_t i2asc(uchar_ptr_t p, unsigned int n); /* ascii conversion functions */ int4 asc2i(uchar_ptr_t p, int4 len); qw_num asc2l(uchar_ptr_t p, int4 len); unsigned int asc_hex2i(uchar_ptr_t p, int len); gtm_uint64_t asc_hex2l(uchar_ptr_t p, int len); /* This macro converts an integer to a decimal string (a more efficient alternative to i2asc). * It is used by format2zwr() which is called a lot during MUPIP EXTRACT (which can be time-consuming * for a big database), hence the need to make it efficient. */ #define I2A(des, des_len, num) \ { \ if ((unsigned)(num) < 1000) \ { /* perform light-weight conversion of numbers upto 3 digits */ \ int n1, n2; /* digits at the 10th and 100th decimal positions respectively */ \ n2 = ((num) / 100) % 10; \ if (0 != n2) \ (des)[(des_len)++] = n2 + '0'; \ n1 = ((num) / 10) % 10; \ if (0 != n1 || 0 != n2) \ (des)[(des_len)++] = n1 + '0'; \ (des)[(des_len)++] = ((num) % 10) + '0'; \ } else \ des_len += (int)(i2asc((uchar_ptr_t)((des) + des_len), num) - (uchar_ptr_t)((des) + des_len)); \ } /* The following is similar to I2A except that it updates the input pointer directly (no length parameter needed) */ #define I2A_INLINE(des, num) \ { \ if ((unsigned)(num) < 1000) \ { /* perform light-weight conversion of numbers upto 3 digits */ \ int n1, n2; /* digits at the 10th and 100th decimal positions respectively */ \ n2 = ((num) / 100) % 10; \ if (0 != n2) \ *des++ = n2 + '0'; \ n1 = ((num) / 10) % 10; \ if (0 != n1 || 0 != n2) \ *des++ = n1 + '0'; \ *des++ = ((num) % 10) + '0'; \ } else \ des = (char *)i2asc((uchar_ptr_t)des, num); \ } /* This macro converts a decimal string to a number (a more efficient alternative to asc2i). * It is used by zwr2format() and str2gvargs which is called a lot during MUPIP LOAD (can be time-consuming for a big database). */ #define A2I(cp, end, num) \ { \ unsigned char *cpbase = (unsigned char*)(cp); \ char ch; \ \ for (num = 0; (cp) < (end) && ('0' <= (ch = *((unsigned char*)cp))) && ('9' >= ch); ++(cp)) \ num = (num) * 10 + (ch - '0'); \ if (cpbase == ((unsigned char*)cp)) \ num = -1; \ } void double2s(double *dp, mval *v); /* double conversion */ int skpc(char c, int length, char *string); /* If the below declaration changes, corresponding changes in gtmxc_types.h needs to be done. */ void *gtm_malloc(size_t size); /* If the below declaration changes, corresponding changes in gtmxc_types.h needs to be done. */ void gtm_free(void *addr); int gtm_memcmp (const void *, const void *, size_t); DEBUG_ONLY(void printMallocInfo(void);) int is_equ(mval *u, mval *v); char is_ident(mstr *v); int val_iscan(mval *v); void mcfree(void); int4 getprime(int4 n); void push_parm(UNIX_ONLY_COMMA(unsigned int totalcnt) int truth_value, ...); UNIX_ONLY(void suspend(int sig);) mval *push_mval(mval *arg1); void mval_lex(mval *v, mstr *output); #define ZTRAP_CODE 0x00000001 #define ZTRAP_ENTRYREF 0x00000002 #define ZTRAP_POP 0x00000004 #define ZTRAP_ADAPTIVE (ZTRAP_CODE | ZTRAP_ENTRYREF) #define GTM_BYTESWAP_16(S) \ ( (((S) & 0xff00) >> 8) \ | (((S) & 0x00ff) << 8) \ ) #define GTM_BYTESWAP_24(L) \ ( (((L) & 0xff0000) >> 16) \ | ((L) & 0x00ff00) \ | (((L) & 0x0000ff) << 16) \ ) #define GTM_BYTESWAP_32(L) \ ( (((L) & 0xff000000) >> 24) \ | (((L) & 0x00ff0000) >> 8) \ | (((L) & 0x0000ff00) << 8) \ | (((L) & 0x000000ff) << 24) \ ) qw_num gtm_byteswap_64(qw_num num64); #ifdef INT8_SUPPORTED #define GTM_BYTESWAP_64(LL) \ ( (((LL) & 0xff00000000000000ull) >> 56) \ | (((LL) & 0x00ff000000000000ull) >> 40) \ | (((LL) & 0x0000ff0000000000ull) >> 24) \ | (((LL) & 0x000000ff00000000ull) >> 8) \ | (((LL) & 0x00000000ff000000ull) << 8) \ | (((LL) & 0x0000000000ff0000ull) << 24) \ | (((LL) & 0x000000000000ff00ull) << 40) \ | (((LL) & 0x00000000000000ffull) << 56) \ ) #else #define GTM_BYTESWAP_64(LL) gtm_byteswap_64(LL) #endif #define ZDIR_FORM_FULLPATH 0x00000000 #define ZDIR_FORM_DIRECTORY 0x00000001 #define IS_VALID_ZDIR_FORM(zdirform) (ZDIR_FORM_FULLPATH == (zdirform) || ZDIR_FORM_DIRECTORY == (zdirform)) #define MAXNUMLEN 128 /* from PV_N2S */ #define CENTISECONDS 100 /* VMS lib$day returns 1/100s, we want seconds, use this factor to convert b/n the two */ #define MINUTE 60 /* seconds in a minute */ #define HOUR 3600 /* one hour in seconds 60 * 60 */ #define ONEDAY 86400 /* seconds in a day */ #define MILLISECS_IN_SEC 1000 /* millseconds in a second */ #define MICROSEC_IN_SEC 1000000 /* microseconds in a second */ #define ASSERT_IN_RANGE(low, x, high) assert((low <= x) && (x <= high)) #if defined(VMS) #define DAYS 6530 /* adjust VMS returned days by this amount; GTM zero time Dec 31, 1840, VMS zero time 7-NOV-1858 */ #define VARLSTCNT1(CNT) VARLSTCNT(CNT) #define PUT_SYS_ERRNO(SYS_ERRNO) SYS_ERRNO #elif defined(UNIX) #define DAYS 47117 /* adjust Unix returned days (seconds converted to days); Unix zero time 1970 */ #define VARLSTCNT1(CNT) VARLSTCNT(CNT + 1) #define PUT_SYS_ERRNO(SYS_ERRNO) 0, SYS_ERRNO #else #error Unsupported platform #endif #define EXIT_NRM 0 #define EXIT_INF 1 #define EXIT_WRN 2 #define EXIT_ERR 4 #define EXIT_RDONLY 8 #define EXIT_MASK 7 #define MIN_FN_LEN 1 #define MAX_FN_LEN 255 #define V4_MAX_FN_LEN 255 /* required for dbcertify.h */ #define MAX_TRANS_NAME_LEN 257 typedef uint4 jnl_tm_t; typedef uint4 off_jnl_t; typedef gtm_uint64_t gtm_off_t; #define MAXUINT8 ((gtm_uint64_t)-1) #define MAXUINT4 ((uint4)-1) #define MAXUINT2 ((unsigned short)-1) #define MAXINT2 (MAXUINT2/2) /* On platforms that support native 8 byte operations (such as Alpha), an assignment to an 8 byte field is atomic. On other * platforms, an 8 byte assignment is a sequence of 4 byte operations. On such platforms, use this macro to determine if the * change from the current value to the new value provides a consistent view (entirely the pre read, or entirely the post read, * and not in between). Any change that causes the most significant 4 bytes to differ can cause inconsistency. In such cases, it * may be necessary to grab crit if modifying a shared field. */ #ifdef INT8_NATIVE #define QWCHANGE_IS_READER_CONSISTENT(FROM8, TO8) (TRUE) #else /* Note: cannot use this macro when FROM8 or TO8 do not have an lvalue (eg. literal) */ #define QWCHANGE_IS_READER_CONSISTENT(FROM8, TO8) (((non_native_uint8 *)&(FROM8))->value[msb_index] \ == ((non_native_uint8 *)&(TO8))->value[msb_index]) #endif #define MAX_SUPPL_STRMS 16 /* max # of non-supplementary streams that can connect to a supplementary root primary */ #ifdef UNIX /* Replication instance file related structures */ /* The below macros and typedef are required in "repl_instance.h", "gtmsource.h", "gtmrecv.h" and "repl_msg.h". * They are hence included in this common header file */ #define MAX_INSTNAME_LEN 16 /* Max Length of the replication instance name including terminating null character '\0' */ #define NUM_GTMSRC_LCL 16 /* max number of source servers that can run on a root primary instance. * also the number of gtmsrc_lcl structures in the replication instance file */ #define NUM_GTMRCV_LCL 16 /* max number of receiver servers that can run at the same time on a supplementary * root primary instance. On a non-supplementary instance, only 1 receiver server can run */ #define INVALID_SUPPL_STRM -1 /* stream #s 0 to 15 are the valid ones */ #define REPL_INST_HDR_SIZE (SIZEOF(repl_inst_hdr)) #define GTMSRC_LCL_SIZE (SIZEOF(gtmsrc_lcl) * NUM_GTMSRC_LCL) /* size of the gtmsrc_lcl array */ #define GTMSOURCE_LOCAL_SIZE (SIZEOF(gtmsource_local_struct) * NUM_GTMSRC_LCL) /* size of the gtmsource_local array */ #define REPL_INST_HISTINFO_START (REPL_INST_HDR_SIZE + GTMSRC_LCL_SIZE) /* Although we have dedicated 60-bits for the stream specific seqno, it is still a very high value and should not be reached * in practice. Therefore, we arbitrarily pick 48-bits as the maximum value for this seqno and assert that the remaining 12 bits * are zero in at least our test environments. This way we catch any uninitialized/garbage value usages of this seqno in the code. */ #define IS_VALID_STRM_SEQNO(SEQNO) (0 == (SEQNO & 0x0FFF000000000000LLU)) /* Given a strm_seqno, determine the corresponding stream# by getting the most significant 4 bits of the 64-bit seqno */ #define GET_STRM_INDEX(SEQNO) (DBG_ASSERT(IS_VALID_STRM_SEQNO(SEQNO)) \ (((SEQNO) >> 60) & 0xF)) /* Given a 64-bit strm_seqno, determine the corresponding 60-bit stream specific seqno. */ #define GET_STRM_SEQ60(SEQNO) (DBG_ASSERT(IS_VALID_STRM_SEQNO(SEQNO)) \ ((SEQNO) & (0x0FFFFFFFFFFFFFFFLLU))) /* Given a 60-bit strm_seqno and 4-bit stream#, this macro returns a unified 64-bit sequence number */ #define SET_STRM_INDEX(SEQNO, STRM_NO) (DBG_ASSERT(0 == GET_STRM_INDEX(SEQNO)) \ DBG_ASSERT((STRM_NO) <= 0xF) \ ((SEQNO) | (((seq_num)STRM_NO) << 60))) #define MAX_NODENAME_LEN 16 /* used by repl_instance.h. A similar macro JPV_LEN_NODE is defined in jnl.h */ #define UNKNOWN_INSTNAME "" /* used in places where instance name is not known (e.g. if pre-V51000 version) */ /* The following defines the structure holding the instance information in a replication instance file. * Any changes to this structure might need changes to the ENDIAN_CONVERT_REPL_INST_UUID macro. */ typedef struct repl_inst_uuid_struct { unsigned char created_nodename[MAX_NODENAME_LEN]; /* Nodename on which instance file was created */ unsigned char this_instname[MAX_INSTNAME_LEN]; /* Instance name that this file corresponds to */ uint4 created_time; /* Time when this instance file was created */ uint4 creator_pid; /* Process id that created the instance file */ } repl_inst_uuid; /* Macro to endian convert an entire "repl_inst_uuid" structure contents given a pointer to the structure */ #define ENDIAN_CONVERT_REPL_INST_UUID(PTR) \ { \ /* No need to convert "created_nodename" as it is a character array */ \ /* No need to convert "this_instname" as it is a character array */ \ /* Endian convert 4-byte "created_time" */ \ (PTR)->created_time = GTM_BYTESWAP_32((PTR)->created_time); \ /* Endian convert 4-byte "creator_pid" */ \ (PTR)->creator_pid = GTM_BYTESWAP_32((PTR)->creator_pid); \ } /* A NULL UUID is denoted by a 0 value for created_time. In that case, other fields are uninitialized and hence unusable. * A non-NULL UUID has a non-zero value for created_time. In that case, other fields are guaranteed to have been initialized. */ #define IS_REPL_INST_UUID_NULL(UUID) (0 == (UUID).created_time) #define IS_REPL_INST_UUID_NON_NULL(UUID) (!IS_REPL_INST_UUID_NULL(UUID)) #define NULL_INITIALIZE_REPL_INST_UUID(UUID) (UUID).created_time = 0 /* Lot of code (e.g. repl_inst_dump) relies on "created_nodename" (which can be a string upto MAX_NODENAME_LEN bytes long) * being NOT null-terminated at the (MAX_NODENAME_LEN - 1)th byte ONLY if the node name length is LESS THAN the max length. * This lets them avoid a scan of the string (to find the real length) in the null-terminated case and safely pass it to * any function (e.g. printf etc.) that expects a null-terminated string. Verify that using the below assert. */ #ifdef DEBUG #define DBG_CHECK_CREATED_NODENAME(PTR) \ { \ int index, last_byte_non_null; \ char *lclPtr = (char *)PTR; \ \ last_byte_non_null = lclPtr[MAX_NODENAME_LEN -1]; \ if (last_byte_non_null) \ { \ for (index = 0; index < MAX_NODENAME_LEN; index++) \ { \ if (!lclPtr[index]) \ assert(FALSE); \ } \ } \ } #else #define DBG_CHECK_CREATED_NODENAME(PTR) #endif /* The following macros define what value the "histinfo_type" member of the repl_histinfo structure gets filled in with */ #define HISTINFO_TYPE_NORMAL 1 /* A history record generated whenever a root primary starts up */ #define HISTINFO_TYPE_UPDRESYNC 2 /* A history record generated when a receiver server starts up with -UPDATERESYNC on * a supplementary root primary instance. */ #define HISTINFO_TYPE_NORESYNC 3 /* A history record generated when a receiver server starts up with -NORESYNC. * Used by a propagating primary supplementary instance to know that "prev_histinfo_num" * has to be recomputed on the receiver side. */ /* The following defines the structure of a history record in the instance file. * Any changes to this structure might need changes to the ENDIAN_CONVERT_REPL_HISTINFO macro. */ typedef struct repl_histinfo_struct { /* Each history record is uniquely defined by the following 5 fields (consider start_seqno and strm_seqno as one field) */ unsigned char root_primary_instname[MAX_INSTNAME_LEN];/* the root primary instance that generated this history record */ seq_num start_seqno; /* the first seqno generated in this history record by the * root primary. In case of a supplementary instance, this * seqno is the unified seqno across all streams. */ seq_num strm_seqno; /* the stream specific jnl seqno. this will help identify which * of the potentially 16 streams (0 for local instance, 1 to 15 for * non-local streams) this history record corresponds to. */ uint4 root_primary_cycle; /* a copy of the "root_primary_cycle" field in the instance file * header of the root primary when it generated the seqno * "start_seqno". This is needed to distinguish two invocations * of the same instance */ uint4 creator_pid; /* pid on rootprimary instance that wrote this history record */ uint4 created_time; /* time on rootprimary when this history record was generated */ int4 histinfo_num; /* = 'n' if this is the n'th history record in the instance file */ int4 prev_histinfo_num; /* = 'n' if the previous history record corresponding to this * stream is the n'th history record in the instance file. */ char strm_index; /* = 0 by default. * = anywhere from 1 to 15 if this history record corresponds to a * non-supplementary stream of updates. */ char history_type; /* can take any one of the HISTINFO_TYPE_* macro values */ char filler_8[2]; /* Filler for 8-byte alignment */ repl_inst_uuid lms_group; /* Non-null only if this instance file is supplementary AND if * the history record has "strm_index" greater than 0. * Null otherwise. In the non-null case, this field stores * the lms group uuid for this particular non-supplementary * stream. The "created_time" field will be non-zero in this case * else zero (this field will be used to determine whether the * "lms_group" member is valid or not given a history record). */ int4 last_histinfo_num[MAX_SUPPL_STRMS]; /* a copy of the last_histinfo_num[] array from the instance file * header BEFORE this history record was added to the instance file. */ } repl_histinfo; /* Macro to endian convert an entire "repl_inst_uuid" structure contents given a pointer to the structure */ #define ENDIAN_CONVERT_REPL_HISTINFO(PTR) \ { \ /* No need to convert "root_primary_instname" as it is a character array */ \ /* Endian convert 8-byte "start_seqno" */ \ (PTR)->start_seqno = GTM_BYTESWAP_64((PTR)->start_seqno); \ /* Endian convert 8-byte "strm_seqno" */ \ (PTR)->strm_seqno = GTM_BYTESWAP_64((PTR)->strm_seqno); \ /* Endian convert 4-byte "root_primary_cycle" */ \ (PTR)->root_primary_cycle = GTM_BYTESWAP_32((PTR)->root_primary_cycle); \ /* Endian convert 4-byte "creator_pid" */ \ (PTR)->creator_pid = GTM_BYTESWAP_32((PTR)->creator_pid); \ /* Endian convert 4-byte "created_time" */ \ (PTR)->created_time = GTM_BYTESWAP_32((PTR)->created_time); \ /* Endian convert 4-byte "histinfo_num" */ \ (PTR)->histinfo_num = GTM_BYTESWAP_32((PTR)->histinfo_num); \ /* Endian convert 4-byte "prev_histinfo_num" */ \ (PTR)->prev_histinfo_num = GTM_BYTESWAP_32((PTR)->prev_histinfo_num); \ /* No need to convert "strm_index" as it is a 1-byte character */ \ /* No need to convert "history_type" as it is a 1-byte character */ \ /* Endian convert "lms_group" of type "repl_inst_uuid" */ \ ENDIAN_CONVERT_REPL_INST_UUID(&((PTR)->lms_group)); \ /* No need to endian convert "last_histinfo_num" as this is not relevant \ * across a replication connection and is regenerated on the receiver anyways. \ */ \ } #define INVALID_HISTINFO_NUM -1 /* 0 is a valid history record number (first element of array) so set it to -1 */ #define UNKNOWN_HISTINFO_NUM -2 /* Special value to indicate there is a history record but is not yet part of the * replication instance file and hence does not have a history number yet (this is * assigned by the function "repl_inst_histinfo_add" only when it adds this history * record to the instance file on the receiving instance). This is possible for * example if the history record is in the receive pool waiting for it to be played * by the update process. Currently used by a propagating primary supplementary instance. */ /* The following two macros convert a history record from that of a non-supplementary instance to a supplementary instance * and vice versa. The "start_seqno" and "strm_seqno" fields are the ones which are manipulated in these conversions. */ #define CONVERT_NONSUPPL2SUPPL_HISTINFO(HISTINFO, JNLPOOL_CTL) \ { \ /* Until now "start_seqno" actually corresponded to the non-supplementary stream's seqno. \ * Now that we are writing this history record into a supplementary instance file, switch it \ * to be the supplementary seqno (jnlpool_ctl->jnl_seqno). Until now "strm_seqno" was 0. \ * Now switch that to be what "start_seqno" was before. \ */ \ assert(0 < (HISTINFO)->strm_index); \ assert(MAX_SUPPL_STRMS > (HISTINFO)->strm_index); \ assert(0 == (HISTINFO)->strm_seqno); \ (HISTINFO)->strm_seqno = (HISTINFO)->start_seqno; \ (HISTINFO)->start_seqno = (JNLPOOL_CTL)->jnl_seqno; \ } #define CONVERT_SUPPL2NONSUPPL_HISTINFO(HISTINFO) \ { \ /* This macro is invoked just before sending a non-supplementary stream history record \ * in a supplementary instance back to a non-supplementary instance. The latter does not \ * understand strm_seqnos hence the need to convert. \ */ \ assert(0 < (HISTINFO).strm_index); \ assert(MAX_SUPPL_STRMS > (HISTINFO).strm_index); \ assert((HISTINFO).strm_seqno); \ (HISTINFO).start_seqno = (HISTINFO).strm_seqno; \ (HISTINFO).strm_seqno = 0; \ } /* A structure to hold ALL aspects of ONE side (could be local or remote) of a replication connection */ typedef struct repl_conn_info_struct { int4 proto_ver; /* The replication communication protocol version of this side of the pipe. * Needs to be "signed" in order to be able to do signed comparisons of this with * the macros REPL_PROTO_VER_DUALSITE (0) and REPL_PROTO_VER_UNINITIALIZED (-1) */ uint4 jnl_ver; /* Format of the journal records */ boolean_t is_std_null_coll; /* TRUE if M-standard null collation; FALSE if GT.M null collation */ boolean_t trigger_supported; /* TRUE if supports triggers; FALSE otherwise */ boolean_t cross_endian; /* TRUE if both sides of the replication connection have different endianness */ boolean_t endianness_known; /* TRUE if endianness of other side is known/determined; FALSE until then */ boolean_t null_subs_xform; /* 0 if the null subscript collation is same between the servers * Non-zero (GTMNULL_TO_STDNULL_COLL or STDNULL_TO_GTMNULL_COLL) if different */ boolean_t is_supplementary; /* Whether one side of the connection is a supplementary instance */ } repl_conn_info_t; #endif /* Replication instance file related structures */ /* Enumerator codes for supported CHSETs in GT.M */ typedef enum { CHSET_M, CHSET_UTF8, CHSET_UTF16, CHSET_UTF16LE, CHSET_UTF16BE, CHSET_ASCII, CHSET_EBCDIC, CHSET_BINARY, CHSET_MAX_IDX_ALL /* maximum number of CHSETs supported */ } gtm_chset_t; #define CHSET_UTF_MIN CHSET_UTF8 #define CHSET_UTF_MAX CHSET_UTF16BE #define CHSET_MAX_IDX CHSET_ASCII /* max true CHSETs */ #define IS_UTF16_CHSET(chset) ((CHSET_UTF16 == (chset)) || (CHSET_UTF16LE == (chset)) || (CHSET_UTF16BE == (chset))) #define IS_UTF_CHSET(chset) ((CHSET_UTF_MIN <= (chset)) && (CHSET_UTF_MAX >= (chset))) #define CHK_BOUNDARY_ALIGNMENT(pointer) (((UINTPTR_T)pointer) & (SIZEOF(UINTPTR_T) - 1)) #if defined(__ia64) || defined(__i386) || defined(__x86_64__) || defined(__sparc) || defined(_AIX) || defined(__MVS__) \ || defined(__s390__) #define GTM_CRYPT #define GTMCRYPT_ONLY(X) X #else #define GTMCRYPT_ONLY(X) #endif #define GTMCRYPT_HASH_LEN 64 #define GTMCRYPT_HASH_HEX_LEN GTMCRYPT_HASH_LEN * 2 #define GTMCRYPT_RESERVED_HASH_LEN 256 #define GET_HASH_IN_HEX(in, out, len) \ { \ int i; \ \ assert(0 == len % 2); \ for (i = 0; i < len; i+=2) \ SPRINTF((char *)out + i, "%02X", (unsigned char)in[i/2]); \ } #ifdef UNIX # define GTM_SNAPSHOT # define NON_GTM_SNAPSHOT_ONLY(X) # define GTM_SNAPSHOT_ONLY(X) X #else # define NON_GTM_SNAPSHOT_ONLY(X) X # define GTM_SNAPSHOT_ONLY(X) #endif /* Currently MUPIP REORG -TRUNCATE is only supported on Unix */ #ifdef UNIX # define GTM_TRUNCATE # define NON_GTM_TRUNCATE_ONLY(X) # define GTM_TRUNCATE_ONLY(X) X #else # define NON_GTM_TRUNCATE_ONLY(X) X # define GTM_TRUNCATE_ONLY(X) #endif /* Currently triggers are supported only on Unix */ #if defined(UNIX) && !defined(__hppa) /* triggers not supported on HPUX-HPPA */ # define GTM_TRIGGER # define GTMTRIG_ONLY(X) X # define NON_GTMTRIG_ONLY(X) # define GTMTRIG_DBG_ONLY(X) DEBUG_ONLY(X) # define GTM_TRIGGER_DEPTH_MAX 127 /* Maximum depth triggers can nest */ #else # define GTMTRIG_ONLY(X) # define NON_GTMTRIG_ONLY(X) X # define GTMTRIG_DBG_ONLY(X) #endif /* A type definition to hold a range of numbers */ typedef struct gtm_num_range_struct { uint4 min; /* included in range */ uint4 max; /* included in range */ } gtm_num_range_t; /* Debug FPRINTF with pre and post requisite flushing of appropriate streams */ #ifndef DBGFPF # define DBGFPF(x) {flush_pio(); FPRINTF x; FFLUSH(stderr); FFLUSH(stdout);} #endif /* Settings for lv_null_subs */ enum { LVNULLSUBS_FIRST = -1, /* So _NO is 0 to match existing values */ LVNULLSUBS_NO, /* No null LV subscripts in SET type cases */ LVNULLSUBS_OK, /* Null LV subscripts are allowed */ LVNULLSUBS_NEVER, /* LVNULLSUBS_NO plus LV subscripts prohibited in $DATA, $GET, $ORDER, $QUERY, KILL, etc */ LVNULLSUBS_LAST }; #define MAX_GVSUBSCRIPTS 32 #define MAX_LVSUBSCRIPTS 32 #define MAX_INDSUBSCRIPTS 32 #define MAX_FOR_STACK 32 #define MAX_ACTUALS 32 /* Maximum number of arguments allowed in an actuallist. This value also determines * how many parameters are allowed to be passed between M and C. */ #if defined(DEBUG) && defined(UNIX) #define OPERATOR_LOG_MSG \ { \ error_def(ERR_TEXT); /* BYPASSOK */ \ if (gtm_white_box_test_case_enabled && (WBTEST_OPER_LOG_MSG == gtm_white_box_test_case_number)) \ { \ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Send message to operator log")); \ } \ } #else #define OPERATOR_LOG_MSG #endif #ifdef GTM_PTHREAD /* If we detect a case when the signal came to a thread other than the main GT.M thread, this macro will redirect the signal to the * main thread if such is defined. Such scenarios is possible, for instance, if we are running along a JVM, which, upon receiving a * signal, dispatches a new thread to invoke signal handlers other than its own. The ptrhead_kill() enables us to target the signal * to a specific thread rather than rethrow it to the whole process. */ #define FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(SIG) \ { \ GBLREF pthread_t gtm_main_thread_id; \ GBLREF boolean_t gtm_main_thread_id_set; \ \ if (gtm_main_thread_id_set && !pthread_equal(gtm_main_thread_id, pthread_self())) \ { /* Only redirect the signal if the main thread ID has been defined, and we are not that. */ \ pthread_kill(gtm_main_thread_id, SIG); \ return; \ } \ } #else #define FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(SIG) #endif #ifdef DEBUG # define MVAL_IN_RANGE(V, START, END) (((char *)(V) >= (char *)(START)) \ && ((char *)(V) < ((char *)(START) + (INTPTR_T)(END) * SIZEOF(mval)))) #endif #endif /* MDEF_included */ fis-gtm-V6.0-003/sr_port/mdq.h0000644000032200000250000000661112201176160014764 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2012 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef MDQ_H_DEFINED #define HDQ_H_DEFINED /* Define basic working macros for queue management of doubly linked list is defined using elements "n.fl" and "n.bl". * The DSRINS insert at tail rather than head and so work FIFO rather than LIFO with DQLOOP and associated macros */ /* Loop through a linked list given any element as the start (q) and a var to use as loop incrementer */ #define DQLOOP(q, n, i) for (i = (q)->n.fl; i != (q); i = (i)->n.fl) /* Initialize an element */ #define DQINIT(q, n) ((q)->n.fl = (q)->n.bl = q) /* Delete one element "x" from the doubly linked list */ #define DQDEL(x, n) ((x)->n.bl->n.fl = (x)->n.fl, (x)->n.fl->n.bl = (x)->n.bl) /* Delete a doubly-linked list of elements from "x->n.fl" to "y->n.bl" (i.e. everything in between "x" and "y" excluding them) */ #define DQDELCHAIN(x, y, n) ((x)->n.fl = (y), (y)->n.bl = (x)) /* Insert one element "x" in between "q" and "q->n.fl" */ #define DQINS(q, n, x) ((x)->n.fl = (q)->n.fl, (x)->n.bl = (q), (q)->n.fl = (x), ((x)->n.fl)->n.bl = (x)) /* Insert one element "x" in between "q" and "q->n.bl" */ #define DQRINS(q, n, x) ((x)->n.bl = (q)->n.bl, (x)->n.fl = (q), (q)->n.bl = (x), ((x)->n.bl)->n.fl = (x)) /* Insert a doubly-linked list of elements from "n->q.fl" to "n->q.bl" in between "o" and "o->q.fl" */ #define DQADD(o, n, q) ((o)->q.fl->q.bl = (n)->q.bl, (n)->q.bl->q.fl = (o)->q.fl, (o)->q.fl = (n)->q.fl, (n)->q.fl->q.bl = (o)) /* Define macros actually used which if #define DEBUG_TRIPLES, adds debugging information. Since these macros are * used in several different queue types and since these debugging macros only work for the exorder field in triples, * the test to see if should do debugging is not elegant but it does allow decent debugging. Note those macros without * debugging are statically defined. */ #define dqloop(q, n, i) DQLOOP(q, n, i) #define dqinit(q, n) DQINIT(q, n) /* #define DEBUG_TRIPLES / * Uncomment this to do triple debugging */ #ifndef DEBUG_TRIPLES # define dqdel(x, n) DQDEL(x, n) # define dqdelchain(x, y, n) DQDELCHAIN(x, y, n) # define dqins(q, n, x) DQINS(q, n, x) # define dqrins(q, n, x) DQRINS(q, n, x) # define dqadd(o, n, q) DQADD(o, n, q) # define CHKTCHAIN(x) #else # include "compiler.h" # define CHKTCHAIN(x) chktchain((triple *)(x)) # define IFEXOCHN(n, c) if (0 == memcmp(#n, "exorder", 3)) c /* memcmp() should be faster and for 3 chars, just as effective */ # define dqdel(x, n) \ { \ IFEXOCHN(n, CHKTCHAIN(x)); \ DQDEL(x, n); \ } # define dqdelchain(x, y, n) \ { \ IFEXOCHN(n, CHKTCHAIN(x)); \ DQDELCHAIN(x, y, n); \ IFEXOCHN(n, CHKTCHAIN(y)); \ } # define dqins(q, n, x) \ { \ IFEXOCHN(n, CHKTCHAIN(q)); \ DQINS(q, n, x); \ IFEXOCHN(n, CHKTCHAIN(q)); \ } # define dqrins(q, n, x) \ { \ IFEXOCHN(n, CHKTCHAIN(q)); \ DQRINS(q, n, x); \ IFEXOCHN(n, CHKTCHAIN(q)); \ } # define dqadd(o, n, q) \ { \ IFEXOCHN(n, CHKTCHAIN(o)); \ DQADD(o, n, q); \ IFEXOCHN(n, CHKTCHAIN(o)); \ } #endif #endif fis-gtm-V6.0-003/sr_port/mem_access.h0000644000032200000250000000120112201176160016270 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef __MEM_ACCESS_H__ #define __MEM_ACCESS_H__ void set_noaccess(unsigned char *na_page[], unsigned char *prvprt); void reset_access(unsigned char *na_page[], unsigned char oldprt); #endif fis-gtm-V6.0-003/sr_port/memcoherency.h0000644000032200000250000002005612201176160016660 0ustar librarygtc/**************************************************************** * * * Copyright 2003, 2010 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef MEMCOHERENCY_H_INCLUDED #define MEMCOHERENCY_H_INCLUDED /* for Uniprocessor systems, no need for "memory barrier" as memory is always coherent. * But almost always we expect to be running on a multi-processor system so we want to avoid the cost * of the if check and do the memory barrier ALWAYS. */ #ifdef __alpha #include /* Read Alpha Architecture Reference Manual, edited by Richard L Sites, * Chapter "System Architecture and Programming Implications" for memory * coherency issues and behavior of "mb" instruction (memory barrier) */ /* NOTES about Alpha (pp. 5-20, section 5.6.5 Implications for Hardware, Chapter 5 System Architecture and Programming * Implications, Alpha Architecture Reference Manual, Edited by Richard L Sites * * MB and IMB force all preceding writes to at least reach their respective coherency points. This does not mean that * main-memory writes have been done, just that the order of the eventual writes is committed. MB and IMB also force all * queued cache invalidates to be delivered to the local caches before starting any subsequent reads (that may otherwise * cache hit on stale data) or writes (that may otherwise write the cache, only to have the write effectively overwriiten * by a late-delivered invalidate) */ #define SHM_WRITE_MEMORY_BARRIER asm("mb") #define SHM_READ_MEMORY_BARRIER SHM_WRITE_MEMORY_BARRIER /* same MB instruction for both read and write barriers */ #ifdef __vms #define SECSHR_SHM_WRITE_MEMORY_BARRIER asm("mb") #define SECSHR_SHM_READ_MEMORY_BARRIER SECSHR_SHM_WRITE_MEMORY_BARRIER #endif /* __vms */ #elif defined(POWER) || defined(PWRPC) /* GT.M defines POWER and PWRPC if _AIX is defined, see sr_rs6000/mdefsp.h */ /* Refer to article "POWER4 and shared memory synchronization by R. William Hay and Gary R. Hook" available at * http://www-106.ibm.com/developerworks/eserver/articles/power4_mem.html */ /* prototypes */ void do_sync(void); void do_lwsync(void); void do_eieio(void); void do_isync(void); /* The machine codes were fetched from http://www-106.ibm.com/developerworks/eserver/articles/powerpc.html */ /* sync : Creates a memory barrier. On a given processor, any load or store instructions ahead of the sync instruction * in the program sequence must complete their accesses to memory first, and then any load or store instructions after * sync can begin */ #pragma mc_func do_sync{"7c0004ac"} #pragma reg_killed_by do_sync /* lwsync : Creates a memory barrier that provides the same ordering function as the sync instruction, except that a * load caused by an instruction following the lwsync may be performed before a store caused by an instruction that * precedes the lwsync, and the ordering does not apply to accesses to I/O memory (memory-mapped I/O). * lwsync is a new variant of the sync instruction and is interpreted by older processors as a sync. The instruction, * as its name implies, has much less performance impact than sync, and is recommended for syncrhonisation of most * memory (but not I/O) references. */ #pragma mc_func do_lwsync{"7c2004ac"} #pragma reg_killed_by do_lwsync /* eieio : Creates a memory barrier that provides the same ordering function as the sync instruction except that * ordering applies only to accesses to I/O memory */ #pragma mc_func do_eieio{"7c0006ac"} #pragma reg_killed_by do_eieio /* isync : Causes the processor to discard any prefetched (and possibly speculatively executed) instructions and * refetch the next following instructions. It is used in locking code (e.g. __check_lock()) to ensure that no * loads following entry into a critical section can access data (because of aggressive out-of-order and speculative * execution in the processor) before the lock is acquired. */ #pragma mc_func do_isync{"4c00012c"} #pragma reg_killed_by do_isync #define SHM_WRITE_MEMORY_BARRIER \ { /* Ensure that code does not rely on ordering of "loads" following lwsync in programming sequence to occur */ \ /* after "stores" before lwsync. Use do_sync() if such ordering is required. Replication code (t_end.c, */ \ /* tp_end.c) do not rely on store-load order across memory barrier. Note that grab/rel_lock() perform */ \ /* "sync" (via call to _clear_lock()), and so, we are guaranteed strict ordering of loads and stores of */ \ /* code that reads/writes to journal pool in transaction logic */ \ do_lwsync(); \ } #define SHM_READ_MEMORY_BARRIER \ { \ do_isync(); \ } #elif defined(__hppa) /* For _PA_RISC1_0, _PA_RISC1_1, accesses to the address space (both to memory and I/O) through load, store and * semaphore instructions are strongly ordered. This means that accesses appear to software to be done in program order * For _PA_RISC2_0, accesses could be "strongly ordered", "ordered", or "weakly ordered" (read PA-RISC 2.0 ARCHITECTURE * by Gerry Kane, appendix "Memory Ordering Model"). * * For all PA-RISC architectures, cache flush operations are weakly ordered. Flushes may be delayed or held pending, and * a sequence of flush operations may be executed in any order. * * SYNC : Enforce program order of memory references * Any load, store, semaphore, cache flush, or cache purge instructions that follow the SYNC instruction get executed * only after all such instructions prior to the SYNC instruction have completed executing. On implementations which * execute such instructions out of sequence, this instruction enforces program ordering. In sytems in which all memory * references are performed in order, this instruction executes as a null instruction. * * IMPORTANT: SYNC instruction enforces ordering of only those accesses caused by the instructions executed on the * same processor which executes the SYNC instruction. * * [Vinaya] Research results: Accesses to fields (global) that are defined volatile are ordered (compiler generates * LDW (or STW) instruction with the O (ordered) completer, i.e., instructions generated are LDW,O (STW,O). Depending * on the requirements, it may be sufficient to define shared fields as volatile to enforce ordering. With replication * though, it is important that pending cache flushes are completed so that source server sees the transaction data * in its entirety. */ #define SHM_WRITE_MEMORY_BARRIER (void)_asm("SYNC") #define SHM_READ_MEMORY_BARRIER SHM_WRITE_MEMORY_BARRIER /* same SYNC instruction for both read and write barriers. * For read, we want all cache purges to be completed before * we load shared fields */ #elif defined(__ia64) #if defined(__hpux) #include #define SHM_WRITE_MEMORY_BARRIER _MF() #elif defined(__linux__) && defined(__INTEL_COMPILER) # define SHM_WRITE_MEMORY_BARRIER __mf() #elif defined(__linux__) /* gcc */ # define SHM_WRITE_MEMORY_BARRIER __asm__ __volatile__ ("mf" ::: "memory") #endif /* __linux__ */ /* On IA64, cross processor notifications of write barriers are automatic so no read barrier is necessary */ #define SHM_READ_MEMORY_BARRIER #else /* SPARC, I386, S390, Itanium */ /* Although SPARC architecture allows for out-of-order memory accesses, Solaris forces strong ordering on memory accesses. * We do not need memory barrier primitives on Solaris/SPARC. */ /* Memory accesses in Intel x86 and IBM S390 archtectures are strongly ordered */ #define SHM_WRITE_MEMORY_BARRIER #define SHM_READ_MEMORY_BARRIER #endif #if !defined(SECSHR_SHM_WRITE_MEMORY_BARRIER) #define SECSHR_SHM_WRITE_MEMORY_BARRIER SHM_WRITE_MEMORY_BARRIER /* default definition */ #endif #if !defined(SECSHR_SHM_READ_MEMORY_BARRIER) #define SECSHR_SHM_READ_MEMORY_BARRIER SHM_READ_MEMORY_BARRIER /* default definition */ #endif #endif /* MEMCOHERENCY_H_INCLUDED */ fis-gtm-V6.0-003/sr_port/memvcmp.c0000644000032200000250000000140012201176160015631 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ /* Compare two character strings using "0" as a filler return 0 iff they are equal return < 0 if a < b and > 0 if a > b */ #include "mdef.h" #include "gtm_string.h" #include "mmemory.h" int memvcmp(void *a, int a_len, void *b, int b_len) { int retval; MEMVCMP(a, a_len, b, b_len, retval); return retval; } fis-gtm-V6.0-003/sr_port/merge_def.h0000644000032200000250000000142712201176160016120 0ustar librarygtc/**************************************************************** * * * Copyright 2001 Sanchez Computer Associates, Inc. * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef MERGE_DEF_DEFINED #define MARG1_LCL 1 #define MARG1_GBL 2 #define MARG2_LCL 4 #define MARG2_GBL 8 #define IND1 0 #define IND2 1 #define MARG1_IS_LCL(arg) (arg & MARG1_LCL) #define MARG1_IS_GBL(arg) (arg & MARG1_GBL) #define MARG2_IS_LCL(arg) (arg & MARG2_LCL) #define MARG2_IS_GBL(arg) (arg & MARG2_GBL) #define MERGE_DEF_DEFINED #endif fis-gtm-V6.0-003/sr_port/merge_desc_check.c0000644000032200000250000001026012201176160017423 0ustar librarygtc/**************************************************************** * * * Copyright 2001, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_string.h" #include "min_max.h" #include "gdsroot.h" #include "gdskill.h" #include "gtm_facility.h" #include "fileinfo.h" #include "gdsbt.h" #include "gdsfhead.h" #include "zshow.h" #include "zwrite.h" #include "filestruct.h" #include "gdscc.h" #include "copy.h" #include "jnl.h" #include "buddy_list.h" #include "hashtab_int4.h" /* needed for tp.h */ #include "tp.h" #include "merge_def.h" #include "gvname_info.h" #include "op_merge.h" #include "format_targ_key.h" #include "ddphdr.h" GBLREF int merge_args; GBLREF merge_glvn_ptr mglvnp; error_def(ERR_MERGEDESC); boolean_t merge_desc_check(void) { unsigned char buff1[MAX_ZWR_KEY_SZ], buff2[MAX_ZWR_KEY_SZ], *end1, *end2; enum db_acc_method acc_meth1, acc_meth2; gd_region *reg1, *reg2; gv_namehead *gvt1, *gvt2; if (MARG1_IS_GBL(merge_args) && MARG2_IS_GBL(merge_args)) { reg1 = mglvnp->gblp[IND1]->s_gv_cur_region; reg2 = mglvnp->gblp[IND2]->s_gv_cur_region; gvt1 = mglvnp->gblp[IND1]->s_gv_target; gvt2 = mglvnp->gblp[IND2]->s_gv_target; acc_meth1 = reg1->dyn.addr->acc_meth; acc_meth2 = reg2->dyn.addr->acc_meth; assert(!(dba_bg == acc_meth1 || dba_mm == acc_meth1) || (NULL != gvt1->gd_csa)); assert(!(dba_bg == acc_meth2 || dba_mm == acc_meth2) || (NULL != gvt2->gd_csa)); /* if (!(both are bg/mm regions && dbs are same && same global) && * !(both are cm regions && on the same remote node && same region) * !(both are usr regions && in the same volume set)) * NO DESCENDANTS * endif */ if (!(((dba_bg == acc_meth1 || dba_mm == acc_meth2) && (dba_bg == acc_meth1 || dba_mm == acc_meth2)) && (gvt1->gd_csa == gvt2->gd_csa) && (gvt1->root == gvt2->root)) && !((dba_cm == acc_meth1) && (dba_cm == acc_meth2) && (reg1->dyn.addr->cm_blk == reg2->dyn.addr->cm_blk) && (reg1->cmx_regnum == reg2->cmx_regnum)) VMS_ONLY (&& !((dba_usr == acc_meth1) && (dba_usr == acc_meth2) && ((ddp_info *)(&FILE_INFO(reg1)->file_id))->volset == ((ddp_info *)(&FILE_INFO(reg2)->file_id))->volset))) { UNIX_ONLY(assert(dba_usr != acc_meth1 && dba_usr != acc_meth2);) return 1; } if (0 == memcmp(mglvnp->gblp[IND1]->s_gv_currkey->base, mglvnp->gblp[IND2]->s_gv_currkey->base, MIN(mglvnp->gblp[IND1]->s_gv_currkey->end, mglvnp->gblp[IND2]->s_gv_currkey->end))) { if (mglvnp->gblp[IND1]->s_gv_currkey->end == mglvnp->gblp[IND2]->s_gv_currkey->end) return 0; /* NOOP - merge self */ if (0 == (end1 = format_targ_key(buff1, MAX_ZWR_KEY_SZ, mglvnp->gblp[IND1]->s_gv_currkey, TRUE))) end1 = &buff1[MAX_ZWR_KEY_SZ - 1]; if (0 == (end2 = format_targ_key(buff2, MAX_ZWR_KEY_SZ, mglvnp->gblp[IND2]->s_gv_currkey, TRUE))) end2 = &buff2[MAX_ZWR_KEY_SZ - 1]; if (mglvnp->gblp[IND1]->s_gv_currkey->end > mglvnp->gblp[IND2]->s_gv_currkey->end) rts_error(VARLSTCNT(6) ERR_MERGEDESC, 4, end1 - buff1, buff1, end2 - buff2, buff2); else rts_error(VARLSTCNT(6) ERR_MERGEDESC, 4, end2 - buff2, buff2, end1 - buff1, buff1); } } else if (MARG1_IS_LCL(merge_args) && MARG2_IS_LCL(merge_args)) { if (mglvnp->lclp[IND1] == mglvnp->lclp[IND2]) return 0; /* NOOP - merge self */ if (lcl_arg1_is_desc_of_arg2(mglvnp->lclp[IND1], mglvnp->lclp[IND2])) { end1 = format_key_lv_val(mglvnp->lclp[IND1], buff1, SIZEOF(buff1)); end2 = format_key_lv_val(mglvnp->lclp[IND2], buff2, SIZEOF(buff2)); rts_error(VARLSTCNT(6) ERR_MERGEDESC, 4, end1 - buff1, buff1, end2 - buff2, buff2); } else if (lcl_arg1_is_desc_of_arg2(mglvnp->lclp[IND2], mglvnp->lclp[IND1])) { end1 = format_key_lv_val(mglvnp->lclp[IND1], buff1, SIZEOF(buff1)); end2 = format_key_lv_val(mglvnp->lclp[IND2], buff2, SIZEOF(buff2)); rts_error(VARLSTCNT(6) ERR_MERGEDESC, 4, end2 - buff2, buff2, end1 - buff1, buff1); } } return 1; } fis-gtm-V6.0-003/sr_port/merrors.msg0000644000032200000250000040273112201176160016236 0ustar librarygtc!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! ! Copyright 2001, 2013 Fidelity Information Services, Inc ! ! ! ! This source code contains the intellectual property ! ! of its copyright holder(s), and is made available ! ! under a license. If you do not know the terms of ! ! the license, please stop and do not read further. ! ! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .FACILITY GTM,246/PREFIX=ERR_ .TITLE MERRORS Error Messages for GTM ! ! The code numbers for the errors that have been ! standardized by the MUMPS Development Committee are ! listed below. ! Those error messages that have a standardized ! error code have a definition that ends in !/ansi=### ! If not specified, the value for "ansi" defaults to 0. ! (Note that the first entry in this file MUST have ! an !/ansi= specification; any subsequent ones are ! optional.) ! ! M1, Naked indicator undefined ! M2, Invalid combination with P _fncodatom_ ! M3, $RANDOM seed less than 1 ! M4, No true condition in $SELECT ! M5, _lineref_ less than zero ! M6, Undefined _lvn_ ! M7, Undefined _gvn_ ! M8, Undefined _svn_ ! M9, Divide by zero ! M10, Invalid pattern match range ! M11, No parameters passed ! M12, Invalid _lineref_ (negative offset) ! M13, Invalid _lineref_ (label not found) ! M14, _line_ level not 1 ! M15, Undefined index variable ! M16, Argumented QUIT not allowed ! M17, Argumented QUIT required ! M18, Fixed length READ not greater than zero ! M19, Cannot copy a tree or subtree into itself ! M20, _line_ must have _formallist_ ! M21, Formal parameter occurs multiple times (original text: Algorithm specification invalid) ! M22, SET or KILL to ^$GLOBAL when data in global ! M23, SET or KILL to ^$JOB for non-existent job number ! M24, Change to collation algorithm while subscripted local variables defined ! M25, Attempt to modify currently executing routine ! M26, Non-existent _environment_ ! M27, Attempt to rollback a transaction that is not restartable ! M28, Mathematical function, parameter out of range ! M29, SET or KILL on _ssvn_ not allowed by implementation ! M30, Reference to _glvn_ with different collating sequence within a collating algorithm ! M31, _controlmnemonic_ used for device without a _mnemonicspace_ selected ! M32, _controlmnemonic_ used in user-defined _mnemonicspace_ which has no associated line ! M33, SET or KILL to ^$ROUTINE when _routine_ exists ! M34, --- currently unassigned --- ! M35, Device does not support _mnemonicspace_ ! M36, Incompatible _mnemonicspace_s ! M37, READ from device identified by the empty string ! M38, Invalid _ssvn_ subscript ! M39, Name of variable expected (original text: Invalid $NAME argument) ! M40, Call-by-reference in JOB _actual_ ! M41, Invalid LOCK argument within a TRANSACTION ! M42, Invalid QUIT within a TRANSACTION ! M43, Invalid range ($X, $Y) ! M44, Invalid _command_ outside of a TRANSACTION ! M45, Invalid GOTO reference ! M46, Invalid attribute name ! M47, Invalid attribute value (original text: Invalid attribute name) ! M48, Nonexistent window, element or choice ! M49, Invalid attempt to set focus ! M50, Attempt to reference a non M-Term window in an OPEN command ! M51, Attempt to destroy M-Term window prior to CLOSE ! M52, Required attribute missing ! M53, Invalid argument for font function ! M54, Attempt to create non-modal child of a modal parent ! M55, Invalid nested TSTART command ! M56, Name length exceeds implementation's limit ! M57, More than one defining occurrence of label in routine ! M58, Too few formal parameters ! M59, Environment reference not permitted for this _ssvn_ ! M60, Undefined _ssvn_ ! M61, Attempt to OPEN file with conflicting ACCESS parameters ! M62, Illegal value for ACCESS parameter while attempting to OPEN file ! M63, Illegal value for DISPOSITION parameter while attempting to CLOSE file ! M64, Illegal value for RENAME parameter while attempting to CLOSE file ! M65, Illegal value for VOLUME label ! M66, Illegal value for DENSITY parameter ! M67, Illegal value for ACCESS parameter ! M68, Illegal value for MOUNT parameter ! M69, Attempted tape I/O while no tape mounted ! M70, Illegal value for BLOCKSIZE parameter ! M71, Attempt to read data block larger than buffer size ! M72, Illegal value for recordsize parameter ! M73, Invalid usage of _devicekeyword_ NEWFILE ! M74, Illegal value for TRANSLATION parameter ! M75, String length exceeds implementation's limit ! M76, TCP socket state incorrect for CONNECT or LISTEN ! M77, TCP _deviceattribute_ missing ! M78, TCP _devicekeyword_ missing ! M79, TCP socket allocated to another device ! M80, Network error not otherwise specified ! M81, Unable to establish network connection ! M82, Network connection suspended: wait to resume ! M83, Network connection lost ! M84, Network protocol error: invalid client message ! M85, Network protocol error: invalid server message ! M86, Cannot relinquish device with I/O pending ! M87, Network buffer overflow ! M88, Non-existent _routine_ ! M89, Specified pattern is not a _subpattern_ ! M90, Invalid _namevalue_ ! M91, Routine source is not available ! M92, Mathematical overflow ! M93, Mathematical underflow ! M94, Attempt to compute zero to the zero-eth power ! M95, Exponentiation returns complex number with non-zero imaginary part ! M96, Attempt to assign value to already valued write-once _ssvn_ ! M97, Routine associated with user-defined _ssvn_ does not exist ! M98, Resource unavailable ! M99, Invalid operation for context ! M100, Output time-out expired ! M101, Attempt to assign incorrect value to $ECODE ! M102, Simultaneous synchronous and asynchronous event class ! M103, Invalid event identifier ! M104, IPC event identifier is not a valid job-number ! M105, Object not currently accessible ! M106, Object does not support requested method or property ! M107, Object has no default value ! M108, Value if not of data type OREF ! M109, Undefined _devicekeyword_ ! M110, Event identifier not available ! M111, Invalid number of days for date ! M112, Invalid number of seconds for time ! ! List of messages which are not reported by GT.M standard error routines(rts_error etc.) but ! by PRINTFs. NOTE: if the value of any these messages changes in future, all its non-standard ! usages should be reflected with the new value. ! ERR_GTMDISTUNDEF 150377714 (reported in gtm.c if $gtm_dist is not defined) ! ERR_DISTPATHMAX 150377682 (reported in gtm.c if $gtm_dist buffer is insufficient) ! ERR_DLLNOOPEN 150379250 (reported in gtm.c if libgtmshr cannot be opened) ! ERR_DLLNORTN 150379258 (reported in gtm.c if gtm_main is not found in libgtmshr) ! ERR_OPCOMMISSED 150381275 (sent via $SNDOPR in util_output.c if prior errors) ! ! List of known undocumented messages follows (along with a comment) ! ERR_ACK internal error (not displayed to the users) ! ERR_ASC2EBCDICCONV not yet documented since zOS is not officially supported ! ERR_DEFEREVENT referenced only if #define DEBUG is TRUE (i.e. for debug builds only) ! ERR_ENQ internal error (not displayed to the users) ! ERR_FREEZEID referenced only if #define DEBUG_FREEZE is TRUE. ! ERR_INVDBGLVL referenced only if "gtmdbglvl" is set to non-zero value (which is a debugging feature) ! ERR_JNLREQUIRED message referenced only in GT.CX code (not supported currently) ! ERR_JNLWRTNOWWRTR internal error (not displayed to the users) ! ERR_JOBINTRRETRHOW internal error (not displayed to users - drives rethrow of jobinterrupt) ! ERR_JOBINTRRQST internal error (not displayed to users - drives jobinterrupt) ! ERR_LKSECINIT message referenced only in GT.CX code (not supported currently) ! ERR_MUDESTROYFAIL referenced only if #define IPCRM_FOR_SANCHEZ_ONLY is TRUE. ! ERR_MUDESTROYSUC referenced only if #define IPCRM_FOR_SANCHEZ_ONLY is TRUE. ! ERR_RBWRNNOTCHG not seen by user since return status of mupip_set_file (that triggers this) is not displayed. ! ERR_REPEATERROR internal error (not displayed to the users) ! ERR_SYSTEMVALUE code is not executed (set $system won't reach op_svput at all to signal the error) ! ERR_TPRETRY internal error (not displayed to the users) ! ERR_WILLEXPIRE error triggered by the license management code which has been since disabled. ! ERR_YDIRTSZ used by a percent utility, which is not documented intentionally ! ERR_ZDEFACTIVE functionality not documented (GT.CM related weirdness) ! ERR_ZDEFOFLOW functionality not documented (GT.CM related weirdness) ! ! ! ----- Buffer to introduce new undocumented error messages without affecting UNUSEDMSGnnn match with corresponding line numbers. ! ! ! ! ! ! In addition all messages of the LMU and GTLP message facility are not documented as Licensing is out of GT.M since V4.2. ! ACK <>/success/fao=0!/ansi=0 BREAKZST /info/fao=0!/ansi=0 BADACCMTHD /info/fao=0!/ansi=0 BADJPIPARAM /error/fao=2!/ansi=0 BADSYIPARAM /error/fao=2!/ansi=0 BITMAPSBAD /error/fao=0!/ansi=0 BREAK /info/fao=0!/ansi=0 BREAKDEA /info/fao=0!/ansi=0 BREAKZBA /info/fao=0!/ansi=0 STATCNT /info/fao=5!/ansi=0 BTFAIL /error/fao=1!/ansi=0 MUPRECFLLCK /error/fao=2!/ansi=0 CMD /error/fao=0!/ansi=0 COLON /error/fao=0!/ansi=0 COMMA /error/fao=0!/ansi=0 COMMAORRPAREXP /error/fao=0!/ansi=0 COMMENT /info/fao=0!/ansi=0 CTRAP /error/fao=1!/ansi=0 CTRLC /info/fao=0!/ansi=0 CTRLY /info/fao=0!/ansi=0 DBCCERR /error/fao=2!/ansi=0 DUPTOKEN /error/fao=5!/ansi=0 DBJNLNOTMATCH /error/fao=6!/ansi=0 DBFILERR /error/fao=2!/ansi=0 DBNOTGDS /error/fao=2!/ansi=0 DBOPNERR /error/fao=2!/ansi=0 DBRDERR /error/fao=2!/ansi=0 CCEDUMPNOW <>/fatal/fao=0!/ansi=0 DEVPARINAP /error/fao=0!/ansi=0 RECORDSTAT /info/fao=6!/ansi=0 NOTGBL /error/fao=2!/ansi=0 DEVPARPROT /error/fao=0!/ansi=0 PREMATEOF /error/fao=0!/ansi=0 GVINVALID /error/fao=2!/ansi=0 DEVPARTOOBIG /error/fao=0!/ansi=0 DEVPARUNK /error/fao=0!/ansi=0 DEVPARVALREQ /error/fao=0!/ansi=0 DEVPARMNEG /error/fao=0!/ansi=0 DSEBLKRDFAIL /error/fao=0!/ansi=0 DSEFAIL /error/fao=2!/ansi=0 NOTALLREPLON /warning/fao=0!/ansi=0 BADLKIPARAM /error/fao=2!/ansi=0 JNLREADBOF /error/fao=2!/ansi=0 DVIKEYBAD <$ZGETDVI("!AD","!AD") contains an illegal keyword>/error/fao=4!/ansi=0 ENQ <>/success/fao=0!/ansi=0 EQUAL /error/fao=0!/ansi=0 ERRORSUMMARY /error/fao=0!/ansi=0 ERRWEXC /error/fao=0!/ansi=0 ERRWIOEXC /error/fao=0!/ansi=0 ERRWZBRK /error/fao=0!/ansi=0 ERRWZTRAP /error/fao=0!/ansi=0 NUMUNXEOR /error/fao=2!/ansi=0 EXPR /error/fao=0!/ansi=0 STRUNXEOR /error/fao=2!/ansi=0 JNLEXTEND /error/fao=2!/ansi=0 FCHARMAXARGS /error/fao=0!/ansi=0 FCNSVNEXPECTED /error/fao=0!/ansi=0 FNARGINC /error/fao=2!/ansi=2 JNLACCESS /error/fao=2!/ansi=0 TRANSNOSTART /error/fao=0!/ansi=44 FNUMARG <$FNUMBER format specifier "!AD" contains an illegal character: "!AD">/error/fao=4!/ansi=0 FOROFLOW /error/fao=1!/ansi=0 YDIRTSZ /error/fao=0!/ansi=0 JNLSUCCESS /success/fao=2!/ansi=0 GBLNAME /error/fao=0!/ansi=29 GBLOFLOW /error/fao=0!/ansi=0 CORRUPT /error/fao=2!/ansi=0 GTMCHECK /fatal/fao=0!/ansi=0 GVDATAFAIL /error/fao=2!/ansi=0 EORNOTFND /error/fao=2!/ansi=0 GVGETFAIL /error/fao=2!/ansi=0 GVIS /info/fao=2!/ansi=0 GVKILLFAIL /error/fao=2!/ansi=0 GVNAKED /error/fao=0!/ansi=1 GVNEXTARG /error/fao=0!/ansi=0 GVORDERFAIL /error/fao=2!/ansi=0 GVPUTFAIL /error/fao=2!/ansi=0 PATTABSYNTAX /error/fao=3!/ansi=0 GVSUBOFLOW /error/fao=0!/ansi=0 GVUNDEF /error/fao=2!/ansi=7 TRANSNEST /error/fao=0!/ansi=0 INDEXTRACHARS /error/fao=0!/ansi=0 UNUSEDMSG260 /error/fao=0!/ansi=0 INDRMAXLEN /error/fao=1!/ansi=0 INSFFBCNT /error/fao=0!/ansi=0 INTEGERRS /error/fao=0!/ansi=0 INVCMD /warning/fao=0!/ansi=0 INVFCN /error/fao=0!/ansi=0 INVOBJ /error/fao=0!/ansi=0 INVSVN /error/fao=0!/ansi=8 IOEOF /error/fao=0!/ansi=0 IONOTOPEN /error/fao=0!/ansi=0 MUPIPINFO /info/fao=2!/ansi=0 IVTIME /error/fao=2!/ansi=0 JOBFAIL /error/fao=0!/ansi=0 JOBLABOFF /error/fao=0!/ansi=0 JUSTFRACT /error/fao=0!/ansi=0 KEY2BIG /error/fao=4!/ansi=0 LABELEXPECTED /error/fao=0!/ansi=0 LVORDERARG /error/fao=0!/ansi=0 MAXFORARGS /error/fao=0!/ansi=0 TRANSMINUS /error/fao=0!/ansi=0 MAXNRSUBSCRIPTS /error/fao=0!/ansi=0 MAXSTRLEN /error/fao=0!/ansi=75 JNLDBERR /error/fao=4!/ansi=0 JNLFILOPN /error/fao=4!/ansi=0 MBXRDONLY /error/fao=0!/ansi=0 JNLINVALID /error/fao=4!/ansi=0 MBXWRTONLY /error/fao=0!/ansi=0 MEMORY /fatal/fao=2!/ansi=0 MTBLKTOOBIG /error/fao=0!/ansi=70 MTBLKTOOSM /error/fao=1!/ansi=70 MTFIXRECSZ /error/fao=2!/ansi=70 MTIS /info/fao=2!/ansi=0 MTRDBADBLK /error/fao=2!/ansi=0 MTRDONLY /error/fao=0!/ansi=62 MTRDTHENWRT /error/fao=0!/ansi=0 MTRECGTRBLK /error/fao=0!/ansi=71 MTRECTOOBIG /error/fao=0!/ansi=72 MTRECTOOSM /error/fao=0!/ansi=72 JNLTMQUAL3 /error/fao=0!/ansi=0 JNLWRTDEFER /info/fao=0!/ansi=0 SELECTFALSE /error/fao=0!/ansi=4 SPOREOL /error/fao=0!/ansi=0 SRCLIN /info/fao=4!/ansi=0 SRCLOC /info/fao=4!/ansi=0 SRCLOCUNKNOWN /info/fao=0!/ansi=0 STACKCRIT /error/fao=0!/ansi=0 STACKOFLOW /fatal/fao=0!/ansi=0 STACKUNDERFLO /error/fao=0!/ansi=0 STRINGOFLOW /error/fao=0!/ansi=0 SVNOSET /error/fao=0!/ansi=0 VIEWFN /error/fao=0!/ansi=0 TERMASTQUOTA /error/fao=0!/ansi=0 TEXTARG /error/fao=0!/ansi=5 TMPSTOREMAX /error/fao=0!/ansi=0 VIEWCMD /error/fao=0!/ansi=0 JNI /error/fao=2!/ansi=0 TXTSRCFMT <$TEXT encountered an invalid source program file format>/error/fao=0!/ansi=0 UIDMSG /error/fao=0!/ansi=0 UIDSND /error/fao=0!/ansi=0 UNDEF /error/fao=2!/ansi=6 UNIMPLOP /error/fao=0!/ansi=0 VAREXPECTED /error/fao=0!/ansi=39 VARRECBLKSZ /error/fao=0!/ansi=0 MAXARGCNT /error/fao=1!/ansi=0 GTMSECSHRSEMGET /error/fao=1!/ansi=0 VIEWARGCNT /error/fao=2!/ansi=0 GTMSECSHRDMNSTARTED /info/fao=5!/ansi=0 ZATTACHERR /error/fao=2!/ansi=0 ZDATEFMT <$ZDATE format string contains invalid character>/error/fao=0!/ansi=0 ZEDFILSPEC /error/fao=2!/ansi=0 ZFILENMTOOLONG /error/fao=2!/ansi=75 ZFILKEYBAD /error/fao=2!/ansi=0 ZFILNMBAD /error/fao=2!/ansi=0 ZGOTOLTZERO /error/fao=0!/ansi=0 ZGOTOTOOBIG /error/fao=0!/ansi=0 ZLINKFILE /error/fao=2!/ansi=0 ZPARSETYPE /error/fao=2!/ansi=0 ZPARSFLDBAD /error/fao=2!/ansi=0 ZPIDBADARG /error/fao=0!/ansi=0 ZPRIVARGBAD /error/fao=2!/ansi=0 ZPRIVSYNTAXERR /error/fao=0!/ansi=0 ZPRTLABNOTFND
/info/fao=2!/ansi=0 MUSECNOTDEL
/info/fao=2!/ansi=0 RPARENREQD /error/fao=2!/ansi=0 ZGBLDIRACC /error/fao=6!/ansi=26 GVNAKEDEXTNM /error/fao=0!/ansi=0 EXTGBLDEL /error/fao=0!/ansi=0 DSEWCINITCON /info/fao=0!/ansi=0 LASTFILCMPLD /info/fao=2!/ansi=0 NOEXCNOZTRAP /info/fao=0!/ansi=0 UNSDCLASS /error/fao=0!/ansi=0 UNSDDTYPE /error/fao=0!/ansi=0 ZCUNKTYPE /error/fao=0!/ansi=0 ZCUNKMECH /error/fao=0!/ansi=0 ZCUNKQUAL /error/fao=0!/ansi=0 JNLDBTNNOMATCH /error/fao=9!/ansi=0 ZCALLTABLE /error/fao=0!/ansi=0 ZCARGMSMTCH /error/fao=2!/ansi=58 ZCCONMSMTCH /error/fao=0!/ansi=58 ZCOPT0 /error/fao=0!/ansi=0 ZCSTATUS /error/fao=0!/ansi=0 ZCUSRRTN /error/fao=0!/ansi=0 ZCPOSOVR /error/fao=1!/ansi=0 ZCINPUTREQ /error/fao=0!/ansi=0 JNLTNOUTOFSEQ /error/fao=6!/ansi=0 ACTRANGE /error/fao=1!/ansi=0 ZCCONVERT /error/fao=0!/ansi=0 ZCRTENOTF /error/fao=2!/ansi=0 GVRUNDOWN /error/fao=0!/ansi=0 LKRUNDOWN /error/fao=0!/ansi=0 IORUNDOWN /error/fao=0!/ansi=0 FILENOTFND /error/fao=2!/ansi=0 MUFILRNDWNFL /error/fao=2!/ansi=0 JNLTMQUAL1 /error/fao=0!/ansi=0 FALLINTOFLST /error/fao=0!/ansi=11 NOTEXTRINSIC /error/fao=0!/ansi=16 GTMSECSHRREMSEMFAIL /error/fao=1!/ansi=0 FMLLSTMISSING /error/fao=2!/ansi=20 ACTLSTTOOLONG /error/fao=2!/ansi=58 ACTOFFSET /error/fao=0!/ansi=0 MAXACTARG /error/fao=0!/ansi=0 GTMSECSHRREMSEM <[client pid !UL] Semaphore (!UL) removed>/error/fao=2!/ansi=0 JNLTMQUAL2